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;
}



写在最后:

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


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


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


相关文章
|
2月前
|
存储 编译器 C语言
【C语言】指针大小知多少 ?一场探寻C语言深处的冒险 !
在C语言中,指针的大小(即指针变量占用的内存大小)是由计算机的体系结构(例如32位还是64位)和编译器决定的。
186 9
|
2月前
|
安全 程序员 C语言
【C语言】指针的爱恨纠葛:常量指针vs指向常量的指针
在C语言中,“常量指针”和“指向常量的指针”是两个重要的指针概念。它们在控制指针的行为和数据的可修改性方面发挥着关键作用。理解这两个概念有助于编写更安全、有效的代码。本文将深入探讨这两个概念,包括定义、语法、实际应用、复杂示例、最佳实践以及常见问题。
65 7
|
2月前
|
存储 NoSQL 编译器
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
指针是一个变量,它存储另一个变量的内存地址。换句话说,指针“指向”存储在内存中的某个数据。
124 3
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
|
3月前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
C语言
利用c语言制作简易计算器
利用c语言制作简易计算器
1522 0
|
1月前
|
存储 编译器 C语言
【C语言程序设计——函数】分数数列求和2(头歌实践教学平台习题)【合集】
函数首部:按照 C 语言语法,函数的定义首部表明这是一个自定义函数,函数名为fun,它接收一个整型参数n,用于指定要求阶乘的那个数,并且函数的返回值类型为float(在实际中如果阶乘结果数值较大,用float可能会有精度损失,也可以考虑使用double等更合适的数据类型,这里以float为例)。例如:// 函数体代码将放在这里函数体内部变量定义:在函数体中,首先需要定义一些变量来辅助完成阶乘的计算。比如需要定义一个变量(通常为float或double类型,这里假设用float。
37 3
|
1月前
|
存储 算法 安全
【C语言程序设计——函数】分数数列求和1(头歌实践教学平台习题)【合集】
if 语句是最基础的形式,当条件为真时执行其内部的语句块;switch 语句则适用于针对一个表达式的多个固定值进行判断,根据表达式的值与各个 case 后的常量值匹配情况,执行相应 case 分支下的语句,直到遇到 break 语句跳出 switch 结构,若没有匹配值则执行 default 分支(可选)。例如,在判断一个数是否大于 10 的场景中,条件表达式为 “num> 10”,这里的 “num” 是程序中的变量,通过比较其值与 10 的大小关系来确定条件的真假。常量的值必须是唯一的,且在同一个。
20 2
|
1月前
|
存储 C语言
【C语言程序设计——函数】递归求斐波那契数列的前n项(头歌实践教学平台习题)【合集】
本关任务是编写递归函数求斐波那契数列的前n项。主要内容包括: 1. **递归的概念**:递归是一种函数直接或间接调用自身的编程技巧,通过“俄罗斯套娃”的方式解决问题。 2. **边界条件的确定**:边界条件是递归停止的条件,确保递归不会无限进行。例如,计算阶乘时,当n为0或1时返回1。 3. **循环控制与跳转语句**:介绍`for`、`while`循环及`break`、`continue`语句的使用方法。 编程要求是在右侧编辑器Begin--End之间补充代码,测试输入分别为3和5,预期输出为斐波那契数列的前几项。通关代码已给出,需确保正确实现递归逻辑并处理好边界条件,以避免栈溢出或结果
66 16
|
1月前
|
存储 编译器 C语言
【C语言程序设计——函数】回文数判定(头歌实践教学平台习题)【合集】
算术运算于 C 语言仿若精密 “齿轮组”,驱动着数值处理流程。编写函数求区间[100,500]中所有的回文数,要求每行打印10个数。根据提示在右侧编辑器Begin--End之间的区域内补充必要的代码。如果操作数是浮点数,在 C 语言中是不允许直接进行。的结果是 -1,因为 -7 除以 3 商为 -2,余数为 -1;注意:每一个数据输出格式为 printf("%4d", i);的结果是 1,因为 7 除以 -3 商为 -2,余数为 1。取余运算要求两个操作数必须是整数类型,包括。开始你的任务吧,祝你成功!
52 1
|
1月前
|
C语言
【C语言程序设计——函数】亲密数判定(头歌实践教学平台习题)【合集】
本文介绍了通过编程实现打印3000以内的全部亲密数的任务。主要内容包括: 1. **任务描述**:实现函数打印3000以内的全部亲密数。 2. **相关知识**: - 循环控制和跳转语句(for、while循环,break、continue语句)的使用。 - 亲密数的概念及历史背景。 - 判断亲密数的方法:计算数A的因子和存于B,再计算B的因子和存于sum,最后比较sum与A是否相等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台对代码进行测试,预期输出如220和284是一组亲密数。 5. **通关代码**:提供了完整的C语言代码实现
61 24

热门文章

最新文章