面试题答案
一键面试void func(int (*p)[3]) {
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
p[i][j]++;
}
}
}
数组名 a
到指针 p
的转换细节
在C语言中,当数组名作为函数参数传递时,数组名会自动转换为指向数组首元素的指针。对于二维数组 int a[2][3]
,数组名 a
转换为 int (*)[3]
类型的指针,它指向一个包含3个 int
型元素的数组。
具体来说,a
本身是一个指向 int [3]
数组的指针,即 a
的类型是 int (*)[3]
。在函数调用 func(a)
时,将 a
的值(即指向二维数组首行的指针)传递给函数 func
的参数 p
,p
同样是 int (*)[3]
类型的指针,它指向了和 a
相同的内存位置。
函数内部指针操作与原数组之间的内存映射关系
在函数 func
内部,p
指向了二维数组 a
的首行。p[i][j]
这种写法等同于 *(*(p + i) + j)
。
p + i
:由于p
是int (*)[3]
类型的指针,p + i
会根据int [3]
数组的大小进行偏移,即偏移量为i * sizeof(int [3])
,这样就指向了第i
行的int [3]
数组。*(p + i)
:解引用p + i
,得到第i
行的int [3]
数组的首地址,此时类型变为int *
。*(p + i) + j
:在int *
类型的指针基础上,再偏移j
个int
大小的位置,即指向第i
行第j
列的元素。*(*(p + i) + j)
:最终解引用得到该位置的元素值,对其进行加1操作,就直接修改了原二维数组a
对应位置的元素值。所以函数内部对p
的操作会直接影响原数组a
的内容,因为它们指向同一块内存区域。