提问



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


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


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

最佳参考


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


第三个与第一个相同。


一般规则是运算符优先级。随着函数指针的出现,它会变得更加复杂。[30]

其它参考1


按照K& R的建议使用cdecl程序。[31]




$ 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 )

其它参考2


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


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


int* arr1[8];


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


int (*arr2)[8];


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


int *(arr3[8]);


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


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

其它参考3


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 

其它参考4


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



??声明如下使用。



int (*arr2)[8];


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


int *(arr3[8]);


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


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


float *(*x)(void )


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


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


编辑:示例


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


#include 
#include 
#include 

#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]


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


(p.s。:随意改进这个样本!)

其它参考5


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

其它参考6


我想我们可以使用简单的规则..


example int * (*ptr)()[];
start from ptr 


ptr是指向
走向正确..现在离开它的(
出来右边()所以
到一个不带参数的函数向左并返回指针向右
一个数组左转的整数

其它参考7


根据经验,正确的一元运算符(如[]()等)优先于左运算符。所以,int *(*ptr)()[];将是一个指向函数的指针,该函数返回指向int的指针数组(当你离开括号时,尽快得到正确的运算符)

其它参考8


这就是我的解释:


int *something[n];



??注意优先级:数组下标运算符([[]])的优先级高于
??解除引用运算符(*)。



所以,在这里我们将在*之前应用[[]],使语句等效于:


int *(something[i]);



??关于声明如何有意义的说明:int num表示(num)是(int),int *ptrint (*ptr)表示,(ptr处的值)是
??一个(int),它使ptr成为一个int的指针。



这可以读作,((某物的第i个索引处的值))是一个整数。所以,(某事物的第i个索引处的值)是一个(整数指针),这使得某事物成为整数指针的数组。


在第二个,


int (*something)[n];


要理解这个陈述,你必须熟悉这个事实:



??注意数组的指针表示:somethingElse [[i]]相当于*(somethingElse + i)



所以,用(* something)替换somethingElse,得到*(* something + i),这是一个声明的整数。所以,(* something)给了我们一个数组,它使得某些东西等同于(指向数组的指针)。

其它参考9


我想第二个声明让许多人感到困惑。这是理解它的简单方法。


让我们有一个整数数组,即int B[8]


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


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

其它参考10


在指向整数的指针中,如果指针递增,则它将转到下一个整数。


在指针数组中,如果指针递增,它将跳转到下一个数组