所以我试图弄清楚指针,我读了一些关于指针的文章,但我仍然不明白为什么这个程序运行起来没有问题
#include <stdio.h>
#include <assert.h>
int main(){
char* p = "abc";
char** pp[2];
pp[0] = &p;
assert(*pp[0]==**pp);
printf("Comparison: %s, %s\n",**pp, *pp[0]);
return 0;
}
据我所知,记忆应该是这样的
Memory Address (hex) Variable name Contents
1000 'a' == 97 (ASCII)
1001 'b' == 98
1002 'c' == 99
1003 0
...
2000-2003 p 1000 hex
...
3000-3003 pp[0] 2000 hex
在这一点上,假设我的记忆是正确的…我希望*pp进入内存并说...
所以pp指向p的地址,它是0x2000,通过取消引用,我希望获得地址0x2000的内容,在我看来,这意味着我将获得0x1000,但情况并非如此,因为程序的输出是:
输出
abc, abc
在**pp的情况下,我认为它首先解引用pp,这将给我们提供pp所指向的内容,这意味着0x2000 (即0x1000)的内容,然后通过再次解引用,我们得到地址0x1000的内容
为什么它们是相等的呢?我遗漏了什么吗?
发布于 2016-01-27 07:44:46
在大多数上下文中,如果您有一个数组a
,则a
是&a[0]
的缩写。(也有一些例外,例如sizeof a
或&a
)。
所以**pp
实际上是指**&pp[0]
。
&pp[0]
是pp[0]
的地址,所以*&pp[0]
等同于pp[0]
,所以**&pp[0]
等同于*pp[0]
。
发布于 2016-01-27 07:49:02
pp总是和*pp一样,不管你处理的是什么类型的指针。
鉴于方括号的运算符优先级很高,*pp与*(pp)相同...根据上面的句子,它将与*(*pp)相同,后者与**pp相同。Q.E.D.
发布于 2016-01-27 07:50:19
,所以pp指向p的地址,它是0x2000,通过取消引用,我希望得到地址0x2000的内容
这是你的推理失误,但可以理解。在C中,赋值的右边,或者通常是对左值的求值,更准确地说,是左值到右值的转换,已经是一个解引用了!例如,int i, j=0; i=j;
有效地取消了对j
的引用;j
是一个地址常量,赋值涉及存储在那里的值,j
的值,因此赋值等于i=0
。其他语言,如Algol68,更精确:一种语言可以有效地编写int i; int *pi = i;
,这是完全有意义的(pi现在指向i)。
这就是为什么在使用*pp[0]
显式地取消对pp[0]
的引用时,实际上是在两次取消对它的引用:首先查看地址0x2000的内容,即0x1000,然后再取消引用以便在0x1000处读取内存。
https://stackoverflow.com/questions/35026135
复制相似问题