以下声明的区别是什么:

int* arr1[8];
int (*arr2)[8];
int *(arr3[8]);

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


当前回答

我想第二个宣言让很多人感到困惑。这里有一个简单的理解方法。

假设有一个整数数组,即int B[8]。

让我们还有一个指向B的变量a。现在,a处的值是B,即(* a) == B。因此a指向一个整数数组。在你的问题中,arr类似于A。

类似地,在int* (*C)[8]中,C是一个指向整数指针数组的指针。

其他回答

typedef int (*PointerToIntArray)[];
typedef int *ArrayOfIntPointers[];

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

使用后声明。

int (* arr2) [8];

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

int * (arr3 [8]);

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

这也有助于处理指向函数的指针。以sigjuice为例:

Float *(*x)(void)

解引用x会发生什么?你得到一个不带参数调用的函数。当你调用它时会发生什么?它将返回一个指向浮点数的指针。

不过运算符优先级总是很棘手。然而,使用圆括号实际上也会令人困惑,因为声明紧随使用之后。至少,对我来说,直觉上arr2看起来像一个8个指向int型的指针的数组,但实际上是相反的。只是需要一些时间去适应。如果你问我,有足够的理由总是在这些声明中添加注释:)

编辑:示例

顺便说一下,我偶然发现了以下情况:一个函数有一个静态矩阵,并使用指针算术来查看行指针是否出界。例子:

#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 &lt; 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;
}

输出:

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

Note that the value of border never changes, so the compiler can optimize that away. This is different from what you might initially want to use: const int (*border)[3]: that declares border as a pointer to an array of 3 integers that will not change value as long as the variable exists. However, that pointer may be pointed to any other such array at any time. We want that kind of behaviour for the argument, instead (because this function does not change any of those integers). Declaration follows use.

(附注:请随意改进此示例!)

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

第三个和第一个一样。

一般规则是运算符优先级。当函数指针出现时,它甚至会变得更加复杂。

int *arr1[5]

在这个声明中,arr1是一个包含5个指向整数的指针的数组。 原因:方括号的优先级高于*(取消引用操作符)。 在这种类型中,行数是固定的(这里是5),但列数是可变的。

int (*arr2)[5]

在这个声明中,arr2是一个指向5个元素的整数数组的指针。 原因:这里,()括号的优先级高于[]。 在这种类型中,行数是可变的,但列数是固定的(这里是5)。

我不知道它是否有一个正式的名字,但我称之为左右事物(TM)。

从变量开始,然后向右、向左、向右……等等。

int* arr1[8];

Arr1是一个包含8个指向整数的指针的数组。

int (*arr2)[8];

Arr2是一个指向8个整数数组的指针(括号块左右)。

int *(arr3[8]);

Arr3是一个包含8个指向整数的指针的数组。

这将帮助您处理复杂的声明。