以下声明的区别是什么:
int* arr1[8];
int (*arr2)[8];
int *(arr3[8]);
理解更复杂的声明的一般规则是什么?
以下声明的区别是什么:
int* arr1[8];
int (*arr2)[8];
int *(arr3[8]);
理解更复杂的声明的一般规则是什么?
当前回答
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
其他回答
按照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>
反之亦然。
cdecl> declare x as pointer to function(void) returning pointer to float
float *(*x)(void )
在指向整数的指针中,如果指针是递增的,那么它将移动到下一个整数。
在指针数组中,如果指针增加,则跳转到下一个数组
我想第二个宣言让很多人感到困惑。这里有一个简单的理解方法。
假设有一个整数数组,即int B[8]。
让我们还有一个指向B的变量a。现在,a处的值是B,即(* a) == B。因此a指向一个整数数组。在你的问题中,arr类似于A。
类似地,在int* (*C)[8]中,C是一个指向整数指针数组的指针。
以下是我的解释:
int *something[n];
优先级注意:数组下标操作符([])优先级高于 解引用运算符(*)。
因此,这里我们将在*之前应用[],使语句等价于:
int *(something[i]);
注意声明的意义:int num表示num是int, int *ptr或int (*ptr)表示,(值在ptr)是 一个int型,使PTR成为一个指向int型的指针。
这可以理解为,(值(值在第i个索引的东西))是一个整数。因此,(value在something的第i个索引处)是一个(整型指针),这使得something成为一个整型指针数组。
在第二个例子中,
int (*something)[n];
要理解这句话,你必须熟悉这个事实:
数组指针表示的注意事项:somethingElse[i]等价于*(somethingElse + i)
因此,用(*something)替换somethingElse,我们得到*(*something + i),根据声明,这是一个整数。所以,(*something)给了我们一个数组,这使得something等价于(指针指向数组)。
最后两个的答案也可以从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 < 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.
(附注:请随意改进此示例!)