C语言-指针进阶-函数指针数组应用-计算器(9.2)

简介: C语言-指针进阶-函数指针数组应用-计算器(9.2)

思维导图:




1. 函数指针

直接上代码:


#include 
void test()
{
  printf("hehe\n");
}
int main()
{
  printf("%p\n", test);
  printf("%p\n", &test);//取函数地址
  return 0;
}


输出:


输出:

00F013CF

00F013CF

打印出来的其实就是函数的地址,


通过观察我们发现函数名的地址与&函数名其实是一样的。


那我们该如何存储函数的地址呢?


例:


#include 
void test()
{
  printf("hehe\n");
}
int main()
{
  //*与指针名先结合,左边是函数返回类型,右边是函数传的参数
  void (*pfun1)() = &test;//因为test与&test其实是一样的
                         //所以&是可以省略的
  return 0;
}

学到这里,我们读两段有趣的代码:


int main()
{
  (*(void (*)())0)();
  void (*signal(int, void(*)(int)))(int);
  return 0;
}
他们分别代表着什么呢?
int main()
{
  (*(void (*)())0)();
  //这是一段函数调用,
  //将0强制类型转换成一个类型是void (*)()的函数指针
  //然后调用0地址处的函数
  void (*signal(int, void(*)(int)))(int);
  //这是一段函数声明,
  //声明的是一个函数名是signal
  //返回类型是void(*)(int)类型的函数指针
  //参数类型是int和void(*)(int)的一个函数
  return 0;
}


2. 函数指针数组

2.1函数指针数组的定义

函数指针数组是什么?


其实就是一个数组的每个元素都是函数指针。


例:


int main()
{
  int (*parr1[10])();
  //这就是一个函数指针数组,parr1与[10]先结合表面他是一个数组
  //而他这个数组每个元素的类型是int(*)()的函数指针
  return 0;
}

2.2函数指针数组应用

函数指针究竟有什么用呢?


我们实现一个计算器试试:


一般的思路:


#include 
//函数实现
int Add(int x, int y)
{
  return x + y;
}
int Sub(int x, int y)
{
  return x - y;
}
int Mul(int x, int y)
{
  return x * y;
}
int Div(int x, int y)
{
  return x / y;
}
//菜单打印
void menu()
{
  printf("1.加法\n2.减法\n3.乘法\n4.除法\n0.退出\n");
}
void test()
{
  int input = 0;
  int x = 0, y = 0;
  int ret = 0;
  do
  {
  menu();
  printf("请选择:>");
  scanf("%d", &input);
  switch(input)
  {
  case 1:
    printf("请输出:>");
    scanf("%d %d", &x, &y);
    ret = Add(x, y);
    printf("%d\n", ret);
    break;
  case 2:
    printf("请输出:>");
    scanf("%d %d", &x, &y);
    ret = Sub(x, y);
    printf("%d\n", ret);
    break;
  case 3:
    printf("请输出:>");
    scanf("%d %d", &x, &y);
    ret = Mul(x, y);
    printf("%d\n", ret);
    break;
  case 4:
    printf("请输出:>");
    scanf("%d %d", &x, &y);
    ret = Div(x, y);
    printf("%d\n", ret);
    break;
  case 0:
    printf("计算器已退出\n");
    break;
  default:
    printf("输入错误,请重新输入\n");
    break;
  }
  } while (input);
}
int main()
{
  test();//分装函数实现
  return 0;
}


但是我们发现这样实现代码量太多,


或者说代码重复的部分太多,代码冗余,那我们该如何改进呢?


利用函数指针数组的思路:

