【问题标题】:How to create a two dimensional array of given size in C++如何在 C++ 中创建给定大小的二维数组
【发布时间】:2015-03-28 07:31:57
【问题描述】:

我需要创建一个给定大小的方阵。我知道如何创建给定大小的动态一维数组。像下面的几行这样的两个维度数组不是同样适用吗?

cin>>size;
int* a[][]=new int[size][size]

【问题讨论】:

  • 看看std::vector

标签: c++ arrays


【解决方案1】:
int* a[][]=new int[size][size]

不,这不起作用。

main.cpp:4: error: only the first dimension of an allocated array may have dynamic size
    new int[size][size];
                  ^~~~

如果行的大小是固定的,那么你可以这样做:

// allocate an array with `size` rows and 10 columns
int (*array)[10] = new int[size][10];

在 C++ 中,您不能拥有两个维度都是动态的二维原始数组。这是因为原始数组索引是根据指针工作的;例如,为了访问第二行,指向第一行的指针需要增加行的大小。但是当行的大小是动态的时,数组不知道该大小,因此 C++ 不知道如何计算指针增量。

如果您想要一个具有多个动态维度的数组,那么您需要构造数组分配,以便 C++ 的默认数组索引逻辑可以处理它(例如 this 重复问题的最佳答案),或者您需要自己实现计算适当指针增量的逻辑。

对于每行具有相同大小的数组,我建议不要使用多个分配,例如那些答案所建议的,或者使用向量的向量。使用向量的向量解决了手动分配的困难和危险,但它仍然使用比必要更多的内存,并且不允许更快的内存访问模式。

另一种方法,扁平化多维数组,可以使代码像任何其他方法一样易于读写,不使用额外的内存,并且性能更好。

扁平化数组意味着您只使用与所需二维数组具有相同元素数量的一维数组,并且您执行在多维索引和对应的一维索引之间转换的算术运算。 new 看起来像:

int *arr = new int[row_count * column_count];

二维数组中的行i,列j对应arr[column_count*i + j]arr[n] 对应于行n/column_count 和列n% column_count 的元素。比如一个10列的数组,第0行第0列对应arr[0];第 0 行,第 1 列对应于arr[1];第 1 行第 0 列对应于arr[10];第 1 行第 1 列对应于arr[11]


您应该避免使用原始newdelete 进行手动内存管理,例如int *arr = new int[size];。相反,资源管理应该包含在 RAII 类中。用于管理动态分配内存的 RAII 类的一个示例是 std::vector

std::vector<int> arr(row_count * column_count);
arr[column_count*i + j]

您可以进一步将计算索引的逻辑封装在另一个类中:

#include <vector>

class Array2d {
  std::vector<int> arr;
  int columns;
public:
  Array2d(int rows, int columns)
  : arr(rows * columns)
  , columns(columns)
  {}

  struct Array2dindex { int row; int column; };

  int &operator[] (Array2dindex i) {
    return arr[columns*i.row + i.column];
  }
};

#include <iostream>

int main() {
  int size;
  std::cin >> size;

  Array2d arr(size, size);

  for (int i = 0; i < size; ++i) {
    for (int j = 0; j < size; ++j) {
      arr[{i, j}] = 100;
    }
  }

  for (int i = 0; i < size; ++i) {
    for (int j = 0; j < size; ++j) {
      std::cout << arr[{i, j}] << ' ';
    }
    std::cout << '\n';
  }
}

【讨论】:

    【解决方案2】:

    如果你使用 C++11,你也可以使用 std::array。

    const int iRows = 3, iCols = 3; // number of rows and columns
    std::array<std::array<int, iCols>, iRows> matrix;
    
    // fill with 1,2,3  4,5,6  7,8,9
    for(int i=0;i<iRows;++i)
        for(int j=0;j<iCols;++j)
            matrix[i][j] = i * iCols + j + 1;
    

    这个类还允许使用函数进行边界检查

    std::array::at
    

    which(就像 operator[])如果数组对象是 const 限定的,则返回一个 const 引用,否则返回一个引用。请注意

    std::array
    

    不是可变大小的数组类型,如

    std::vector
    

    【讨论】:

    • 这个需要预先知道尺寸。如果您在用户输入之前不知道尺寸,则它不起作用。示例中的cin &gt;&gt; size 杀死了它。
    【解决方案3】:

    你可以使用std::vector:

    std::vector<std::vector<int*>> a(size, std::vector<int*>(size));
    

    这将创建一个动态分配的二维数组int*,其宽度和高度等于size

    或与new相同:

    int*** a = new int**[size];
    for (size_t i = 0; i < size; ++i)
        a[i] = new int*[size];
    ...
    for (size_t i = 0; i < size; ++i)
        delete a[i];
    delete a;
    

    请注意,C++ 中没有 new[][] 运算符,您只需调用两次 new[]

    但是,如果您想使用newdelete 而不是std::vector,则应该使用智能指针而不是原始指针,例如:

    std::unique_ptr<std::unique_ptr<int*>[]> a(new std::unique_ptr<int*>[size]);
    for (size_t i = 0; i < size; ++i)
        a[i].reset(new int*[size]);
    ...
    // No need to call `delete`, std::unique_ptr does it automatically.
    

    【讨论】:

    • 在使用带有“new”的方法时出现错误“int** a shadows a parameter”。知道为什么会这样吗?
    • 也许你在某个地方还有另一个变量叫做a
    • 是的,你说得对,我之前已经声明过。那么,在这种情况下,我需要写 a=new int*[size] 还是 **a=new int*[size]?
    • 两种情况都报错,不知道是什么原因
    • **a 只是取消引用 a 两次,这不是你想要的。如果你想做a = new int*[size],那么a 必须声明为int**。顺便检查一下我对智能指针解决方案的编辑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多