494

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

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

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

4

13 回答 13

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

第三个和第一个一样。

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

于 2009-05-13T18:37:30.057 回答
270

按照 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 )
于 2009-05-13T18:44:59.733 回答
129

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

从变量开始,然后向右、向左、向右……以此类推。

int* arr1[8];

arr1是一个由 8 个指向整数的指针组成的数组。

int (*arr2)[8];

arr2是一个指向 8 个整数数组的指针(括号在左右两边)。

int *(arr3[8]);

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

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

于 2009-05-13T18:41:48.613 回答
27
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 
于 2011-03-02T08:03:18.593 回答
16

最后两个的答案也可以从 C 中的黄金法则中推导出来:

声明遵循使用。

int (*arr2)[8];

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

int *(arr3[8]);

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

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

float *(*x)(void )

当你取消引用时会发生什么x?你得到一个可以不带参数调用的函数。当你调用它时会发生什么?它将返回一个指向 a 的指针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 &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]

请注意,边框的值永远不会改变,因此编译器可以优化它。这与您最初可能想要使用的不同: const int (*border)[3]: 将边界声明为指向 3 个整数数组的指针,只要变量存在,该数组就不会改变值。但是,该指针可以随时指向任何其他此类数组。相反,我们希望参数具有这种行为(因为此函数不会更改任何这些整数)。声明遵循使用。

(ps:请随时改进此示例!)

于 2010-03-30T09:40:55.997 回答
5
typedef int (*PointerToIntArray)[];
typedef int *ArrayOfIntPointers[];
于 2010-08-14T17:51:34.160 回答
3

根据经验,右一元运算符(如[]()等)优先于左一元运算符。因此,int *(*ptr)()[];将是一个指向函数的指针,该函数返回指向 int 的指针数组(离开括号后尽快获取正确的运算符)

于 2014-09-19T13:34:06.017 回答
2

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

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

ptr是指向“向右移动..它的”)的指针现在向左移动它的一个“(”出来向右移动“()”所以“指向一个不带参数的函数”向左“并返回一个指针”去向右“数组”向左“整数”

于 2012-07-09T15:04:34.017 回答
2

以下是我的解释:

int *something[n];

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

因此,在这里我们将应用[]before *,使语句等效于:

int *(something[i]);

注意声明的意义:int num手段num是一个intint *ptrint (*ptr)手段,(价值在ptr)是一个int,它使ptr一个指针指向int

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

在第二个中,

int (*something)[n];

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

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

因此,替换somethingElse(*something),我们得到*(*something + i),根据声明,它是一个整数。所以,(*something)给我们一个数组,它相当于(pointer to an array)

于 2015-10-11T18:52:17.780 回答
2

这是一个有趣的网站,它解释了如何在 C 中读取复杂类型: http ://www.unixwiz.net/techtips/reading-cdecl.html

于 2018-08-22T19:51:14.243 回答
0

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

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

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

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

于 2016-10-12T11:46:19.940 回答
0
int *arr1[5]

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

int (*arr2)[5]

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

于 2020-05-31T03:17:14.210 回答
-9

在指向整数的指针中,如果指针递增,则它进入下一个整数。

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

于 2013-03-31T14:41:58.040 回答