指向数组/指针数组的C指针消歧

Geo*_*rge 451 c arrays pointers variable-declaration

以下声明之间有什么区别:

int* arr1[8];
int (*arr2)[8];
int *(arr3[8]);
Run Code Online (Sandbox Code Playgroud)

理解更复杂的声明的一般规则是什么?

Meh*_*ari 426

int* arr[8]; // An array of int pointers.
int (*arr)[8]; // A pointer to an array of integers
Run Code Online (Sandbox Code Playgroud)

第三个与第一个相同.

一般规则是运算符优先级.随着函数指针的出现,它可能变得更加复杂.

  • 不.int*arr [8]:分配8x4字节*total*,每个指针4个字节.int(*arr)[8]是正确的,4个字节. (10认同)
  • 因此,对于32位系统:int*arr [8];/*为每个指针分配8x4字节*/int(*arr)[8];/*分配了4个字节,只有一个指针*/ (4认同)
  • 第一个与最后一个相同的原因是它总是允许在括号中包装括号.P [N]是一个数组声明符.P(....)是函数声明符,*P是指针声明符.所以下面的所有内容都是相同的,没有任何括号(除了函数之一'"()":int((*p))); void((g(void))); int*(a [1]); void(*(p())). (4认同)
  • 我应该重新阅读我写的内容.每个指针我的意思是4.谢谢您的帮助! (2认同)
  • 你的解释做得很好。有关运算符优先级和结合性的深入参考,请参阅 Brian Kernighan 和 Dennis Ritchie 的 The C Programming Language(ANSI C 第二版)的第 53 页。运算符 `( ) [ ] ` 从左到右关联并且具有比 `*` 更高的优先级,因此将 `int* arr[8]` 读作大小为 8 的数组,其中每个元素都指向一个 int 和 `int (*arr) [8]` 作为指向大小为 8 的数组的指针,该数组包含整数 (2认同)

sig*_*ice 261

按照K&R的建议使用cdecl程序.

$ cdecl
Type `help' or `?' for help
cdecl> explain int* arr1[8];
declare arr1 as array 8 of pointer to int
cdecl> explain int (*arr2)[8]
declare arr2 as pointer to array 8 of int
cdecl> explain int *(arr3[8])
declare arr3 as array 8 of pointer to int
cdecl>
Run Code Online (Sandbox Code Playgroud)

它也是另一种方式.

cdecl> declare x as pointer to function(void) returning pointer to float
float *(*x)(void )
Run Code Online (Sandbox Code Playgroud)

  • @ankii 你可以从 Homebrew 安装(也许还有 MacPorts?)。如果这些不符合您的口味,那么通过 cdecl.org 右上角的 Github 链接构建您自己的版本是微不足道的(我刚刚在 macOS Mojave 上构建了它)。然后只需将 cdecl 二进制文件复制到您的 PATH 即可。我推荐 $PATH/bin,因为不需要 root 参与如此简单的事情。 (2认同)

GMa*_*ckG 124

我不知道它是否有正式名称,但我称之为Right-Left Thingy(TM).

从变量开始,然后向右,向左,向右......等等.

int* arr1[8];
Run Code Online (Sandbox Code Playgroud)

arr1是一个包含8个整数指针的数组.

int (*arr2)[8];
Run Code Online (Sandbox Code Playgroud)

arr2是指向8个整数的数组的指针(括号内的左右).

int *(arr3[8]);
Run Code Online (Sandbox Code Playgroud)

arr3是一个由8个整数指针组成的数组.

这应该可以帮助您完成复杂的声明.

  • 我听说它的名字是"螺旋规则",可以在[这里](http://www.c-faq.com/decl/spiral.anderson.html)找到. (19认同)
  • @InkBlend:螺旋规则与[右 - 左规则](http://ieng9.ucsd.edu/~cs30x/rt_lt.rule.html)不同.在[int*a [] [10]的情况下[前者失败](http://stackoverflow.com/questions/16260417/the-spiral-rule-about-declarations-when-is-it-in-error) `而后者成功. (6认同)

小智 25

int *a[4]; // Array of 4 pointers to int

int (*a)[4]; //a is a pointer to an integer array of size 4

int (*a[8])[5]; //a is an array of pointers to integer array of size 5 
Run Code Online (Sandbox Code Playgroud)

  • @Rushil:不,最后一个下标(`[5]`)代表内部维度.这意味着`(*a [8])`是第一个维度,因此是数组的外部表示.`a`**中每个元素指向**的是一个大小为5的不同整数数组. (2认同)

小智 15

最后两个答案也可以从C中的黄金法则中扣除:

声明如下使用.

int (*arr2)[8];

如果你取消引用arr2会发生什么?你得到一个8个整数的数组.

int *(arr3[8]);

如果你从arr3中获取一个元素会怎么样?你得到一个指向整数的指针.

这在处理函数指针时也很有用.以sigjuice为例:

float *(*x)(void )

当你取消引用x时会发生什么?你得到一个你可以不带参数调用的函数.你打电话后会发生什么?它将返回一个指向float的指针.

但是,运算符优先级总是很棘手.但是,使用括号实际上也可能会造成混淆,因为声明随后使用.至少对我来说,直观地说,arr2看起来像是一个由8个指针组成的数组,但它实际上是另一种方式.只需要一些习惯.如果你问我:)总是足以为这些声明添加注释的原因:)

编辑:示例

顺便说一句,我偶然发现了以下情况:一个具有静态矩阵的函数,它使用指针算法来查看行指针是否超出范围.例:

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

#define NUM_ELEM(ar) (sizeof(ar) / sizeof((ar)[0]))

int *
put_off(const int newrow[2])
{
    static int mymatrix[3][2];
    static int (*rowp)[2] = mymatrix;
    int (* const border)[] = mymatrix + NUM_ELEM(mymatrix);

    memcpy(rowp, newrow, sizeof(*rowp));
    rowp += 1;
    if (rowp == border) {
        rowp = mymatrix;
    }

    return *rowp;
}

int
main(int argc, char *argv[])
{
    int i = 0;
    int row[2] = {0, 1};
    int *rout;

    for (i = 0; i < 6; i++) {
        row[0] = i;
        row[1] += i;
        rout = put_off(row);
        printf("%d (%p): [%d, %d]\n", i, (void *) rout, rout[0], rout[1]);
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

0 (0x804a02c): [0, 0]
1 (0x804a034): [0, 0]
2 (0x804a024): [0, 1]
3 (0x804a02c): [1, 2]
4 (0x804a034): [2, 4]
5 (0x804a024): [3, 7]

请注意,border的值永远不会改变,因此编译器可以对其进行优化.这与您最初可能要使用的内容不同const int (*border)[3]::它将border声明为指向3个整数数组的指针,只要该变量存在,该数组就不会更改值.但是,该指针可以在任何时候指向任何其他这样的数组.我们想要参数的那种行为(因为这个函数不会改变任何整数).声明如下使用.

(ps:随意改进这个样本!)


小智 5

typedef int (*PointerToIntArray)[];
typedef int *ArrayOfIntPointers[];
Run Code Online (Sandbox Code Playgroud)