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

发布于 2024-12-12 05:10:07 字数 394 浏览 0 评论 0原文

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

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”。但事实并非如此!

OK, I'm having trouble understanding pointers to pointers vs pointers to arrays.
Consider the following code:

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

Why does the first printf work, while the second one doesn't?

From what I understand, 's' is a pointer to the first element of the array (that is, 'H').
So declaring p2 as char** means that it is a pointer to a pointer to a char. Making it point to 's' should be legal, since 's' is a pointer to a char. And thus dereferencing it (i.e. **p2) should give 'H'. But it doesn't!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

海风掠过北极光 2024-12-19 05:10:07

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

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

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

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

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

Your misunderstand lies in what s is. It is not a pointer: it is an array.

Now in most contexts, s evaluates to a pointer to the first element of the array: equivalent to &s[0], a pointer to that 'H'. The important thing here though is that that pointer value you get when evaluating s is a temporary, ephemeral value - just like &s[0].

Because that pointer isn't a permanent object (it's not actually what's stored in s), you can't make a pointer-to-pointer point at it. To use a pointer-to-pointer, you must have a real pointer object to point to - for example, the following is OK:

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

If you evaluate *p2, you're telling the compiler to load the thing that p2 points to and treat it as a pointer-to-char. That's fine when p2 does actually point at a pointer-to-char; but when you do char **p2 = &s;, the thing that p2 points to isn't a pointer at all - it's an array (in this case, it's a block of 13 chars).

追风人 2024-12-19 05:10:07

据我了解,'s'是指向数组第一个元素的指针
不,s 是一个数组。它可以简化为指向数组的指针,但在此之前,它只是一个数组。指向数组的指针成为指向数组第一个元素的指针。 (是的,这有点令人困惑。)

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

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

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

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

:当给定数组而不是指针时进行编译。

From what I understand, 's' is a pointer to the first element of the array
No, s is an array. It can be reduced to a pointer to an array, but until such time, it is an array. A pointer to an array becomes a pointer to the first element of the array. (yeah, it's kinda confusing.)

char (*p1)[] = &s;
This is allowed, it's a pointer to an array, assigned the address of an array. It points to the first element of s.

char **p2 = &s;
That makes a pointer to a pointer and assigns it the address of the array. You assign it a pointer to the first element of s (a char), when it thinks it's a pointer to a pointer to one or more chars. Dereferencing this is undefined behavior. (segfault in your case)

The proof that they are different lies in sizeof(char[1000]) (returns size of 1000 chars, not the size of a pointer), and functions like this:

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

which will compile when given an array, but not a pointer.

李不 2024-12-19 05:10:07

这是有效的示例,加上指针地址的打印输出,使事情变得简单易懂:

#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);
}

Here's the sample that works, plus printouts of pointer addresses to make things simple to see:

#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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文