前言
宝子们,想象一下你在一个大型的书库里找书。书库的书架上摆放着很多排书,每一排书架上都有很多本书。现在,你手里拿着一张地图(指针),这张地图告诉你每一排书架的具体位置。而书架上的每一本书(数组元素)都有自己的编号(索引)。今天这回咱们就来聊聊二维数组与指针之间的关系吧。
一、字符指针变量
首先我们先来介绍一下字符指针变量。字符指针变量顾名思义就是指针变量的类型是字符类型嘛,但是我们学习字符的时候,一个单独的字符和一个字符串之间是有差异的,现在到了指针的环节,两者依然存在差异
二、数组指针
在此之前,我们已经学过了一些基本类型的指针(整型指针,字符指针),现在咱们再来学习一种指针——数组指针,有了前面的基础,我们应该清楚的知道:数组指针就是指针变量指向数组的指针。我们要知道数组指针的类型是 int(*)[10] (指向的数组是一个长度为10的整型数组)
三、二维数组传参的本质
之前我们在间接输出一个一维数组的值时,我们经常通过定义一个函数,然后通过实参传递给形参最后输出。在前面初识指针的时候,咱们已经知道了,实参传给形参的其实是指针(用数组的形式写也是可以的,但是本质上还是指针),今天咱们学习的二维数组传参也有异曲同工之处。
四、函数指针
4.1 函数指针的初始化和解引用
现在我们已经学习了数组指针,那么我们平时也很常用的函数是否也有指针呢?是的,也有函数指针。在此之前,我们先说一个小细节,在数组中arr表示的是数组首元素地址,而&arr表示的是整个数组的地址。但是在函数之中,(例如Add()函数)Add与&Add 的地址是相同的
但是我们还有一点要注意
---------------------------------------------------------------------------------------------------------------------------------
和前面的数组指针一样,函数指针也是在函数的形式上做一些小改动得到的
这里再给函数指针变量的类型做一个小小的解释:在式子的最左边是这个指针指向的函数的类型,*必须放在中间里的括号内,最右边的括号内放的是函数参数的类型(注意:参数的类型,个数要与函数一致)。在调用函数的时候,我们也可以用指针的形式
4.2 函数指针数组
在编写一个程序的时候,如果遇到许多个相似的函数时,当我们定义好函数时,再去一一调用,想想是不是很麻烦?有没有办法把这些函数都放在一个数组里面,然后再遍历使用,那样不是方便许多了嘛。接下来,我们再来学习一个函数指针数组
4.3 两个与函数指针有关的有趣代码
第一眼看到这串代码,心想这是啥子玩意啊,不知道从哪里下手,注意作为一名合格的程序猿,要时刻保持冷静。
这串代码,咱们可以层层剥开分析:首先我们可以看中间的 void (*)()这就是咱们刚刚学习的指针变量类型
( void (*)() )0,这是一个强制类型转换,这里的数字0就是一个地址0
*( void (*)() )0, 是将函数类型指针解引用之后就是一个函数了
最后我们可以看出( *( void (*)() )0 ) ()是一个函数调用(形如Add() )
这个代码相较于上面那个代码是不是更加清楚一点呢,但是我们也不能掉以轻心,也要认真分析
这串代码,咱们来层层分析:中间的signal(int, void(*)(int))是一个有两个参数的函数(只有函数名与函数参数,那么函数类型就是前面的)
由上面的分析,咱们将void (*)(int)拿出来,可以清楚地看到这是一个函数指针类型
故我们可以得出结论:这是一个以signal为函数名,void(*)(int)为函数类型的函数声明
ps:在一个函数中,函数一般有三个作用:函数定义,函数声明,函数调用。以后我们分析函数的时候可以从这三个方面考虑
4.4 typedef关键字
现在学习了指针之后,不知道你们是否觉得现在那些类型的名字实在太长,那些开发者可能也有相同的感觉,于是他们又发明了一个关键字——typedef。它是用来类型重命名的,可以将复杂的类型,简单化。
老规矩,最后咱们再来介绍一个函数指针数组的小妙用——转移表