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

时间:2011-06-24 12:12:56

标签: c pointers declaration

我正在努力理解这三个声明之间的差异:

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

第一个和第二个工作没问题,我明白他们做了什么。第三个声明的含义是什么,使用它的正确方法是什么?

谢谢!

4 个答案:

答案 0 :(得分:13)

第三个是指向5个字符数组的指针,而第二个是指向char的5个指针的数组

想象一下:

________          _____________________
|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,具体取决于目标计算机。

答案 1 :(得分:4)

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

答案 2 :(得分: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数组的指针,因此要访问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会产生相同的 value (数组的第一个元素的地址),它们具有不同的类型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]){...}
    

答案 3 :(得分:3)

char (*p3)[5];

实际上声明了一个指向5 char数组的指针。这意味着它应该指向一个指向5 char数组的指针。它不会分配5个任何东西,只是指针,它应该指向指向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)解除引用),然后访问该地址的第三个位置(由解除引用的指针指向)。