一封来自恶魔的挑战邀请函,那些你见过或者没见过的C语言指针都在这里了 (2)

int func4(int *arr[10]); 这道题也好说了,即arr实际上是int **类型,而作为开发者的你,需要保证传入一个元素个数大于等于10的int指针数组。答案:func4是 函数(形参为int二级指针, 返回值为int)

准则1:函数形参中所谓的数组实际上都是指针类型

int func5(int(*arr)[10]); 注意arr本身又不是一个数组,而是指针!一个指向数组的指针! 答案:func5是 函数(形参为指向[int数组(10元素)]的指针, 返回值为int)

int func6(int arr[10][10]); 你以为arr是int**吗?那就又错了。如果退化成int**类型的话,那么对于传入的指针做类似arr[3][5]的操作是十分危险的。通常int**用于指向两个维度都是动态分配的二维数组(一个动态的指针数组,每个指针是一个动态数组),即把第一行的元素都当做int*而不是int来看待。把一个二维数组强制变成变成int**,再解除一次引用就会引起野指针的危险操作。因此实际上编译器只会对第一维度的[10]当做*来处理,即等价于int func6(int (*arr)[10]);。 答案:func6是 函数(形参为指向[int数组(10元素)]的指针, 返回值为int)

准则2:对于函数形参中的多维数组,只会将第一维度作为指针处理

int func7(int arr[][10]); 和上一题等价。答案:func7是 函数(形参为指向[int数组(10元素)]的指针, 返回值为int)

int func8(int **); 这里只接受两个维度都是动态分配的二维数组(即int指针数组)。 答案:func8是 函数(形参为int二级指针, 返回值为int)

const int * p5; 《C++ Primer》称其为顶层const,即指向常量的指针,其所指数据不可修改,但指针本身可以替换,例:

p5 = NULL; // 正确! *p5 = 5; // 错误!

而像const int num = 5这种也是顶层const

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

箭头所指的为返回值类型。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyjfzz.html