解释int(*a)[3]

fot*_*ton 23 c c++ arrays types pointers

当使用C中的数组和指针时,人们会很快发现它们并不等同,尽管乍一看似乎是这样.我知道L值和R值的差异.不过,最近我试图找出一个可以与二维数组结合使用的指针类型,即

int foo[2][3];
int (*a)[3] = foo;
Run Code Online (Sandbox Code Playgroud)

不过,我只是不能找出编译器如何"理解"的类型定义,尽管常规运算符优先级规则*[].相反,如果我使用typedef,问题会变得非常简单:

int foo[2][3];
typedef int my_t[3];
my_t *a = foo;
Run Code Online (Sandbox Code Playgroud)

在底线,有人可以回答我关于int (*a)[3]编译器如何读取该术语的问题吗?int a[3]很简单,int *a[3]也很简单.但那么,为什么不int *(a[3])呢?

编辑:当然,而不是"类型转换"我的意思是"typedef"(它只是一个错字).

cod*_*ict 53

每次你对复杂的声明都有疑问时,你可以在Unix系统中使用cdecl工具:

[/tmp]$ cdecl
Type `help' or `?' for help
cdecl> explain int (*a)[10];
declare a as pointer to array 10 of int
Run Code Online (Sandbox Code Playgroud)

编辑:

此处还提供此工具的在线版本.

感谢Tiberiu Ana和gf

  • +1告诉我一个我不知道存在的工具. (2认同)

Geo*_*che 22

它声明了一个指向3 ints 数组的指针.

括号是必要的,因为下面声明了一个由3个指针组成的数组int:

int* a[3];
Run Code Online (Sandbox Code Playgroud)

使用时可获得更好的可读性typedef:

typedef int threeInts[3];
threeInts* pointerToThreeInts;
Run Code Online (Sandbox Code Playgroud)


Alo*_*hal 19

首先,你的意思是"typedef"而非"类型转换".

在C中,指向type的指针T可以指向类型为的对象T:

int *pi;
int i;
pi = &i;
Run Code Online (Sandbox Code Playgroud)

以上内容很容易理解.现在,让我们让它变得更复杂一些.你似乎知道数组和指针之间的区别(也就是说,你知道数组不是指针,它们有时会表现得像).所以,你应该能够理解:

int a[3];
int *pa = a;
Run Code Online (Sandbox Code Playgroud)

但为了完整起见:在赋值中,名称a相当于&a[0],即指向数组第一个元素的指针a.如果您不确定其工作原理和原因,那么有很多答案可以解释数组的名称何时"衰减"到指针以及何时不是:

我确信在SO上还有更多这样的问题和答案,我刚刚提到了一些我从搜索中找到的问题.

回到主题:当我们有:

int foo[2][4];
Run Code Online (Sandbox Code Playgroud)

foo的类型是"阵列[2]阵列[3]int".这意味着它foo[0]是一个3 ints foo[1]的数组,并且是一个3 ints 的数组.

现在让我们说我们想要声明一个指针,我们想要指定它foo[0].也就是说,我们想做:

/* declare p somehow */
p = foo[0];
Run Code Online (Sandbox Code Playgroud)

以上int *pa = a;在线的形式上没有区别,因为它们的类型afoo[0]相同.所以,我们需要int *p;作为我们的声明p.

现在,要记住关于数组的主要事情是关于数组名称衰减到指向其第一个元素的指针的"规则"仅适用一次.如果你有一个数组的数组,那么在值上下文中,数组的名称不会衰减为"指向指针的指针"类型,而是衰减到"指向数组的指针".回到foo:

/* What should be the type of q? */
q = foo;
Run Code Online (Sandbox Code Playgroud)

foo上面的名称是指向第一个元素的指针foo,即我们可以将上面的内容写成:

q = &foo[0];
Run Code Online (Sandbox Code Playgroud)

类型foo[0]是"数组[3]int".因此,我们需要q将一个指针"数组[3]int":

int (*q)[3];
Run Code Online (Sandbox Code Playgroud)

q需要括号因为[]绑定比*C 更紧密,所以int *q[3]声明q为指针数组,我们想要一个指向数组的指针. int *(q[3])是,从上面,等同于int *q[3],即3个指针的数组int.

希望有所帮助.您还应该阅读C for smarties:数组和指针,以获得关于此主题的非常好的教程.

关于阅读声明一般:你从"里里外外"读取它们,从"变量"的名称开始(如果有的话).你尽可能地离开,除非[]右边有一个,你总是尊重括号. cdecl应该能够在一定程度上帮助你:

$ cdecl
cdecl> declare p as  pointer to array 3 of int
int (*p)[3]
cdecl> explain int (*p)[3]
declare p as pointer to array 3 of int
Run Code Online (Sandbox Code Playgroud)

阅读

int (*a)[3];

      a            # "a is"
    (* )           # parentheses, so precedence changes.
                   # "a pointer to"
        [3]        # "an array [3] of"
int        ;       # "int".
Run Code Online (Sandbox Code Playgroud)

对于

int *a[3];

     a             # "a is"
      [3]          # "an array [3] of"
    *              # can't go right, so go left.
                   # "pointer to"
int      ;         # "int".
Run Code Online (Sandbox Code Playgroud)

对于

char *(*(*a[])())()

          a         # "a is"
           []       # "an array of"
         *          # "pointer to"
        (    )()    # "function taking unspecified number of parameters"
      (*        )   # "and returning a pointer to"
                 () # "function"
char *              # "returning pointer to char"
Run Code Online (Sandbox Code Playgroud)

(来自c-faq问题1.21的例子.实际上,如果你正在阅读这么复杂的声明,那么代码就会出现严重问题!)


Tib*_*Ana 6

它的意思是

声明一个指向int数组3的指针

请参阅cdecl以供将来参考.