2011-10-27 74 views
12

好吧,我很难理解指针指向数组的指针。 考虑下面的代码:为什么指向一个指针与指向数组的指针不兼容?

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'。但它不!

+1

的分配没有汇编VC++ 2010。 – Jon

+0

奇怪。它在GCC 4.4.4上正常工作。 – Meta

+0

@Meta:不在GCC 4.3.4([demo](http://ideone.com/K6D1D))或4.5.1([demo](http://ideone.com/gTGhY))... – ildjarn

回答

11

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

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

由于该指针不是永久性对象(它实际上并不存储在s中),因此无法在其中指向指针指针。使用指针到指针,你必须有一个指针对象指向 - 例如,以下是OK:

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

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

+0

好的。我想我现在开始明白了。 你能否澄清关于s是'暂时的,短暂的价值'的部分?每次都不是同一个地址吗? – Meta

+1

@Meta:我的意思是,'s'计算的指针不是一个可寻址的对象,就像'a + 1'不是一样(在标准的情况下,它不是一个左值)。 – caf

+0

@caf,如果's'不是一个可寻址的对象,那么'&s'怎么不是一个编译错误(但是'&(a + 1)')? – Shahbaz

1

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]) {} 

这将编译时给定一个数组,但不是一个指针。

1

下面是工程样品,加上指针地址的打印输出,使事情变得简单看:

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

我在代码中添加了一行代码,使其更清晰一些。 – Shahbaz

相关问题