C中的多维数组:它们是锯齿状的吗?

关于C编程语言(ANSI-C)的一个简单问题:

C中的多维数组是锯齿状的吗?

我的意思是 – 我们在谈论“数组数组”(一个指向内存中其他地址的指针数组),或者这只是“长一维数组”(它是按顺序存储在内存中)?

困扰我的是我有点确定:

matrix[i][j]相当于* ( * (matrix + i) + j)

C中的多维数组是连续的。 下列:

 int m[4][5]; 

由4个int[5]组成,在记忆中彼此相邻。

一个指针数组:

 int *m[4]; 

是锯齿状的。 每个指针都可以指向不同长度的单独数组(的第一个元素)。

m[i][j]等价于*(*(m+i)+j) 。 参见C11标准 ,第6.5.2.1节:

下标运算符[]的定义是E1 [E2]与(*((E1)+(E2))相同)

因此, m[i][j]等价于(*(m+i))[j] ,其等价于*(*(m+i)+j)

存在这种等价是因为在大多数情况下,数组类型的表达式会衰减到指向其第一个元素的指针(C11标准,6.3.2.1)。 m[i][j]被解释如下:

  • m是一个数组数组,因此它衰减到指向m[0]的指针,即第一个子数组。
  • m+i是指向mi个子arrays的指针。
  • m[i]等价于*(m+i) ,取消引用指向mi个子数组的指针。 由于这是数组类型的表达式,因此它衰减为指向m[i][0]的指针。
  • m[i][j]等价于*(*(m+i)+j) ,取消引用指向ji个子数组的第j个元素的指针。

请注意,指向数组的指针与指向其第一个元素的指针不同。 m+i是指向数组的指针; 它不是数组类型的表达式,它不会衰减,无论是指向指针还是指向任何其他类型。

连续的内存区域:

 int arr[N][M]; 

一个非连续的内存区域:

 int** arr = malloc(N*sizeof(int*)); for (int i=0; i 

在两种情况下,您都可以将arr用作二维数组(例如, arr[1][2] = 3 )。 但是,您可以安全地应用更大的复制操作,例如memset(arr,0,N*M*sizeof(int)) ,仅在第一种情况下。

这取决于。

C中的多维数组按顺序排列。

如果要使用指针,可以创建锯齿状数组。

如果声明一个多维数组,则会得到“长一维数组”(它按顺序存储在内存中)。

如果声明指向指针(指针….)的指针,则会得到数组数组。

对于初学者C程序员来说,这种差异会引起很多混乱。

一个或多个数组,如int matrix[A][B]不是锯齿状的,因为matrix每个元素都是array of B intarray of B int

您想知道*(*(matrix+i)+j)的结果是并将其与matrix[i][j]的结果进行比较。

由于matrix的类型是array of A array of B int ,因此表达式matrix+i是指向matrix array of B int的第iarray of B int指针,其类型是int (*)[B] 。 取消引用此表达式将生成一个array of B int 。 表达式*(matrix+i)+j)导致指向该数组的第jint的指针。 取消引用该表达式会产生一个int 。 这相当于表达式matrix[i][j]作用。

指针数组(例如int *matrix[A] )可能是锯齿状的,因为matrix每个元素可能指向不同大小的分配。

你是对的, matrix[i][j]相当于*(*(matrix + i) + j) ,因为arr[i]相当于*(arr + i) 。 但是,请记住,如果arr被声明为

 int arr[64]; 

那么对arr任何引用都可以隐式转换为&arr[0] ,即指向第一个元素的指针。 数组数组也是如此:

 int matrix[8][8]; 

这里matrix类型为int[8][8] ,当你向它添加一个整数时会自动转换为int (*)[8] ,就像在matrix + i 。 然后*(matrix + i)有类型int[8] ,当你添加j时再次转换为int * ,所以*(matrix + i) + j类型为int * ,因此*(*(matrix + i) + j)按预期输入int

所以重点是, 数组不是指针 ,只是它们可以隐式地转换为指向第一个元素的指针。

因此,如果您分配上面的数组数组( int matrix[8][8]; ),那么所有元素在内存中都是连续的。