多维动态数组,为啥不起作用?

Posted

技术标签:

【中文标题】多维动态数组,为啥不起作用?【英文标题】:Multidimensional dynamic arrays, Why doesn't it work?多维动态数组,为什么不起作用? 【发布时间】:2012-09-13 04:56:43 【问题描述】:

我不是在这里寻找解决方案,我在 Google 上找到了很多。我正在寻找解释。

在玩数组时,我发现动态声明二维数组并不像预期的那样工作

一维数组,作品

int main()

int rows;
int* pointer;
pointer = new int[rows]; 

二维数组,不起作用

int main()

int rows;
int columns;
int* pointer;
pointer = new int[rows][columns]; //error on this line

在我看来,这是一种直观的做事方式,因为这就是它对常规数组的处理方式,但显然它不正确并且不会编译。

我一直没能找到清楚的解释为什么会这样,希望这里的人能启发我。

谢谢:)

【问题讨论】:

真的,如果我是你,我只会使用向量。我知道你不想要解决方案,但我对此深有感触,所以我想我会把它作为评论。 This entry of the C++-FAQ on arrays 可能会有所帮助。不仅对 OP,对一些回答者也是如此。 【参考方案1】:

这不起作用的原因是,为了能够拥有一个二维数组,您需要一个指针数组,该数组将指向许多您想要的类型的数组。

在这种情况下,您尝试将地址存储到 int* 类型的变量中的 int* 数组(其中每个“单元格”将指向一个 int 数组),它应该是 int**。

回顾一下: 一维数组:int* 二维数组:int** 3D数组:int***

所有数组必须是一维的原因是因为您的内存是一维的(将所有内存视为一个大的内存地址数组),这意味着多维数组必须是“伪造的”。

【讨论】:

这不仅仅是数据类型的问题(顺便说一下,如果new 与二维数组语法一起使用,则它是int(*)[],而不是int**)。除了数据类型问题:使用new直接在堆上分配二维数组只有在第二维作为常量表达式给出时才有效。【参考方案2】:

这不仅仅是其他答案所描述的数据类型问题。

类似的语法

pointer = new int[rows][columns]

仅当columns 是一个常量表达式时才有效。您不能在那里使用变量(但请注意,rows 可以是变量)。

这里是解释。 C++ 标准仅允许您通过以下方式将二维数组语法与 new 运算符一起使用(来自 §5.3.4/1):

new-expression:
  ::opt new new-placementopt new-type-id new-initializeropt
  ::opt new new-placementopt ( type-id ) new-initializeropt
new-placement:
  ( expression-list )
new-type-id:
  type-specifier-seq new-declaratoropt
new-declarator:
  ptr-operator new-declaratoropt
  noptr-new-declarator
noptr-new-declarator:
  [ expression ] attribute-specifier-seqopt
  noptr-new-declarator [ constant-expression ] attribute-specifier-seqopt
new-initializer:
  ( expression-listopt )
  braced-init-list

相关部分是这样的:

noptr-new-declarator:
  [ expression ] attribute-specifier-seqopt
  noptr-new-declarator [ constant-expression ] attribute-specifier-seqopt

第一行的意思是你可以在 type-id 后面加上一个括号表达式。第二行(这是一个递归语句)允许您在最初的括号之后使用多对括号,但它们必须包含一个常量表达式

标准进一步解释了这一点(强调我的):

(§5.3.4/5) 当分配的对象是一个数组(即使用 noptr-new-declarator 语法或 new-type-id 或 type-id 表示数组类型)时,new -expression 产生一个指向数组初始元素(如果有)的指针。 [ 注意:new int 和 new int[10] 都具有 int* 类型,并且 new int[i][10] 的类型是 int (*)[10] — end note ] 属性- noptr-new-declarator 中的 specifier-seq 属于关联的数组类型。

(§5.3.4/6) noptr-new-declarator 中的每个常量表达式都应是一个整数常量表达式 (5.19),并计算为严格的正值。 noptr-new-declarator 中的表达式应为整数类型、无范围枚举类型或存在单个非显式转换函数到整数或无范围枚举类型的类类型 (12.3)。 [...] [ 示例:给定定义 int n = 42,new float[n][5] 是格式良好的(因为 n 是 noptr-new-declarator 的表达式),但是 new float[ 5][n] 格式不正确(因为 n 不是常量表达式)。 — 结束示例]

【讨论】:

【参考方案3】:

你可以通过以下方式理解它:

二维数组看起来像一个带有行和列的网格,用于人类表示,但在内存中它存储在连续的内存中。因此,每当您说二维数组或大小mxn 时,您指的是m 数组n 元素一个接一个地存储。即对于 3x3 网格元素存储为:

(0,0) (0,1) (0,2) (1,0) (1,1) (1,2) (2,0) (2,1) (2,2)

如果你想访问这样的数据结构,你需要使用指向指针的指针,即指向每行第一个元素的位置地址数组的指针。

因此可以通过 3 个(行数)地址访问数组

(Address of element 0,1) (Address of element 1,0) (Address of element 2,0)

由于存储了元素的地址,所以现在你需要一个指向指针的指针来访问这个指针数组(保存每行第一个元素的地址)。

对于一维数组:

int* pointer = new int[3];

Array: (0) (1) (2)
pointer: (Address of first element of Array)

对于二维数组:

