为啥指向指针的指针与指向数组的指针不兼容?

Posted

技术标签:

【中文标题】为啥指向指针的指针与指向数组的指针不兼容?【英文标题】:Why is a pointer to a pointer incompatible with a pointer to an array?为什么指向指针的指针与指向数组的指针不兼容? 【发布时间】:2011-12-16 22:21:14 【问题描述】:

好的,我无法理解指向指针的指针与指向数组的指针。 考虑以下代码:

char s[] = "Hello, World";
char (*p1)[] = &s;
char **p2 = &s;
printf("%c\n", **p1); /* Works */
printf("%c\n", **p2); /* Segmentation fault */

为什么第一个 printf 有效,而第二个无效?

据我了解,“s”是指向数组第一个元素(即“H”)的指针。 所以将 p2 声明为 char** 意味着它是一个指向 char 指针的指针。让它指向 's' 应该是合法的,因为 's' 是指向 char 的指针。因此取消引用它(即**p2)应该给出'H'。但事实并非如此!

【问题讨论】:

没有任何分配在 VC++2010 上编译。 奇怪。它在 GCC 4.4.4 上运行良好。 @Meta : 不在 GCC 4.3.4 (demo) 或 4.5.1 (demo)... @Meta :啊,你的代码是有效的 C 但不是有效的 C++; c++ 标签让所有人失望,所以我删除了它。 【参考方案1】:

您的误解在于s 是什么。它不是指针:它是一个数组。

现在在大多数情况下,s 的计算结果是指向数组第一个元素的指针:等效于 &s[0],即指向 'H' 的指针。但这里重要的是,您在评估 s 时获得的指针值是一个临时的、短暂的值 - 就像 &s[0] 一样。

因为该指针不是永久对象(它实际上不是存储在s 中的内容),所以您不能在其上创建指向指针的指针。要使用指针指向指针,您必须有一个真正的指针对象来指向——例如,以下是可以的:

char *p = s;
char **p2 = &p;

如果您评估*p2,您是在告诉编译器加载p2 指向的东西并将其视为指向字符的指针。当p2 确实指向一个指向字符的指针时,这很好;但是当你执行char **p2 = &s; 时,p2 指向的东西根本就不是一个指针——它是一个数组(在这种情况下,它是一个由 13 个chars 组成的块)。

【讨论】:

嗯,好的。我想我现在开始明白了。你能澄清一下关于 s 是“临时的、短暂的价值”的部分吗?不是每次都是同一个地址吗? @Meta:我的意思是s 计算的指针不是可寻址对象,就像a + 1 不是一样(在标准中,它不是左值)。跨度> @caf,如果s不是可寻址对象,为什么&s不是编译错误(但&(a+1)是)? @Shahbaz: s 一个可寻址对象 - 它是一个数组 - 但 s 在大多数情况下计算为指针值不是可寻址对象。碰巧&ss 确实not 评估指向第一个元素的指针的上下文之一 - 它仍然是数组的指示符,因此&s 给出了地址那个数组。 s 仍然指定数组本身的另一个上下文是 sizeof s(所以这给出了 array 的大小,而不是指针的大小)。 @caf,它开始变得有意义了。数组名就像一个函数名,它的& 给出了它的地址,但是因为没有& 它没有意义,没有& 它也给出了地址!同样的方式func&func 将是相同的值。这也是为什么应该使用char (*p)[],类似于char (*fptr)()。我说的对吗?【参考方案2】:

From what I understand, 's' is a pointer to the first element of the array 不,s 是一个数组。它可以简化为指向数组的指针,但在此之前,它是一个数组。指向数组的指针变成指向数组第一个元素的指针。 (是的,这有点令人困惑。)

char (*p1)[] = &s; 这是允许的,它是一个指向数组的指针,分配了数组的地址。它指向 s 的第一个元素。

char **p2 = &s; 这会创建一个指向指针的指针并将其分配给数组的地址。当它认为它是一个指向一个或多个字符的指针时,你为其分配一个指向 s 的第一个元素(char)的指针。取消引用这是未定义的行为。 (你的情况是段错误)

它们不同的证据在于sizeof(char[1000])(返回1000个字符的大小,而不是指针的大小),函数如下:

template<int length>
void function(char (&arr)[length]) 

当给定一个数组而不是指针时,它将编译。

【讨论】:

【参考方案3】:

以下是有效的示例,以及指针地址的打印输出,以便于查看:

#include <stdio.h>
char s[] = "Hello, World";
char (*p1)[] = &s;
char *p2 = (char*)&s;

int main(void)

   printf("%x %x %x\n", s, p2, *p2);
   printf("%x\n", &s);    // Note that `s` and `&s` give the same value
   printf("%x\n", &s[0]);
   printf("%c\n", **p1); 
   printf("%c\n", *p2);

【讨论】:

我在您的代码中添加了一行,以便更清楚为什么会发生这种情况。

以上是关于为啥指向指针的指针与指向数组的指针不兼容?的主要内容,如果未能解决你的问题,请参考以下文章

定义了一个常数组,为啥能用指针改变数组元素的值?

C语言中 内存消亡 指向她的指针就一定消亡或成了空指针为啥是错的啊

C语言基础:指针相关概念(指针的算术运算 指针数组指向指针的指针 传递指针给函数 从函数返回指针 )为啥C 语言不支持在调用函数时返回局部变量的地址?

为啥指向成员函数的指针不像数据指针那样只是内存地址

指针&数组

在C语言中能否直接给指针指向的数据赋值?为啥?