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
是指向m
第i
个子arrays的指针。 -
m[i]
等价于*(m+i)
,取消引用指向m
第i
个子数组的指针。 由于这是数组类型的表达式,因此它衰减为指向m[i][0]
的指针。 -
m[i][j]
等价于*(*(m+i)+j)
,取消引用指向j
第i
个子数组的第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 int
的array of B int
。
您想知道*(*(matrix+i)+j)
的结果是并将其与matrix[i][j]
的结果进行比较。
由于matrix
的类型是array of A array of B int
,因此表达式matrix+i
是指向matrix
array of B int
的第i
个array of B int
指针,其类型是int (*)[B]
。 取消引用此表达式将生成一个array of B int
。 表达式*(matrix+i)+j)
导致指向该数组的第j
个int
的指针。 取消引用该表达式会产生一个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];
),那么所有元素在内存中都是连续的。