一.字符指针变量和数组指针变量
二.二维数组传参的本质
三.函数指针变量及函数指针数组
四.转移表
(一)字符指针变量和数组指针变量
1.字符指针变量
我们以前输入字符使用的大多是char类型,而字符指针用的多是char*类型,例如:char*p="abcdef"中,我们把第一个元素“a”的地址放入了字符指针p中,“*”代表这个p是指针(变量),p指向的内容是char类型。
例如:int main()
{
char ch='k';//创建字符
char*p=&ch;//创建字符指针
return 0;
}
我们可以补充一道题目,加深我们对字符指针变量的理解:
它的运行结果是这样的:
这是因为如果我们创建的只是两个字符数组,那么它在内存里面会申请两份空间,而换成字符指针的形式储存,一模一样的字符串,是没有必要储存两份的,因为地址指向的内容是一样的。
2.数组指针变量
数组指针和数组有一些不同:数组一般是特地存放一些数据的,而数组指针(属于指针变量)是指向某个数组,进而访问数组里面的数据。
比如int*p[10]是指针数组,“*”代表是指针变量,p是指针,p[10]代表p指向的是含十个元素的数组,int*代表数组中每个元素是指针类型。
而int(*p)[10]是数组指针,“*”代表是指针,(*p)表示这个是指向数组的指针,[10]表示这个数组有10个元素,int表示数组内对应的元素类型是int类型。
这里我们讲一下数组指针的初始化:
我们调试一下看一看:
结果是一样的。
(补充:这一类指针也可以用float*p表示浮点型指针,看具体用途)
(二)二维数组传参的本质
曾经我们在数组传参时,只需要传入数组名等就可以了,今天我们有指针的帮助,可以探索一下二维数组传参的本质。
我们以前传参是这样的:
#include <stdio.h>
void test(int arr[3][5], int r, int c)
{
int i = 0;
int j = 0;
{
for (j = 0; j < c; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7} };
test(arr, 3, 5);
return 0;
}
传参时把“三行五列”都传过去了。
那我们既然学了指针,有没有更好的办法呢?
有的,如下:
效果是一样的,大家可以打印去试一下。
但为什么参数部分和原来的二维数组参数变化比较大?
我们知道二维数组是一维数组的数组,二维数组里面的每个元素其实是一维数组。这样就回到了我们之前使用指针形式传参一维数组,同理我们在参数里面看到的in(*arr)[5]的意思是arr是一个数组指针,指针指向的一维数组里面含有5个元素,每个元素的类型是int类型。
(三)函数指针变量及函数指针数组
1.函数指针变量
函数本身其实是有地址的,而我们以指针形式把函数的地址储存起来时,这种指针就是函数指针变量。
例如:我们写一段代码:
int test(int x, int y)
{
return x + y;
}
int main()
{
int test(x,y);
int(*p)(int x, int y) = &test;
printf("%p", p);
printf("%p", test);
printf("%p", &test);
return 0;
}
我们打印一下就可以发现结果都是一样的,这说明&test和test是一样的。
其实我们写上面的函数传参和之前的数组传参有一点不一样的地方,就是要在指针后面加上代传参的数据类型。
当我们想调用函数的时候,在上面的代码下,加上(*p)(参1,参2)或p(参1,参2)等就完成了对函数的调用。
2.函数指针数组
函数指针数组,也和函数传参差不多。如下:
假设我已经创建了4个函数,他们的返回类型是int,参数有两个,都是int型。
int(*parr[5])(int,int)={0,fun(1),fun(2),fun(3),fun(4)};
当我们想通过函数指针来调用相应的函数时,紧接上parr[n](参1,参2)就可以调用相对应的函数,并得到相应结果了。
(四)转移表
我们利用函数指针及函数指针数组来用一下转移表,来完成一个简单的计算器:
当然,这4个函数不慎遗失,需要读者们自己填充。
假如我们不去使用转移表,而是大量使用switch语句等,就会导致每个函数在实现时要多写大量的代码,如下:
随着函数的增加,每个case都要多写三四行,这样的代码写起来费劲,也大量占内存,我们若通过函数指针数组的方式来调用函数,岂不是简单省事?