。
int const * p6;
和p5
等价。
int * const p7;
《C++ Primer》称其为底层const,即指针本身为常量,其所指数据可以修改,但指针本身不可以替换,例:
p5 = NULL; // 错误!
*p5 = 5; // 正确!
const int * const p8;
包含了顶层与底层const,这样所指和数据与指针本身都不可以修改。
钻石(答对6题升至该段位,正确率75%)
请用文字描述下列指针、函数、函数指针的具体类型:
int (*pfunc1)(int);
int (*pfunc2[10])(int);
int (*(*pfunc3)[10])(int);
int func9(int (*pf)(int, int), int);
const int ** p9;
int * const * p10;
int ** const p11;
int * const * const p12;
实用性正在逐步降低中...
钻石题解
int (*pfunc1)(int);
答案:pfunc1是 函数(形参为int, 返回值为int)的指针
,符号化描述即int(*)(int)
int (*pfunc2[10])(int);
f2先与[10]结合,说明f2是一个数组,把f2[10]
拿开,则元素类型为int(*)(int)
。答案:pfunc2是 函数(形参为int, 返回值为int)的指针数组(10元素)
int (*(*pfunc3)[10])(int);
函数没法作为数组的元素,但函数指针可以。经过前面的磨难,应该可以看出来这是一个指向数组的指针,数组的元素是函数指针。 答案:pfunc3是 指向[函数(形参为int, 返回值为int)的指针数组(10元素)]的指针
int func9(int (*pf)(int, int), int);
一个函数里面需要接受一个函数指针作为形参,通常将以这种方式传递的函数叫做回调函数。 答案:func9是 函数(形参为{函数(形参为{int, int}, 返回值为int)的指针, int}, 返回值为int)
const int ** p9;
具体可以参考下面的示范:
p9 = NULL; // 正确!
*p9 = NULL; // 正确!
**p9 = 5; // 错误!
int * const * p10;
具体可以参考下面的示范:
p10 = NULL; // 正确!
*p10 = NULL; // 错误!
**p10 = 5; // 正确!
int ** const p11;
具体可以参考下面的示范:
p11 = NULL; // 错误!
*p11 = NULL; // 正确!
**p11 = 5; // 正确!
int * const * const p12;
具体可以参考下面的示范:
p12 = NULL; // 错误!
*p12 = NULL; // 错误!
**p12 = 5; // 正确!
大师(答对5题升至该段位,正确率62.5%)
如果你有幸能够坚持到这一步,或者已经放弃治疗想看看后续内容,那么接下来你将要面对的可能是各种匪夷所思的、恶魔般指针,这些奇奇怪怪的写法甚至能够通过编译,简直就是恶魔。
现在允许你使用一种伪lambda的描述方式,来对函数或函数指针进行拆解。示例如下:
int (*pfunc1)(int); // (*pfunc1)(int)->int
int f1(int); // f1(int)->int
箭头所指的为返回值类型。
那么。。。祝你好运,请用伪lambda描述方式拆解下面函数和函数指针:
int (*pfunc4)(int*());
int (*func10(int[]))[10];
int (*func11(int[], int))(int, int);
int (*(*pfunc5)(int))(int[10], int);
int (*(*pfunc6)(int[10]))[10];
int (*(*pfunc7[10])(int[10]))[10];
int (*pfunc8(int(*(int(*())))));
int (*(*(*pfunc9)[10])(int[], int))(int, int);
大师题解
int (*pfunc4)(int*());
基本上都倒在了形参的int*()
这种什么鬼写法是吧,不然这怎么能叫恶魔指针呢,哈哈哈... 反正在这篇文章里,就让可读性就统统见鬼去吧!如果你有Visual Studio的话,把这份声明粘贴到VS,然后光标放在上面,你会发现实际上形参的int*()
会被解读为int*(*)()
。 答案:(*pfunc4)((*pf)()->int*)->int
int (*func10(int[]))[10];
这个在《C++ Primer》上似曾相识,如果你之前在里面做过类似的题目话,就会知道这个函数,返回的是一个指向数组的指针。你可以将该函数类似于函数调用的部分func10(int*)
拿掉,剩下的就是返回值类型int(*)[10]
了。 答案:func10(int*)->int(*)[10]
int (*func11(int[], int))(int, int);
函数返回了一个函数指针。 答案:func11(int*, int)->int(*)(int, int)
int (*(*pfunc5)(int))(int[10], int);
函数指针,所指函数返回了一个函数指针。 答案:(*pfunc5)(int)->((*)(int*, int)->int)
int (*(*pfunc6)(int[10]))[10];
答案:(*pfunc6)(int*)->int(*)[10]
int (*(*pfunc7[10])(int[10]))[10];
答案:(*pfunc7[10])(int*)->int(*)[10]
int (*pfunc8(int(*(int(*())))));
这又是什么鬼玩意???我们先根据现有的经验来进行层层解耦。首先像这种int(*())
的外层括号是可以去掉的,只是一个误导,然后就变成了int*()
的鬼形式,然后编译器会认为它是int*(*)()
。那答案也就呼之欲出了。 答案:(*pfunc8)((*pf1)((*pf2)()->int*)->int*)->int*
int (*(*(*pfunc9)[10])(int[], int))(int, int);
答案:((*pfunc9)[10])(int*, int)->((*pf)(int, int)->int)
结语
如果你能完成上面的所有题目,那么你将获得隐藏称号:人形编译器。
这里的指针几乎就是你这辈子能见到的所有指针了。至于其余变种指针,基本上都围绕这上面提到的方法构成。毕竟我们还没加上C++的引用呢...
欢迎在评论里面留下自己的段位证明(请诚实对待)。坑挖的太大也难免会有一些错漏,欢迎指正。
现在,我们都是恶魔了