指针由浅入深(4)
目录1. 字符指针变量2. 数组指针变量2.1 数组指针变量是什么2.2 数组指针变量怎么初始化3. 二维数组传参的本质4. 函数指针变量4.1 函数指针变量的创建4.2 函数指针变量的使用4.3 两端有趣的代码4.3.1 代码14.3.2 代码24.4 typedef 关键字5. 函数指针数组6. 转移表1. 字符指针变量在指针的类型中有一种指针类型为字符指针char*一般使用int main() { char chw; char* pcch; *pcw; return 0; }还有另一种使用方法《剑指offer》中收录了一道和字符串相关的笔试题我们可以试着做一下加深一下理解这段代码运行出来的结果接下来解释一下为什么是这个结果这里str3和str4指向的是一个同一个常量字符串。C/C会把常量字符串存储到单独的一个内存区域 当几个指针指向同一个字符串的时候他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同str3和str4相同。2. 数组指针变量2.1 数组指针变量是什么之前我们学习到了指针数组指针数组是一种数组数组中存放的是地址指针那数组指针是指针还是数组呢当然是指针也就是存放数组的地址能够指向数组的指针变量。那数组指针变量应该怎么写呢int (*p) [6]将其拆分一下1. p先和*结合在一起说明p是指针变量2. 去掉*p剩下int [10]说明指针指向的是一个包含10个int元素的数组3. p是一个指针指向的是一个数组所以叫做数组指针。2.2 数组指针变量怎么初始化数组指针存放的是整个数组的地址而不是数组首元素的地址。注意数组指针的类型就是把变量名去掉后剩下的部分比如int (*p) [10] 中变量名是p那么类型就是去掉p后剩下的 int (*) [10] 表示“指向含有10个int元素数组的指针”。3. 二维数组传参的本质在之前我们需要将一个二维数组传递给一个函数时是这样写的这里实参是二维数组形参也写成二维数组的形式除了这种写法还有别的写法吗首先我们再次理解一下二维数组二维数组是一维数组的数组二维数组的元素是一维数组每一行就是一个元素首元素就是第一行。如下图所以意味着二维数组传参本质上就是传递了地址传递的是第一行这个一维数组的地址。如下当然 *(*(arri)j) 也有其他的表示形式arr[i][j]总结二维数组传参形参的部分可以写成数组也可以写成指针形式。4. 函数指针变量4.1 函数指针变量的创建经过类比我们可以得出函数指针变量是用来存放函数地址的未来通过地址能够调用函数的。那函数是否会有地址呢可以测试一下从上述代码结果我们可以知道函数是有地址的且函数名就是函数的地址也可以通过函数名的方式获得函数的地址。如果我们需要将函数的地址存放起来就要创建函数指针变量其写法与数组指针非常相似。如下函数指针变量的类型和数组一样将变量名去掉即可。可以对函数指针变量类型进行解析4.2 函数指针变量的使用通过函数指针调用指针指向的函数。从上面可以看出pf之前有无*都可以。4.3 两端有趣的代码4.3.1 代码1(*(void (*)())0)();代码解析1. 上述代码是一次函数调用调用的是0这个地址处的函数这个函数没有参数返回类型是void的函数。2. void(*)()是函数指针类型( void (*)() )0发生了强制类型传换将整型0强制类型转换为函数指针类型将0当作一个地址。3. *( void (*)() )0前面加上*表示调用0地址处的这个函数。4.3.2代码2void (*signal(int , void(*)(int)))(int);代码解析1. 上述代码是一个函数声明。2. 声明函数名叫做signal有两个参数第一个参数的类型是int第二个参数的类型是函数指针void(*)(int)这个函数指针能够指向的函数参数是int返回类型是void函数的返回值类型是void(*)(int)。4.4 typedef 关键字typedef 是用来类型重命名的可以将复杂的类型简单化。比如写unsigned int 写起来不方便但如果写成uint 是不是就方便多了那么我们可以使用typedef来重命名如下typedef unsigned int uint;那如果是指针类型能否重命名呢是可以的比如将int * 重命名为ptr_t 如下typedef int* ptr_t;但是对于数组指针和函数指针稍微有点区别比如我们有数组指针类型int(*)[5],需要重命名为parr_t那可以这样写typedef int(*parr_t)[5]; //新的类型名必须在*的右边函数指针类型的重命名也是一样的比如将void(*)(int)类型重命名为pf_t,就可以这样写typedef void(*pf_t)(int); //新的类型名必须在*的右边那么我们便可以简化代码2了1 typedef void(*pfun_t)(int); 2 pfun_t signal(int, pfun_t);5. 函数指针数组数组是一个存放相同类型数据的存储空间我们已经学习了指针数组比如int* arr[10]; //数组的每个元素是int*那要把函数的地址存到一个数组中那这个数组就叫函数指针数组那函数指针的数组如何定义呢int (*parr[3])()解析1. int表示函数的返回类型为int2. parr是数组名3. [3] 表示数组有三个元素4. * 表示每个数组的元素都是指针5. 表示这些指针指向函数。那数组的内容是什么呢是int(*)()类型的函数指针。6. 转移表函数指针数组的用途转移表。举例计算器的一般实现使用函数指针数组的实现只需要引进函数指针数组改下主函数代码即可其他不变。