【问题标题】:C++ Multi-dimensional Arrays on the Heap堆上的 C++ 多维数组
【发布时间】:2010-09-25 08:26:57
【问题描述】:

如何动态分配多维数组?

【问题讨论】:

  • 啊啊,这是个好问题。

标签: c++ arrays memory heap-memory allocation


【解决方案1】:

如果你已经知道嵌套维度的大小,你也可以使用 new 来分配一个多维数组:

typedef int dimensions[3][4];

dimensions * dim = new dimensions[10];
dim[/* from 0 to 9 */][/* from 0 to 2 */][/* from 0 to 3 */] = 42;
delete [] dim;

可以传递运行时确定的值,而不是10。因为它不是类型运算符 new 返回的一部分,所以这是允许的。例如,如果您知道列数,但又想保持行数可变,这很好。 typedef 让代码更容易阅读。

【讨论】:

【解决方案2】:

为了完整起见,当您提前知道数组边界时,这是在 C++ 中执行此操作的更好方法。使用以下类的好处是您不必关心在数据上调用 delete[]。这意味着这个类将是异常安全的,所有其他关于 RAII 的好东西。

template<typename T, int width, int height>
class MultiArray
{
    private:
        typedef T cols[height];
        cols * data;
    public:
        T& operator() (int x, int y) { return data[x][y]; }
        MultiArray() { data = new cols[width]; }
        ~MultiArray() { delete [] data; }
};

用法:

MultiArray<int, 10, 10> myArray;
myArray(2, 3) = 4;
cout << myArray(2, 3);

编辑: 并且,当我这样做时,如果您在运行时之前知道数组边界,则可以使用以下设置:

template<typename T>
class Array2D
{
    private:
        const int width;
        T * data;
    public:
        T& operator() (int x, int y) { return data[y*width + x]; }
        Array2D(const int w, const int h) : width(w) { data = new T[w*h]; }
        ~Array2D() { delete [] data; }
};

用法:

Array2D myArray(10, 10);
myArray(3, 4) = 42;
cout << myArray(3, 4);

