C中的多重引用和解引用

有人可以解释我多重参考和解除引用背后的概念吗? 为什么以下程序将输出设为’h’?

int main() { char *ptr = "hello"; printf("%c\n", *&*&*ptr); getchar(); return 0; } 

而不是这个,而是产生’d’?

 int main() { char *ptr = "hello"; printf("%c\n", *&*&ptr); getchar(); return 0; } 

我读到连续使用’*’和’&’相互抵消,但这个解释没有提供上述代码中产生的两个不同输出背后的原因?

第一个程序产生h因为& s和* s相互“取消”:“取消引用X的地址”返回X:

  • ptr – 指向"hello"文字的首字符的指针
  • *ptr – 取消引用指向初始字符的指针,即初始字符
  • &*ptr指向初始字符的指针的解引用地址,即指向初始字符的指针,即ptr本身

等等。 正如您所看到的,一对*&并将您带回到您已经开始的位置,因此您可以从取消引用/获取地址表达式中删除所有这些对。 因此,您的第一个程序的printf相当于

 printf("%c\n", *ptr); 

第二个程序具有未定义的行为,因为指针正在传递给printf ,格式说明符为%c 。 如果将相同的表达式传递给%s ,则会打印单词hello

 printf("%s\n", *&*&ptr); 

让我们来看看该计划的重要部分:

 char *ptr = "hello"; 

创建一个指向字符串文字"hello" char的指针。 现在,对于令人困惑的部分:

 printf("%c\n", *&*&*ptr); 

这里, %c需要一个char 。 让我们看看*&*&*ptr是什么类型。 ptr是一个char* 。 应用解除引用运算符( * )会产生一个char 。 将address-of运算符应用于此char会返回char* 。 这再次重复,最后, *最后给我们一个char ,字符串文字"hello"的第一个字符,它被打印出来。


在第二个程序中,在*&*&ptr ,首先应用&运算符,它给出了一个char** 。 在此上应用*会返回char* 。 这再次重复,最后,我们得到一个char* 。 但是%c需要char ,而不是char* 。 因此,第二个程序根据C11标准展示未定义行为 (强调我的):

7.21.6.1 fprintf函数

[…]

  1. 如果转换规范无效,则行为未定义。 282 如果任何参数不是相应转换规范的正确类型,则行为未定义。

所以,基本上,当你执行第二个程序时,任何事情都会发生。 您的程序可能会崩溃,发出分段错误,输出奇怪的内容或执行其他操作。


顺便说一句,你说得对:

我读到连续使用’*’和’&’相互抵消

让我们分解*&*&*ptr实际上是什么,但首先,请记住,当将*应用于指针时,它会为您提供指针所指向的内容。 另一方面,当应用&变量时,它会为您提供该变量的内存地址。

现在,在得到稳定的基础之后,让我们看看你在这里有什么: ptr是一个指向char的指针,因此在执行*ptr它会给你ptr指向的数据,在这种情况下, ptr指向一个字符串"hello"但是,一个char只能容纳一个char,而不是整个字符串,对吧? 所以,它指向这样一个字符串的开头,这是其中的第一个字符,即h

继续… *&*&*ptr=*&*&(*ptr) = *&*&('h')= *&*(&'h') = *&*(ptr)=*&(*ptr) = *&('h')= *ptr = 'h'

如果你在下一个函数上应用相同的模式,我很确定你能搞清楚。

摘要:从右到左读取指针!