关于C编程语言(ANSI-C)的一个简单问题:
C中的多维数组是否呈锯齿状?
我的意思是 - 我们是在谈论“数组数组”(一个指向内存中其他地址的指针数组),或者这只是“长一维数组”(它是按顺序存储在内存中的)? / p>
困扰我的是我确信:
matrix[i][j]
相当于* ( * (matrix + i) + j)
答案 0 :(得分:13)
C中的多维数组是连续的。以下内容:
int m[4][5];
由4个int[5]
组成,在记忆中彼此相邻。
指针数组:
int *m[4];
是锯齿状的。每个指针都可以指向不同长度的单独数组(的第一个元素)。
m[i][j]
相当于*(*(m+i)+j)
。请参阅C11 standard,第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
是指向i
m
子阵列的指针。m[i]
相当于*(m+i)
,取消引用指向i
m
子阵列的指针。由于这是数组类型的表达式,因此它会衰减为指向m[i][0]
。m[i][j]
相当于*(*(m+i)+j)
,取消引用指向j
i
子阵列的m
元素的指针。请注意,指向数组的指针与指向其第一个元素的指针不同。 m+i
是指向数组的指针;它不是数组类型的表达式,它不会衰减,无论是指向指针还是指向任何其他类型的指针。
答案 1 :(得分:3)
连续的记忆区域:
int arr[N][M];
非连续的记忆区域:
int** arr = malloc(N*sizeof(int*));
for (int i=0; i<N; i++)
arr[i] = malloc(M*sizeof(int));
在这两种情况下,您都可以将arr
用作二维数组(例如arr[1][2] = 3
)。但是,您可以安全地应用更大的复制操作,例如memset(arr,0,N*M*sizeof(int))
,仅在第一种情况下。
答案 2 :(得分:2)
这取决于。
C中的多维数组按顺序排列。
如果要使用指针,可以创建锯齿状数组。
答案 3 :(得分:1)
如果声明一个多维数组,则会得到“长一维数组”(按顺序存储在内存中)。
如果声明指向指针(指针......)的指针,则会得到数组数组。
这种差异是初学者C程序员非常困惑的原因。
答案 4 :(得分:0)
int matrix[A][B]
之类的数组不是锯齿状的,因为matrix
的每个元素都是array of B int
。
您想知道*(*(matrix+i)+j)
的结果,并将其与matrix[i][j]
的结果进行比较。
由于matrix
的类型为array of A array of B int
,因此表达式matrix+i
是指向i
array of B int
matrix
的指针},其类型为int (*)[B]
。取消引用此表达式会生成array of B int
。表达式*(matrix+i)+j)
会生成指向该数组的j
int
的指针。取消引用该表达式会产生int
。这相当于表达式matrix[i][j]
的作用。
指针数组(例如int *matrix[A]
)可能会出现锯齿状,因为matrix
的每个元素都可能指向不同大小的分配。
答案 5 :(得分:0)
您是对的,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]
类型,当您添加int *
时会再次转换为j
,因此*(matrix + i) + j
的类型为int *
,因此{{} 1}}具有预期的类型*(*(matrix + i) + j)
。
所以关键是,数组不是指针,只是它们可以隐式地转换为指向第一个元素的指针。
因此,如果您分配上述数组(int
),那么所有元素在内存中都是连续的。