我创建了一个指向指针和int数组的指针,但是当我尝试通过指向指针的指针访问数组时,它会跳过一些元素并一次移动两个元素(例如:从1到3).这是我的代码:
int main(void) {
int c=10;
int p[5]={2,3,5,6,8};
int *x;
int **y;
x=p;
y=&p;
printf("p value is %d and p points to %d",p,&p);
printf("\n x is %d \n",x[1]);
printf("\n y is %d \n",y[0]);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我打印y[1]它将打印5而不是3并y[2]打印为8.我想不出原因.谁可以帮我这个事?指针x是沿着正确的元素,做工精细和移动x[0]=2,x[1]=3,x[5]=5.也可以解释为什么我得到p和&p的相同值
好吧,这个问题已经回答的答案已被接受,但即使是公认的答案并不能解释的奇怪的结果楼主是看到:为什么y[1]和y[2]打印5和8?这是解释.
原创海报:您从以下声明中得到了什么结果?
printf ("Size of integer: %zu\n", sizeof (int));
printf ("Size of pointer: %zu\n", sizeof (int*));
Run Code Online (Sandbox Code Playgroud)
我敢打赌输出是:
Size of integer: 4
Size of pointer: 8
Run Code Online (Sandbox Code Playgroud)
换句话说,我猜你在64位机器上进行编译,其中整数的大小是4个字节,指针的大小是8个字节.基于这个假设,这是正在发生的事情.
p是一个数组.除了少数例外,当在任何表达式中使用时,数组的名称"衰减"为指向其第一个元素的指针.p因此,只要您访问其值,它就会生成其第一个元素的地址.
&p关于数组"衰减"到指针的规则的例外之一.当应用于数组名称时,address-of运算符返回指向整个数组的指针 - 而不是指向指向数组第一个元素的指针的指针.
这意味着的是,p与&p具有相同的价值,但它们在语义上是非常不同的.打印时,您将获得相同的值:
printf("p value is %p and p points to %p", p, &p); // use %p and not %d for addresses
Run Code Online (Sandbox Code Playgroud)
但是,这并不意味着p并且&p指的是同一件事.p是数组的第一个元素的地址,即&p[0].另一方面,&p是整数5个整数数组的地址.
所以当你定义x和y如下:
int* x = p;
int** y = &p;
Run Code Online (Sandbox Code Playgroud)
x被赋予指向数组的第一个元素的指针; y被指定一个指向整个数组的指针.这是一个重要的区别!
此外,y声明的方式与您分配给它的值之间存在不匹配.&p属于int (*) [5]; 指向数组5的指针int.y仅仅是指向单个指针的指针int.您的编译器应该向您发出有关此不匹配的警告.我的确如此:
Warning: incompatible pointer types assigning to 'int**' from 'int (*) 5'
Run Code Online (Sandbox Code Playgroud)
这种不匹配解释了打印y[1]和的价值时的奇怪结果y[2].让我们来看看这些价值观是怎样的.
如您所知,数组下标是从数组开头的偏移量:
x[0] == *(x + 0)
Run Code Online (Sandbox Code Playgroud)
因此x[0]产生数组的第一个元素,即2.类似地
x[1] == *(x + 1)
Run Code Online (Sandbox Code Playgroud)
但是x是指向int的指针.那么添加中真正的幸福是什么x + 1?记住指针算法的工作原理.向指针添加整数意味着您实际上将该整数乘以指向的元素的大小.在这种情况下:
x + 1 == x + (1 * sizeof(int))
Run Code Online (Sandbox Code Playgroud)
由于sizeof(int)系统上为4,因此值为x[1]数组中的下一个整数,即3.
那么,当你打印时y[0],这是如何评估的?
y[0] == *(y + 0)
Run Code Online (Sandbox Code Playgroud)
因此,打印在地址所指向的地址处的值y,即在地址处p.这是第一个元素p,因此得到结果2.
打印时会发生什么y[1]?
y[1] == *(y + 1)
Run Code Online (Sandbox Code Playgroud)
但是什么y呢?这是一个pointer to a pointer to an int.因此,当您添加1时y,指针算法的工作方式是它再次添加1*指向的元素类型的大小.
y + 1 == y + (1 * sizeof (int*))
Run Code Online (Sandbox Code Playgroud)
a的大小int*是8个字节,而不是4个字节!因此,每次递增y1时,您将其递增8个字节,或两个整数的大小.因此,当你取消引用该值时,你得到的不是数组中的下一个整数,而是两个距离的整数.
为了更清楚地解释:让我们假设数组从元素1000开始.然后,因为每个都int需要4个字节,所以情况如下:
Address Element
-----------------------
1000 2
1004 3
1008 5
1012 6
1016 8
p == &p == x == y == 1000
*x == *y == 2
Run Code Online (Sandbox Code Playgroud)
当您向x添加1时,您正在添加1*sizeof(int),即您实际上正在添加4.因此,您获得1004,并且*(x + 1),或者x[1],给您3.
但是当你向y添加1时,你正在添加1*sizeof(int*),即你实际上是在添加8.所以你得到1008,并*(y + 1)给你地址1008或5的元素.
这解释了您获得的输出.但是,这不是一种合理的编码方式.你不应该指望指针的大小总是8个字节.你不应该分配int (*) []一个int**.您不应该取消引用指向指针的指针int并期望获得int结果.并始终注意编译器警告.