【问题标题】:2D Matrix allocation on heap in c++c++中堆上的二维矩阵分配
【发布时间】:2011-12-02 20:07:19
【问题描述】:

我正在寻找一种在内存中连续元素在堆上分配 2D (m x n) 矩阵的方法。目前我知道有两种方法可以做到这一点:

第一种方法

int* M = new int[m * n];
  • 亲:M 的大小可以动态确定。
  • Con:M 的索引有点麻烦。 (M[i * m + j])

第二种方法

typedef int dim[2];
dim* M = new dim[n];
  • 专业人士:M 的索引正是我想要的。
  • Con:无法动态设置第一个维度 (m) 的大小。

问题

有没有办法在堆上动态分配一个二维矩阵,我可以用[i][j] 索引元素并且内存分配是连续的?

我知道为此使用一个类会很有意义,但我正在专门寻找一种如上所述的方法。

【问题讨论】:

  • 当然,只需编写一个自定义IntArray2D 类,并使用适当的operator[] 返回一个重载operator[] 本身的代理。
  • 您好 Woltan,我将始终使用您提到的第一种方法。使用索引可能看起来更尴尬。但这是你很快就会使用的东西。避免在第二种方法中使用指针的痛苦并保持简单。

标签: c++ matrix memory-management heap-memory


【解决方案1】:

你可以试试这个

int** M = new int*[m];
int *M_data = new int[m*n];

for(int i=0; i< m; ++i) 
{
    M[i] = M_data + i * n;
}

【讨论】:

  • 我最喜欢这个答案,因为它很简单。问题的所有条件都满足。 (连续的内存分配和索引)
【解决方案2】:

这是我在评论中提到的IntArray2D 类的最小版本:

class IntArray2D
{
    std::vector<int> data_;
    int height_;
    int width_;

public:

    IntArray2D(int height, int width)
    : data_(height * width), height_(height), width_(width) 
    {
    }

    int* operator[](int index)
    {
        return &data_[index * width_];
    }

    const int* operator[](int index) const
    {
        return &data_[index * width_];
    }
};

示例用法:

IntArray2D test(100, 10);
test[99][9] = 42;
int i = test[0][0];

您可能想要添加边界检查,并且要在两个维度上执行此操作,您需要返回适当的代理对象而不是指针。练习留给读者;-)

【讨论】:

    【解决方案3】:

    注意:请参阅下面的编辑了解如何做到这一点。我将保持原帖不变。

    原帖

    要使两种尺寸都动态且元素连续,除了第一种方法之外别无他法。 (注意:查看编辑,有办法做到这一点,但使用 g++)

    这样想:当你告诉编译器计算 array[i][j] 时,它会自动将其转换为:

    *(array+i*m+j)
    

    如果数组是静态的并且m(列数)是已知的。或者如果数组是二维的(type ** 类型):

    *(*(array+i)+j)
    

    第二种情况是您通常如何处理二维数组,但数据不是连续的。这给你留下了第一个选择。现在在第一个选项中,在编译时,编译器必须知道m。如果你想在运行时设置m,编译器就无法计算i*m+j

    现在有办法解决这个问题。一种是使用您提到的类,它包含array = new type[n*m]; 并正确重载[] 运算符。另一种需要更多内存的方法(因此我个人不推荐)是采用第二个type ** 类型的数组,而不是将每个元素设置为new type[m],而是将其设置为开头一维数组中的行数。

    不过,底线是,您必须拥有new type[n*m]

    编辑:使用 g++ 的方法

    这来自下面的 cmets:

    type *array_helper = new type[n*m];
    type (*array)[m] = (type (*)[m])array_helper;
    

    那么就可以使用数组了,元素是连续的。

    我也试过了,效果很好

    type array[n][m];
    

    我打印了地址,专门检查了array[i][m-1]array[i+1][0],地址是连续的。

    【讨论】:

    • 在现代 C++ 中,您很少必须在您自己的代码中的任何位置使用new
    • 或者您可以将new[m*n] 的结果转换为(int(*)[m]),两全其美。你低估了编译器。
    • @Dave,这和写OP的第二种方法完全一样。问题是m 是动态设置的(它不是常量),因此(int *[m]) 是不可能的!
    • 这完全是错误的。我写了一个示例程序pastebin.com/SMFRUM0c,它完全符合 OP 的要求。它在 g++ 上编译时没有警告。
    • @Dave,我刚刚尝试使用我的 g++,但出现错误。你确定你真的让m动态吗?试试这个代码:int m, n; cin &gt;&gt; n &gt;&gt; m; int *arr = new int[n*m]; for (int i = 0; i &lt; n; ++i) for (int j = 0; j &lt; m; ++j) arr[i*m+j] = i*m+j; int **arr2 = (int (*)[m])arr; for (int i = 0; i &lt; n; ++i) for (int j = 0; j &lt; m; ++j) cout &lt;&lt; arr2[i][j] &lt;&lt; endl; 对我来说,这不会编译并给出这个错误:cannot convert 'int (*)[(((unsigned int)(((int)m) + -0x000000001)) + 1)]' to 'int**' in initialization
    【解决方案4】:

    你想要一个指向(int-array)的指针:

     cin >> w >> h;
     int (*data)[w] = (int (*)[w])new int[w*h];
     for(int y=0;y<h;y++)
     for(int x=0;x<w;x++)
         data[y][x] = (w*y)+x;
    

    【讨论】:

      【解决方案5】:

      根据 crazyjul 的回答,您只需分配一次内存即可。

      int **arr = new int*[col*(row+1)];
      for(int a=0; c<col; ++a){
          arr[a] = (int*)&arr[(a+1)*row];
      }
      

      【讨论】:

        【解决方案6】:

        类 C 伪代码:

        int** M = new int*[m];
        for(int i in 0..m-1) {
            M[i] = new int[n];
        }
        

        【讨论】:

        • @crazyjul,哎呀,对。在我看来,必须在内存一致性和索引方法之间做出选择
        【解决方案7】:

        使用 boost arraymatrix 或 STL vector

        您的矩阵还有一件事:Why shouldn't my Matrix class's interface look like an array-of-array?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-10-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-08-14
          • 2021-12-26
          • 1970-01-01
          • 2021-05-07
          相关资源
          最近更新 更多