指向数组/指针消除歧义数组的C指针

以下声明有什么区别:

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 

第三个和第一个一样。

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

按照K&R的build议使用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 ) 

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

从variables开始,然后向右,向左,向右……等等。

 int* arr1[8]; 

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

 int (*arr2)[8]; 

arr2是一个指针(括号左右),由8个整数组成。

 int *(arr3[8]); 

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 

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

声明如下使用。

int (*arr2)[8];

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

int *(arr3[8]);

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

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

float *(*x)(void )

当你解除引用x时会发生什么? 你得到一个函数,你可以调用没有参数。 当你打电话时会发生什么? 它会返回一个指向浮动的指针。

但是,运算符优先级总是非常棘手。 但是,使用括号实际上也可能会令人困惑,因为声明会随之使用。 至less对我来说,arr2直观地看起来像是一个8个指针的数组,但实际上是相反的。 只需要一些习惯。 足够的理由总是添加评论这些声明,如果你问我:)

编辑:例如

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

 #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个整数数组的指针,只要该variables存在就不会改变数值。 但是,该指针可能随时指向任何其他此类数组。 我们需要这种参数的行为,而不是(因为这个函数不会改变任何整数)。 声明如下使用。

(ps:随意改进这个样本!)

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

作为一个经验法则,正确的一元运算符(比如[]()等)优先于左边的运算符。 所以, int *(*ptr)()[]; 会是一个指向一个函数的指针,该函数返回一个指向int的指针数组(当你离开括号的时候尽可能快地得到正确的运算符)

以下是我的解释:

 int *something[n]; 

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

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

 int *(something[i]); 

注意如何声明是有道理的: int num (int)是指int(int), int *ptr或者int (*ptr)意思是,(ptr的值)是一个(int),这使ptr成为int的指针。

这可以理解为,(某物的第i个索引值)是一个整数。 所以,(在某物的第i个索引处的值)是一个(整数指针),它使某个数组成为整数指针。

在第二个,

 int (*something)[n]; 

为了使这个陈述有意义,你必须熟悉这个事实:

注意数组的指针表示:somethingElse [i]等价于*(somethingElse + i)

所以,用(* something)replaceelse else,我们得到*(* something + i),这是一个整数作为每个声明。 所以,(* something)给了我们一个数组,这使得一些东西等价于(指向数组的指针)。

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

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

ptr是一个指向”right rightits“的指针)”现在向左走一个“(”out out go right“()”so“到不带任何参数的函数”向左走“,并返回一个指针”向右“到数组”向左“整数”

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

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

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

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

在指针指向一个整数,如果指针递增,那么它将转到下一个整数。

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