2011-06-24 77 views
9

人。'char(* p)[5]'是什么意思?'?

我试图抓住这三个声明之间的区别:我试图做一些测试,以找出这

char p[5]; 
char *p[5]; 
char (*p)[5]; 

,因为读的声明之类的东西的每一个指南并没有帮助我到目前为止。我写了这个小程序,它不工作(我试过其他种类使用第三申报的,我已经跑出去的选项):

#include <stdio.h>                
#include <string.h>                
#include <stdlib.h>                

int main(void) {                 
     char p1[5];                
     char *p2[5];                
     char (*p3)[5];               

     strcpy(p1, "dead");              

     p2[0] = (char *) malloc(5 * sizeof(char));        
     strcpy(p2[0], "beef");             

     p3[0] = (char *) malloc(5 * sizeof(char));        
     strcpy(p3[0], "char");             

     printf("p1 = %s\np2[0] = %s\np3[0] = %s\n", p1, p2[0], p3[0]);   

     return 0;                
} 

第一和第二的作品好吧,我也了解他们的工作。第三个声明的含义和使用它的正确方法是什么?

谢谢!

+0

解码声明是我和C++最不喜欢的部分。 –

回答

12

第三种是指针至5个字符数组,而第二是5的阵列指针为char。而第二个看起来像

________   _____________________ 
|0x7777| -------> | H | e | l | l | o | 
|______|   |_0_|_1_|_2_|_3_|_4_| 
    p   ^
        | 
        0x7777 

"abc" "def" "ghi" "jkl" "mno" 
    ^ ^ ^ ^ ^
    |  |  |  |  | 
____________________________________ 
|0x9999|0x7777|0x3333|0x2222|0x6666| 
|___0__|___1__|___2__|___3__|___4__| 
        p 

这是的情况下,了解指针和数组之间的区别是至关重要的一个

想象一下这样的。一个数组是一个对象,其大小是其每个元素的大小乘以计数,而指针仅仅是一个地址。

在第二种情况下,sizeof(p)将产生5 * the_size_of_a_pointer

在第三种情况下,sizeof(p)将产生the_size_of_a_pointer,这通常是48,具体取决于目标机器。

+9

的[顺时针螺旋规则(http://c-faq.com/decl/spiral.anderson.html)是当你用'C'搞乱知道一个方便的事情。 –

+0

我试图P3分配5个字符,并指着P3那些使用,它没有工作。它不像你说的那样工作......你介意发布一些示例代码还是更清晰的东西? – jpmelos

+0

在第三种情况下,sizeof(p3)不会产生您所说的内容,而是产生8,这是我机器中指针的大小。 – jpmelos

4

这是一个指向字符数组的指针。它在C FAQ中解释。将来,如果您不了解声明,请使用cdeclcdecl(1)

+0

非常感谢,您的C常见问题解答帮助我深刻理解了这个话题。 – jpmelos

3
char (*p3)[5]; 

实际上声明一个指针的5 char阵列。这意味着它应该指向一个指向数组5 char的指针。它不分配任何东西,只是一个指针,它应该指向5 char

所以,正确的使用方法是:

#include <stdio.h>                
#include <string.h>                
#include <stdlib.h>                

int main(void) {                 
     char p1[5];                
     char *p2[5];                
     char (*p3)[5];               

     strcpy(p1, "dead");              

     p2[0] = (char *) malloc(5 * sizeof(char));        
     strcpy(p2[0], "beef");             

     p3 = &p1;                

     printf("p1 = %s\np2[0] = %s\np3 = %s\n", p1, p2[0], *p3);    

     return 0;                
} 

如果你想访问使用P3来访问它是P1串的一个位置,你必须做(*p3)[2],例如。它将进入第三个位置。这是因为您首先必须将p3转换为p1(在执行位置算术之前的(*p3)解除引用),然后访问该地址的第三个位置(由解除引用的指针指向)。

+0

太棒了,你总结我的答案更好:-) –

4
char p[5];  // p is a 5-element array of char 
char *p[5];  // p is a 5-element array of pointer to char 
char (*p)[5]; // p is a pointer to a 5-element array of char 

C的声明语法围绕类型的内置的表达,而不是对象。这个想法是,声明的形式与它在代码中出现的表达形式相匹配。

在上面的例子中,我们正在处理数组。在第一种情况下,pchar的数组;访问特定的字符值,我们将简单地索引到阵列:

val = p[i]; 

类型表达p[i]的是char,因而p声明是char p[5]

在下一种情况下,p是指向char的指针数组;访问的值,我们索引到阵列和解除引用的结果:

val = *p[i]; 

后缀运算符等[]具有比一元运算符等*一个更高的优先级,因此,上述被分析为

val = *(p[i]); 

的表达式*p[i]的类型为char,因此p的声明为char *p[5]

在最后的情况下,p是指向字符数组,所以访问我们必须解引用数组指针char值,然后下标到结果:

val = (*p)[i]; 

由于[]具有较高的优先级高于一元*,我们必须使用括号将*p(与p[i]相对)进行明确分组。同样,表达(*p)[i]的类型是char,所以p声明是char (*p)[5]

编辑

指向数组的指针在以下上下文中显示:

  1. 你明确地服用N维数组的地址:

    int x[10]; 
    int (*px)[10] = &x; 
    
    注意的是,虽然表情x&x产生相同(数组的第一元素的地址),它们具有不同类型的int * vs int (*)[10])。

  2. 你动态分配的阵列型对象:

    int (*px)[10] = malloc(sizeof *px); 
    

  3. N维阵列表达 “衰变” 到的指针(N-1) - 尺寸数组:

    int x[10][20]; 
    foo(x); 
    ... 
    void foo(int (*px)[20]){...} 
    

+0

+1。非常好的解释!谢谢,真的很清楚如何思考声明! – jpmelos

+0

在你编辑的第一个上下文中,你说'x'的类型是int *,而'&x'的类型是int(*)[10]'。你的意思是'x'的类型是'int [10]',我猜? – jpmelos

+1

@jpmelos:既然它不是'sizeof'或'&'的操作数,'x'会衰减为'int *'。 –