#include 
//菜单打印
void menu()
{
  printf("1.加法\n2.减法\n3.乘法\n4.除法\n0.退出\n");
}
//函数实现
int Add(int x, int y)
{
  return x + y;
}
int Sub(int x, int y)
{
  return x - y;
}
int Mul(int x, int y)
{
  return x * y;
}
int Div(int x, int y)
{
  return x / y;
}
//函数指针数组存放上述函数的地址
int (*pf[5])(int, int) = { NULL, Add, Sub, Mul, Div };
void test()
{
  int input = 0;
  int x = 0;
  int y = 0;
  int ret = 0;
  do
  {
  menu();
  printf("请选择:>");
  scanf("%d", &input);//这里输入函数指针数组的下标
  if (input == 0)//用if else语句判断退出和选择错误的特殊情况
  {
    printf("退出计算器\n");
    break;
  }
  else if (input >= 1 && input <= 4)//使用计算器的情况
  {
    printf("请输入两个操作数:>");
    scanf("%d %d", &x, &y);
    ret = pf[input](x, y);//通过函数指针数组调用函数
    printf("%d\n", ret);
  }
  else
  {
    printf("选择错误\n");
  }
  } while (input);
}
int main()
{
  test();//分装函数实现
  return 0;
}

这样写,代码冗余的问题也解决了,


这就是函数指针数组的一个应用场景,


当然,函数指针数组也有一定的缺陷,比如实现这个计算器时:


想要通过数组访问,每个函数指针的参数必须要相同。


3. 指向函数指针数组的指针

我们学了函数指针,


又学了函数指针数组,


当然也有指向函数指针数组的指针啦!


例:

int Add(int x, int y)
{
  return x + y;
}
int main()
{
  int(*padd)(int, int) = Add; //这是一个函数指针
  int(*parr[5])(int, int);//这是一个函数指针数组
  int(*(*pparr)[5])(int, int) = &parr;
  //*与指针名先结合,证明这是一个指针,与[]相连证明这是一个数组指针,
  //而这个数组指针每个元素的类型是int(*)(int,int)的函数指针,
  //这就是一个指向函数指针数组的指针。
  return 0;
}



写在最后:

以上就是本篇文章的内容了,感谢你的阅读。


如果喜欢本文的话,欢迎点赞和评论,写下你的见解。


如果想和我一起学习编程,不妨点个关注,我们一起学习,一同成长。


相关文章
|
存储 人工智能 程序员
一文彻底搞明白C语言的数组
本文详细介绍了C语言中的数组,包括定义、初始化(静态与动态)、存储方式、访问方法及常用操作,如遍历、修改元素和作为函数参数传递。数组是C语言中最基本的数据结构之一,掌握它对编程至关重要。下篇将介绍二维数组,敬请期待!
747 0
一文彻底搞明白C语言的数组
|
传感器 算法 安全
【C语言】两个数组比较详解
比较两个数组在C语言中有多种实现方法,选择合适的方法取决于具体的应用场景和性能要求。从逐元素比较到使用`memcmp`函数,再到指针优化,每种方法都有其优点和适用范围。在嵌入式系统中,考虑性能和资源限制尤为重要。通过合理选择和优化,可以有效提高程序的运行效率和可靠性。
1099 6
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
521 5
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
容器
在使用指针数组进行动态内存分配时,如何避免内存泄漏
在使用指针数组进行动态内存分配时,避免内存泄漏的关键在于确保每个分配的内存块都能被正确释放。具体做法包括:1. 分配后立即检查是否成功;2. 使用完成后及时释放内存;3. 避免重复释放同一内存地址;4. 尽量使用智能指针或容器类管理内存。
|
存储 NoSQL 编译器
C 语言中指针数组与数组指针的辨析与应用
在C语言中,指针数组和数组指针是两个容易混淆但用途不同的概念。指针数组是一个数组,其元素是指针类型;而数组指针是指向数组的指针。两者在声明、使用及内存布局上各有特点,正确理解它们有助于更高效地编程。
|
C语言
留念 C语言第一课简单的计算器制作
留念 C语言第一课简单的计算器制作 学C语言这么久了。  /* 留念 C语言第一课简单的计算器制作 */   #include  #include #includevoid displayMenu(); /*赵存档做*/void add();void sub();void m...
938 0
|
存储 算法 C语言
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
855 23
|
8月前
|
存储 C语言
`scanf`是C语言中用于按格式读取标准输入的函数
`scanf`是C语言中用于按格式读取标准输入的函数,通过格式字符串解析输入并存入指定变量。需注意输入格式严格匹配,并建议检查返回值以确保读取成功,提升程序健壮性。
1452 0