指向数组/指针消除歧义数组的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是指向整数指针数组的指针。
在指针指向一个整数,如果指针递增,那么它将转到下一个整数。
在指针数组中,如果指针递增,则跳转到下一个数组