最后两个的答案也可以从C中的黄金法则中推导出来:
声明遵循使用。
int (*arr2)[8];
如果取消引用 arr2 会发生什么?你得到一个由 8 个整数组成的数组。
int *(arr3[8]);
如果你从arr3 中获取一个元素会发生什么?你得到一个指向整数的指针。
这在处理指向函数的指针时也很有帮助。以 sigjuice 为例:
float *(*x)(void )
当您取消引用 x 时会发生什么?你得到一个可以不带参数调用的函数。当你调用它时会发生什么?它将返回一个指向float 的指针。
不过,运算符优先级总是很棘手。然而,使用括号实际上也可能令人困惑,因为声明遵循使用。至少,对我来说,直观上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 < 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]
请注意,边框的值永远不会改变,因此编译器可以对其进行优化。这与您最初可能想要使用的不同:const int (*border)[3]: 将边界声明为指向 3 个整数数组的指针,只要变量存在,该数组就不会改变值。但是,该指针可以随时指向任何其他此类数组。相反,我们希望参数具有这种行为(因为此函数不会更改任何这些整数)。声明后使用。
(ps:请随时改进此示例!)