关于理解复杂指针声明及定义的看法。
对于一个指针变量来说,最重要的是它指向的类型,它决定了编译器对它指向对象的理解,如:int i; int* p = &i;p现在指向一个int大小的内存空间,并且这个空间是int变量i的空间,那么我们就可以通过p来间接的读取或修改i的值,如:
int j = *p; *p = 1;*p是规定的语法,也可以说在这里*p就与i等价。这是因为编译器已经拥有了足够的信息,它知道p指向的空间大小(一个int的大小)及对这块空间里值的解释(补码)。
再看一看这段代码:
程序代码:
struct Book { char name[31]; char author[31]; char isbn10[11]; char isbn13[14]; char language[100]; char publisher[100]; }; struct Book thinking_in_cpp; struct Book* p = &thinking_in_cpp; strcpy(p->name, "Thinking in C++"); strcpy(p->author, "Bruce Eckel"); strcpy(p->isbn10, "0139798099"); strcpy(p->isbn13, "9780139798092"); ... printf("Book name: %s\n", p->name); printf("Book author: %s\n", p->author); printf("Book isbn-10: %s\n", p->isbn10); printf("Book isbn-13: %s\n", p->isbn13); ...可以看到,这里的p指向的并不是基本类型,它指向的是我们自定义的结构类型Book,当然编译器在struct Book* p = &thinking_in_cpp;这段代码之后就已经了解到了足够的信息,编译器知道p指向的空间有多大(使该指针+1或-1会增加或减少sizeof(struct Book)),还知道p指向的是一个结构体变量,它有6个成员,并且还可以使用->操作符来引用该结构变量的成员。
好了,这说明指针需要的不仅仅是地址,而更重要的是它指向的类型(编译器可以允许使用的操作符及对其值的解释)。
下面有一些变量的定义:
程序代码:
int** p; // p指向一个int*的变量,它是指向指针的指针。 void(*p)(void); // p指向一个函数,该函数不接收参数,也不返回值。 int(*p)(int,int); // p指向一个函数,该函数接收两个int参数,并且返回一个int。 void(**p)(void); // p指向一个函数的指针,它指向的指针指向的函数不接收参数也不返回值,它是指向指针的指针。 void(*p[10])(void); // p是一个数组,每个元素都是一个指针,并且每个元素都指向一个函数,这个函数不接收参数也不返回值。 void(*(*p)[10])(void); // p是一个指针,它指向一个有10个元素的数组,这个数组的每个元素都是一个指针,并且每个元素都指向一个不接收参数也不返回值的函数。 int(*(*p)(void))[10]; // p是一个指针,它指向一个函数,这个函数不接收参数,并且返回一个指针,这个指针指向10个int的数组。 void(*(*p)(void))(void); // p是一个指针,它指向一个函数,这个函数不接收参数,并且返回一个指针,这个指针也指向一个函数,这个函数不接收参数,也不返回值。对于void (*p)(void);这是函数指针的语法,*p两边的括号是不能少的,比如:void *p(void);p是一个函数,这个函数不接收参数,返回一个void*指针,并且这是一个函数的声明。加上了括号就使编译器先看到了*p(这说明()能改变声明及定义时的优先级规则,否则编译器就是从右往左来识别变量的类型),这样p就是一个指针,然后右边发现了(void),这就可以表示p是一个函数指针了,因为遇到了一对括号,并且这个括号里有东西,括号里面是void,则说明指向的这个函数不接收参数,最后在左边发现了void,说明指向的这个函数不返回值。
在声明或定义时,编译器是从标识符开始的,先看标识符的右边,然后左边,然后是上次右边的右边,然后是上次左边的左边。。。以此类推。那么我们来看看这个:
int(*p)(int,int);先从标示符开始,发现*p被括号包起来了,所以p先与*结合,p就变成了一个指针(说明()改变了优先级),然后再看右边发现了(int,int)这说明p是一个函数指针,指向的这个函数接收两个int参数,最后再看左边,发现了int,说明这个函数返回一个int。
看看下面的一些解释:
void(**p)(void);先从标示符开始,很明显**p被括起来了,那么p就是一个指针并且它指向一个指针(指针的指针),然后在右边发现了(void)这说明p指向的指针是一个函数指针,这个函数不接收参数,最后在左边发现void,说明p指向的指针指向的函数不返回值。所以p就是一个指向函数指针的指针。
void(*p[10])(void);先从标示符开始,*p[10]被括起来了,那么先看p的右边,发现了[10],说明p是一个数组并且这个数组有10个元素,然后在左边发现了*,说明这个数组的每个元素都是一个指针,然后再看右边,发现了(void),说明这个数组的每个元素都是一个函数指针并且这个函数不接收参数,最后在左边发现了void,说明这个函数不返回值。所以p实际上是一个函数指针的数组。
void(*(*p)[10])(void);先从标示符开始,*p被括起来了,那么p就与*结合,所以p就是一个指针,然后在右边发现了[10],说明p指向一个有10个元素的数组,然后在左边发现了*,说明这个数组的每个元素都是指针,然后再右边发现了(void),说明这个数组的每个元素都指向一个函数并且这个函数不接收参数,最后在左边发现了void,说明这个函数不返回值。所以p是一个有10个函数指针数组的指针。
int(*(*p)(void))[10];先从标示符开始,*p被括起来了,那么p就与*结合,所以p就是一个指针,然后在右边发现了(void),说明p是一个函数指针并且这个函数不接收参数,然后再左边发现了*,说明p指向的这个函数返回一个指针,然后再右边发现了[10],说明这个函数返回的指针指向一个有10个元素的数组,最后在左边发现了int说明这个数组的每个元素都是int。所以p是一个函数指针,并且这个函数返回的是一个指向有10个元素的数组的指针。
void(*(*p)(void))(void);依然先从标示符开始,*p被括起来了,那么p就与*结合,所以p就是一个指针,然后在右边发现了(void),说明p是一个函数指针并且这个函数不接收参数,然后再左边发现了*,说明这个函数返回一个指针,然后在右边又发现了(void)说明返回的这个指针是一个函数指针并且这个函数不接收参数,最后在左边发现了void,说明返回的函数指针指向的函数没有返回值。所以p就是一个函数指针,并且指向的这个函数也返回一个函数指针。
最后请大家来理解一下,下面这句定义(回答正确的童鞋都有分):
int*(*(*(*p)[10])(int))(int,int);
[ 本帖最后由 lz1091914999 于 2013-1-10 11:54 编辑 ]