int **pointer = new int[3][3];

Array: (0,0) (0,1) (0,2) (1,0) (1,1) (1,2) (2,0) (2,1) (2,2)
Row Address Array: (Address of 0,1) (Address of 1,0) (Address of 2,0)
pointer: (Address of first element of Row Address Array)

希望这会有所帮助!

【讨论】:

你说的是真的,但 OP 给出的代码中的真正问题是维度是 both 作为变量给出的。如果 new 与 2D 数组语法一起使用,情况会有所不同。【参考方案4】:

其他人已经很好地解释了这一点,但这里有一个示例可以阐明使用 new 创建动态大小的多维数组:

int rows = 20;
int columns = 30;

// the following is essentially just an array of int pointers
int **pointer = new int*[rows]; 

// so, loop through the array creating the second dimension
for (int i = 0;i < rows;i++)
    pointer[i] = new int[columns];

【讨论】:

【参考方案5】:

这是一个一维字符指针数组:char* Dynamic_One_Dimensional_Char_Pointer_Array。注意char *

这是一个二维字符指针数组:char **Dynamic_Two_Dimensional_Char_Pointer_Array。注意char **

这是为二维字符指针数组分配内存的方式:

    //memory allocated for elements of rows.
    Dynamic_Two_Dimensional_Char_Pointer_Array = new char *[ROWS] ;

    //memory allocated for  elements of each column.
    for(   i = 0 ; i < ROWS ; i++ ) Dynamic_Two_Dimensional_Char_Pointer_Array[i] = new char[COLUMNS];

这是如何打印二维数组([rows][columns]):

   for(rows=0;rows<maxLines;rows++)
   
       for(int columns=0;columns<strlen(Dynamic_Two_Dimensional_Char_Pointer_Array[rows]);columns++)
       
            cout<<Dynamic_Two_Dimensional_Char_Pointer_Array[rows][columns]<<"";
       
       cout<<"  \n";
   

这就是你为二维字符指针数组取消分配内存的方式:

//free the allocated memory
for(   i = 0 ; i < ROWS ; i++ )   delete [] Dynamic_Two_Dimensional_Char_Pointer_Array[i] ;
delete [] Dynamic_Two_Dimensional_Char_Pointer_Array ;

完整示例代码:

#include<vector>
#include<string>
#include<iostream>
using namespace std;

int main()


    int COLUMNS =80; //80 characters wide
    int ROWS =20;// 20 lines
    int i,maxLines=0;

    char* Dynamic_One_Dimensional_Char_Pointer_Array = new char[80];
    char **Dynamic_Two_Dimensional_Char_Pointer_Array = 0;

    //memory allocated for elements of rows.
    Dynamic_Two_Dimensional_Char_Pointer_Array = new char *[ROWS] ;

    //memory allocated for  elements of each column.
    for(   i = 0 ; i < ROWS ; i++ ) Dynamic_Two_Dimensional_Char_Pointer_Array[i] = new char[COLUMNS];


    strcpy(Dynamic_One_Dimensional_Char_Pointer_Array,"apples 123 oranges 456 bananas 789 lemons 101112 kiwi 132415 grapes 161718" );
    cout<<"  \ninput = "<<Dynamic_One_Dimensional_Char_Pointer_Array<<"  \n\n";
    cout<<"Output = \n";

    char seperators[]   = " ,\t\n";
    char *token; 
   token = strtok( Dynamic_One_Dimensional_Char_Pointer_Array, seperators );  
   i=0;

   while( token != NULL )
   
      strcpy(Dynamic_Two_Dimensional_Char_Pointer_Array[i],token);
      token = strtok( NULL, seperators );  
      i++;
   
   maxLines=i;
   cout<<"  \n";

   cout<<"show contents 1 print [rows] \n";
   cout<<"-------------------------------------------\n";
   for(int rows=0;rows<maxLines;rows++)
   
     cout<<Dynamic_Two_Dimensional_Char_Pointer_Array[rows]<<"  \n";
   
   cout<<"  \n";

   cout<<"show contents 2  print [rows][columns]\n";
   cout<<"-------------------------------------------\n";

   for(rows=0;rows<maxLines;rows++)
   
     //cout<<Dynamic_Two_Dimensional_Char_Pointer_Array[rows]<<"  \n";
       for(int columns=0;columns<strlen(Dynamic_Two_Dimensional_Char_Pointer_Array[rows]);columns++)
       
            cout<<Dynamic_Two_Dimensional_Char_Pointer_Array[rows][columns]<<"";
       
       cout<<"  \n";
   



    delete[] Dynamic_One_Dimensional_Char_Pointer_Array;

    //free the allocated memory
    for(   i = 0 ; i < ROWS ; i++ )   delete [] Dynamic_Two_Dimensional_Char_Pointer_Array[i] ;
    delete [] Dynamic_Two_Dimensional_Char_Pointer_Array ;

    return 0;

【讨论】:

以上是关于多维动态数组,为啥不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

为啥这个 PHP 递归函数不起作用

PHP array_key_exists 不起作用;数组不是多维的

在 PHP 7.0 中编码多维数组不起作用 (json_encode)

为啥通过动态链接导航后pushViewController 不起作用?

为啥 addEventListener 属性对动态 HTMLcollection 对象不起作用?

为啥动态组件创建中的属性绑定不起作用?