——————————————————————————————————————————————————————————————————————————————————————————————————————————————
函数指针数组的字面意思:
函数 指针 数组
首先 ,他是一个数组,数组的每个元素是函数指针。
他也就是 一群 函数指针的集合。也就是一个数组,用来存放指针,每个指针指向一个函数。
那么剖析下面的概念:
——————————————————————————————————————————————————————————————————————————————————————————————————————————————
指针 :存放地址的变量。指针指向的是地址,,,,巴拉巴拉一堆东西!!!!
使用 int 类型的变量进行举例子 :
int main()
{
int int_P = 10;
int *P = NULL;
printf("int_P = %d ", int_P);
printf("int_P 存放的地址=%p ", &int_P);
printf("int_P 的大小=%d\r\n", sizeof(int_P));
P = &int_P;
printf("*P = %d ", *P);
printf("P = %X ", P);
printf("P 存放的地址=%p ", &P);
printf("P 的大小=%d\r\n", sizeof(P));
}
综上是可以看到的一些信息:
指针P 指向int类型的变量 int_P ;
指针变量本身的地址是 :0X0093F7C4 。指针变量的地址里面存储的是他指向的变量的地址 0X0093F7D0。
指针变量的创建:
指针类型* 指针名 = &变量
例如上附代码中的:
int int_P =10 ;
int*P =NULL;
P = &int_P ;
这是一种方法,这种方式我更加的喜欢。(我也不知道为啥)还可以使用下述的更加直接的方式:
int int_P =10 ;
int*P =&int_P;
p表示指针的名字,* 与p结合,表示这是一个指针变量,int是存放变量地址的类型。
我们将int_P 的地址存放到p中,就可以通过p来找到int_P 当中的内容。
p是一个指针变量,他里面存的是地址,通过地址来访问int_P 存储的数据,需要用到 * 号,
"*"表示解引用
*p解引用就可以找到int_P 中存储的数据,而p本身存储的是地址,所以上图显示将p以地址的形式打印出来,
显示的是a在内存中的地址。
中国人讲话很含蓄,不过关于软件方面的翻译工作做的还是很直白的,毕竟我们是新生代农民工啊!
指针数组,就是 一堆指针组成的组合。
int main()
{
int Num1 = 10;
int Num2 = 15;
int Num3 = 20;
int Num4 = 25;
int *P[4] = {NULL};
P[0] = &Num1;
P[1] = &Num2;
P[2] = &Num3;
P[3] = &Num4;
printf("Num1 =%d Num1的地址是:%p\r\n", Num1,&Num1);
printf("Num2 =%d Num2的地址是:%p\r\n", Num2, &Num2);
printf("Num3 =%d Num3的地址是:%p\r\n", Num3, &Num3);
printf("Num4 =%d Num4的地址是:%p\r\n", Num4, &Num4);
printf("P的地址是 :%p , P存放的地址 :%X\r\n", &P,P);
printf("P[0]的地址是 :%p , P[0]存放的地址 :%X *P[0] = %d\r\n", &P[0], P[0], *P[0]);
printf("P[1]的地址是 :%p , P[1]存放的地址 :%X *P[1] = %d\r\n", &P[1], P[1], *P[1]);
printf("P[2]的地址是 :%p , P[2]存放的地址 :%X *P[2] = %d\r\n", &P[2], P[2], *P[2]);
printf("P[3]的地址是 :%p , P[3]存放的地址 :%X *P[3] = %d\r\n", &P[3], P[3], *P[3]);
}
这个是完全的非常的清晰的:
指针类型* 指针名[个数] ={ &变量,&变量,&变量 。。。 };
或者使用我上述的方式:
指针类型 * 指针名[个数] = {NULL};
我个人是非常的倾向于这样的创建方式的。
整型变量,指针变量,在创建的时候全部都是空,是0,或者是NULL 。想要赋值,你去函数里面赋值去,或者你去其他地方赋值去。反正就别在我创建变量的地方进行赋值。
函数指针,和上面来讲 应该是一脉相承的,指针结尾,那么说破天他也是个指针。
字面上理解,就是存放函数的指针。
指针可以存放的只有地址啊???
那么为啥可以存放函数呢???好神奇??
因为函数 有一个神奇的名字,叫做 函数入口地址,这个函数入口地址,不管你的函数名命名的有多长,他都是4个字节,刚好可以存放在指针里面。就这!!!
C语言的精髓啊!!!
他的模板是这样的:
返回值 (*指针名)(数据类型,数据类型)
举例子:
int (*P)(int ,int) ;
当然这个是非常灵活的:
void (*P)(void); //这样的也是非常可以的。
注意点:
int (*P)(int ,int );
绝对是不可以写成 :
int * P (int ,int) ;
因为上面中小括号的优先级比较高。写成上面的 int(*P) ,这个是函数指针。
int * P ();这个是返回int *类型的函数。
下面举个大一点的例子:
int ADD(int Num1, int Num2)
{
printf("传进来的 Num1 =%d ,Num2 =%d\r\n", Num1, Num2);
return Num1 + Num2;
}
int(*P)(int, int);
int main()
{
// P = &ADD;
P = ADD;
printf("%d\r\n" , P(2,3));
}
P中存放的是函数Add的地址,而函数名就是函数的入口地址。
我们使用Add函数的时候语法规范是这样的 Add(x,y);
直接调用这个函数就可以了!
那么既然函数名就是地址,而p中存放的是Add函数的地址,
所以p就代表了Add,所以我们可以将p看成Add,p(x,y)同样可以做到Add(x,y)的效果,
这两者在使用的时候没有任何差异。
好了,,到最后了 函数指针数组这缝合怪!!!
那么明确一点他是啥 , 数组,,,他必须是数组。
他是啥组成的数组???
函数指针组成的!!!
那么想一下,函数指针怎么写?
void(*P)(void);
想想怎么加上数组???
void(*P)(void)[]; ???
void(*P)[](void); ???
void (*P[])(void);
不用想了上面的带问号的是不对的!!!
按我的想法!!!肯定是第一种啊!!
但是就是第三种!!!!
#include
void test_01(){
printf("This is test01\r\n");
}
void test_02() {
printf("This is test02\r\n");
}
void test_03() {
printf("This is test03\r\n");
}
int (*taskDriveFuncTable[3] ) (void) =
{
test_01,
test_01,
test_03
};
int main()
{
taskDriveFuncTable[0]();
taskDriveFuncTable[1]();
taskDriveFuncTable[2]();
}
int(*P[])(void);
这个顺序不可以乱!!!
下面借鉴一下别人的博客!
可以看到,改造后的代码摒弃了switch语句,采用的是if判断,
一些繁琐的输出语句和选择也全部被优化掉,而今后不论是添加函数功能,还是删除,
只需要修改数组大小,删除数组元素即可,大大简化了代码,变得更好维护。
让我们来仔细分析一下改造后的代码:
先从函数指针数组开始分析,
函数指针数组的创建 返回值(*数组名[元素个数])(数据类型,数据类型)
例如 int (*p[4])(int ,int)
首先这是一个数组,所以p要和[]先结合,我们拿掉数组名后剩下的就是数组的元素类型
也就是: int (*)(int int) 函数指针
上面我们讲过,函数指针数组就是用来存放函数指针的,而函数指针存放的地址就是函数名,函数指针和函数的使用方法上除了名字没有区别,所以既然函数指针存放的是函数名,函数名就是函数地址,我们直接就将函数名(地址)存入数组中。
然后进入while循环,打印菜单,提示用户输入,进入if判断,0则退出。
我们用i来存储用户选择的功能,然后用i作为函数指针数组的下标,通过下标来访问数组的元素
比如arr[0],而数组的元素是函数指针,也就是函数的地址,我们知道函数名就是函数的地址,我们在初始化数组的时候,放入的就是函数名(函数的地址),所我们可以直接用数组的下标来使用函数:arri - 1。以此类推,如果用户输入的是1,2,3,4,我们就使用函数来实现算术功能,输入其他的数则继续循环,回到选择功能。输入0 ,break跳出循环,结束程序。
以上就是函数指针数组的详解,欢迎大家评论与指点!!!————————————————
版权声明:本文为CSDN博主「莱科宁是冠军」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Raikkonen_love/article/details/126483563
——————————————————————————————————————————————————————————————————————————————————————————————————
综上所有的想写的,已经写完了。
写一点自己的想法吧,多看多读多谢 代码这样的东西吧!!!
操千曲而后晓声,观千剑而后识器。——《文心雕龙·知音》
这东西 ,你要多想 ,你更要吃过见过!!!