关于数组指针的问题?
int main()
{
int arr[5] = { 1,2,3,4,5 };
int* p = arr;
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ", *(p + i));
printf("%d ", p[i]);
}
return 0;
}
我是可以理解这里打印的时候p+i ==p[i]的 因为是将数组名arr赋值给了指针p
但是
void print2(int(*p)[5], int x, int y)
{
int i = 0;
int j = 0;
for (i = 0; i < x; i++)
{
for (j = 0; j < y; j++)
{
printf("%d ", p[i][j]);
printf("%d ", *((*p + i) + j));
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
print2(&arr, 3, 5);
}
这段代码中我想不通为什么 这为什么 *((*p+i)+j)可以等价于p[i][j]
疑问这里p不是被&arr赋值了吗 要找到arr不应该使用*p吗
*((*p+i)+j)这个我能明白
但是这个p[i][j]我看不明白 为什么不是(*p)[i][j]??
求前辈点一下 展开
首先,第一段代码不是这样理解的
数组名等效于该数组的首地址,即arr与&arr[0]等效
传递给p的不是arr数组名,而是该数组的首地址
对于第二段代码,我们要先好好地理解“指针”是什么
int *p 就声明了p是一个int型的指针变量
它所存储的信息是一个int型变量的地址
那么p+1就是与*p相邻的下一个int型变量的地址
p+i就是p的下下下······(i个下)个int型变量的地址
*(某地址)即得到该地址的变量的值(但对于数组只能得到位于该地址的数组的首地址)
再联系数组的定义,我们就不难发现*(p+i)等价于p[i]
那么若定义 int (*p)[5]
即p是一个 int ()[5] 型的指针变量
它存储的信息是一个长度为5的int型数组的地址
p[i][j]等价于*(*(p+i)+j)
那么*((*p+i)+j)是什么呢
*p是该数组的首地址,是一个int型指针
*p+i就是该数组第一个变量的下下下······(i个下)个变量的地址
(*p+i)+j就是该数组第一个变量的下下下······(i+j个下)个变量的地址
*((*p+i)+j)得到的是该数组第一个变量的下下下······(i+j个下)个变量
如果(i+j)超出了5(大于等于5)
二维数组arr含15个int型变量,它们会在内存中“一字排开”
即{1,2,3,4,5,2,3,4,5,6,3,4,5,6,7}
那么这下会取到什么值就能看得很清楚了
并且我们也可以发现,p[i][j]也等价于*(*p+i*5+j)
所以最终输出的值
还有:
第二段代码在部分编译器中会出现这样一段错误:
[Error] cannot convert 'int (*)[3][5]' to 'int (*)[5]' for argument '1' to 'void print2(int (*)[5], int, int)'
这是因为&arr与p不是同一类型的指针
但由于所有指针的所占空间都相等,所以在部分编译器中仍能通过
正确的方式应该是print2(arr, 3, 5);
为避免误导进行一些拓展:
变量在内存中的存储方式都是二进制,以8位为1字节是最小存储单位
变量在内存中的地址其实是往左增大的(以位移运算的方向为准)
但是我们在写数组时都是靠右的地址更大
实验:可定义一个unsigned short型变量a并赋值为256,定义一个unsigned char型指针p并赋值为&a,可发现p[0]值为0而p[1]值为1,即数的高位地址更大,结合数左移后值是变大的事实,可得出变量在内存中的地址其实是往左增大的。这在用unsigned char型指针编辑其他变量的值时要特别注意
2021-08-10
p+i == &p[i]
同理*((*p + i) + j也不等效于p[i][j]
*(*(p+i)+j)==p[i][j]