【讨论】:

    【解决方案3】:

    使用 Boost.Multiarray 怎么样?我相信它很好地满足了您的需求! http://www.boost.org/doc/libs/1_37_0/libs/multi_array/doc/user.html#sec_introduction

    这是文档页面的摘录:

     #include < boost/multi_array.hpp >
    
     #include < cassert >
    
    int main () 
    
    {
    
      // Create a 3D array that is 3 x 4 x 2
    
      typedef boost::multi_array< double, 3 > array_type;
    
      typedef array_type::index index;
    
      array_type A(boost::extents[3][4][2]);
    
    
      // Assign values to the elements
    
      int values = 0;
    
      for(index i = 0; i != 3; ++i) 
    
        for(index j = 0; j != 4; ++j)
    
          for(index k = 0; k != 2; ++k)
    
            A[i][j][k] = values++;
    
      // Verify values
    
      int verify = 0;
    
      for(index i = 0; i != 3; ++i) 
    
        for(index j = 0; j != 4; ++j)
    
          for(index k = 0; k != 2; ++k)
    
            assert(A[i][j][k] == verify++);
    
      return 0;
    
    }
    

    【讨论】:

      【解决方案4】:

      看到这个: C++ FAQ by Marshall Cline

      请参阅“如何使用 new 分配多维数组?”和“但是之前的常见问题解答的代码非常棘手且容易出错!难道没有更简单的方法吗?”部分。

      【讨论】:

      • 我已经有一段时间没有考虑过 C++ 常见问题解答了。连同 Strostrup 的书,它曾经是我最喜欢的编程读物之一。
      • FAQ [16.16] 似乎不正确。它使用 new[] 为行分配内存。然后将每个指针设置为 NULL 并重新分配它。它永远不会释放它设置为 NULL 的内存,从而泄漏该内存。请检查。
      【解决方案5】:

      std::vector&lt;std::vector&lt;int&gt; &gt;应该被提及,因为它通常是最简单的方法。但是,请注意它是非矩形的。并非每个std::vector&lt;int&gt; 都需要具有相同的长度。

      【讨论】:

      • 对于一维数组,它更简单,但二维使事情变得复杂。您必须将每个元素显式初始化为您想要的大小。
      • 是的,但这并不难:std::vector<:vector> > myarray(height, std::vector(width));创建一个全为 0 的矩形,由 [row][column] 索引。行在内存中是连续的,列不是。
      • @MarkRansom,实际上,对我来说,这是这种方法的好处。 boost::multi_array 是一个很好的容器,当维度的长度一致时,vector&lt;vector&lt;...&gt;&gt; 是动态非恒定长度数组的方法......诚然,这几乎不需要......但是当它是时,这是要走的路!
      【解决方案6】:

      我很惊讶还没有人提到boost::multi_array。就在上周,我在一个程序中需要一个 2D 数组,发现它比我之前提出的自制解决方案(所有这些都在其他 cmets 中提到)更容易,编码也更快.

      【讨论】:

        【解决方案7】:

        这是我的实现;我声明了一个 ints 的连续块,而不是在我的 for 循环中创建新块,所以我不会在所有地方造成页面错误。感谢 eJames 指出为什么这段代码最初被破坏。

        int width = 10, height = 10, totalSize = width*height;
        int **myArray = new int*[width];
        int *data = new int[totalSize];
        
        for ( int i = 0; i < height; ++i )
        {
            myArray[i] = data + (i*width);
        }
        
        // do some things here
        
        delete[] data;
        delete[] myArray;
        

        【讨论】:

        • 此代码将无法正常工作,如图所示。具体来说,循环中对 myArray[i] 的写入将无处不在。在此处查看我修改后的循环:stackoverflow.com/questions/340943/…
        【解决方案8】:

        您的循环不会正确地将指针值写入myArray。我建议改为:

        int width = 10;
        int height = 10;
        int ** myArray = new int*[width];
        int * data = new int[width*height];
        int * index = data;
        for (int i = 0; i < width; i++)
        {
            myArray[i] = index;
            index += height;
        }
        
        // ...
        
        delete[] data;
        delete[] myArray;

        【讨论】:

        • 你是对的;我有这个工作,并在没有检查它是否工作的情况下对其进行了重构。也许我应该停止破坏构建......
        【解决方案9】:

        作为另一种选择,STLSoft 包括 fixed_array_2d 类(以及 3D 和 4D 版本)。与这里给出的自制解决方案相比,它具有类似的实现,但功能集更完整(完全支持迭代器等)。与 boost::multi_array 相比,它的重量更轻,更容易在不完全兼容的 C++ 编译器上使用,但(故意)缺少 multi_array 的一些特性。

        【讨论】:

          【解决方案10】:

          如果您只是在正确数量的元素上留出空间,则可以将一维索引为 2、3 或 N 维。例如,如果我有 10 行和 10 列,我知道如果我在第 3 行,我将必须遍历至少 30 个元素才能到达它。

          不知何故,我更喜欢这种表示法用于简单的二维数组,因为我不需要担心指针的嵌套级别。缺点是更混乱的索引符号。这是一个具有 n 行和 m 列的二维数组的示例:

          int *matrix = new int[n*m];
          
          //set element (3,7) to 10
          matrix[3*m+7] = 10;
          
          //print the matrix
          for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
              cout << matrix[i*m+j] << ' ';
            }
            cout << '\n';
          }
          

          【讨论】:

            【解决方案11】:

            这是对另一个线程上的帖子的复制。它完全符合您的要求,无需提前知道数组尺寸,也无需使用 boost 或 STL。

            这是一个例程,它在连续的内存空间中分配维度为 N1 x N2 x N3 的 3D 数组,同时允许您使用 a[i][j][k] 语法进行运算符访问。该数组是动态的但连续的,因此它比 vector 方法和 new[] 调用循环具有巨大优势。

            template <class T> T ***Create3D(int N1, int N2, int N3)
            {
                T *** array = new T ** [N1];
            
                array[0] = new T * [N1*N2];
            
                array[0][0] = new T [N1*N2*N3];
            
                int i,j,k;
            
                for( i = 0; i < N1; i++) {
            
                    if (i < N1 -1 ) {
            
                        array[0][(i+1)*N2] = &(array[0][0][(i+1)*N3*N2]);
            
                        array[i+1] = &(array[0][(i+1)*N2]);
            
                    }
            
                    for( j = 0; j < N2; j++) {     
                        if (j > 0) array[i][j] = array[i][j-1] + N3;
                    }
            
                }
            
                cout << endl;
                return array;
            };
            
            template <class T> void Delete3D(T ***array) {
                delete[] array[0][0]; 
                delete[] array[0];
                delete[] array;
            };
            

            然后在您的实施例程中...

            int *** array3d;
            int N1=4, N2=3, N3=2;
            
            int elementNumber = 0;
            
            array3d = Create3D<int>(N1,N2,N3);
            
            //equivalently, a 'flat' array could be obtained with
            //int * array = array3d[0][0];
            
            cout << "{" << endl;
            for (i=0; i<N1; i++) {
                cout << "{";
                for (j=0; j<N2; j++) {
                    cout << "{";
                    for (k=0; k<N3; k++) {
                        array3d[i][j][k] = elementNumber++;
                        cout << setw(4) << array3d[i][j][k] << " ";
            
                        //or if you're using the flat array:
                        //array[i*N2*N3 + j*N3 + k] = elementNumber++;
            
                    }
                    cout << "}";
                }
                cout << "}";
                cout << endl ;
            }
            cout << "}" << endl;
            
            Delete3D(array3d);
            

            给出输出:

            {
            {{   0    1 }{   2    3 }{   4    5 }}
            {{   6    7 }{   8    9 }{  10   11 }}
            {{  12   13 }{  14   15 }{  16   17 }}
            {{  18   19 }{  20   21 }{  22   23 }}
            }
            

            【讨论】:

              猜你喜欢
              • 2016-05-20
              • 1970-01-01
              • 2019-01-05
              • 1970-01-01
              • 2023-04-04
              • 2012-03-11
              • 1970-01-01
              • 1970-01-01
              • 2015-12-08
              相关资源
              最近更新 更多