【C指针(五)】6种转移表实现整合longjmp()/setjmp()函数和qsort函数详解分析&&模拟实现2

简介: 【C指针(五)】6种转移表实现整合longjmp()/setjmp()函数和qsort函数详解分析&&模拟实现

【C指针(五)】6种转移表实现整合longjmp()/setjmp()函数和qsort函数详解分析&&模拟实现1:https://developer.aliyun.com/article/1474740


switch实现计算器:

主要实现计算器程序思路:

  1. 定义了四个运算函数add、sub、mul、div实现四则运算。
  2. main函数中:
  • 使用do while循环控制程序循环执行。
  • 打印菜单让用户选择运算类型。
  • 根据用户选择用switch case调用对应的运算函数。
  • 每次运算前输入两个操作数,运算后打印结果。
  1. 选择0退出循环,退出程序。
#include <stdio.h>

int add(int a, int b)//加法
{
  return a + b;
}

int sub(int a, int b)//减法
{
  return a - b;
}

int mul(int a, int b)//乘法
{
  return a * b;
}

int div(int a, int b)//除法
{
  return a / b;
}

int main()
{
  int x, y;
  int input = 1;
  int ret = 0;
  do
  {
    printf("*************************\n");
    printf("****  1:add   2:sub   ***\n");
    printf("****  3:mul   4:div   ***\n");
    printf("****  0:exit   ....   ***\n");
    printf("*************************\n");
    printf("请选择:");
    scanf("%d", &input);
    switch (input)//选择
    {
    case 1:
      printf("输入两个操作数:");
      scanf("%d %d", &x, &y);
      ret = add(x, y);
      printf("ret = %d\n", ret);
      break;
    case 2:
      printf("输入两个操作数:");
      scanf("%d %d", &x, &y);
      ret = sub(x, y);
      printf("ret = %d\n", ret);
      break;
    case 3:
      printf("输入两个操作数:");
      scanf("%d %d", &x, &y);
      ret = mul(x, y);
      printf("ret = %d\n", ret);
      break;
    case 4:
      printf("输入两个操作数:");
      scanf("%d %d", &x, &y);
      ret = div(x, y);
      printf("ret = %d\n", ret);
      break;
    case 0:
      printf("退出程序\n");
      break;
    default:
      printf("选择错误,请重新选择\n");
      break;
    }
  } while (input);
  return 0;
}

实现是实现了,但是case里面的每个代码块除了ret = (?)(x,y);有点不同,其他都很相似,这么多代码重复写,会造成代码的冗余,如果我们又继续给用户增加功能,比如&,^,>>等等,然后一个功能我们就加一个case,case多了,代码重复的也多咋改变呢?

不着急,我们不是学习了函数指针数组吗?


我们可以把函数的地址存储在数组里面,然后通过指针访问数组下标(0,1,2,3,4,5...),然后解引用找到我们要找到我们要实现函数的地址

然后给他传参,再接收他的计算的返回值不就搞定了。

哈哈哈哈!!掌声应该送给自己,说做就做!让我们继续往下走。

函数指针数组实现计算器:


思路:


定义了4个函数Add、Sub、Mul、Div,用于四则运算。


menu()函数打印菜单界面。


定义了一个函数指针数组pfArr,元素类型为int (*)(int, int),可以存储这4个二元运算函数的地址。


在主函数中使用do-while循环不断运行:

  • 调用menu()打印菜单
  • scanf输入选择
  • 根据选择从pfArr数组中获取对应函数的地址
  • 调用该函数进行运算
  • 打印结果
void menu()//封装菜单
{
  printf("******************************\n");
  printf("****  1. add     2. sub   ****\n");
  printf("****  3. mul     4. div   ****\n");
  printf("****  0. exit             ****\n");
  printf("******************************\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 main()
{
  int input = 0;
  int x = 0;
  int y = 0;
  int ret = 0;
  do
  {
    menu();
    //函数指针数组的方式解决一下
    //这里的函数指针数组,我们称为转移表
    // 
                    为什么这里要加NULL,直接{add,sub,mul,div}不行吗?
                 如果真是可以的话,那我们观察他的下标  0   1   2   3
                此时此刻,如果我们选择1.add,那么(*p[1])取出的地址是sub,这不对呀,
                如果我们在前面加一个NULL,{ NULL,add,sub,mul,div }
                                    下标为  0    1   2   3   4
                地址:*p[ 0 ] == 0,     *p[ 1 ] ==add
    int (*pfArr[])(int, int) = { NULL, Add, Sub, Mul, Div };
    //                           0     1    2    3    4
    printf("请选择:");
    scanf("%d", &input);

    if (input == 0)
    {
      printf("退出计算器\n");
    }
    else if (input >= 1 && input <= 4)
    {                   
      printf("请输入两个操作数:");
      scanf("%d %d", &x, &y);
      ret = pfArr[input](x, y);           //(*p[input])==add/sub/mul/div函数名,也就是函数的地址
                                        //(p[input])也可以,*号有无,都相当于函数名,也是函数地址
                                        // 也就是ret=(p[input])(x,y);
      printf("%d\n", ret);
    }
    else
    {
      printf("选择错误,重新选择\n");
    }
  } while (input);
  return 0;
}

解释:

当input输入1, pfArr[1]取得Add的地址,然后通过Add函数的地址,执行指令。(当然同理input输入2,3,4也是同样的步骤)。

如果要增加功能,那么可以int (*pfArr[])(int, int) = { NULL, Add, Sub, Mul, Div };增加相应的功能,然后增加相应功能的代码块!

比如,你想要增加位运算(&, |, ^)的功能:

解释:

当input输入1, pfArr[1]取得Add的地址,然后通过Add函数的地址,执行指令。(当然同理input输入2,3,4也是同样的步骤)。

如果要增加功能,那么可以int (*pfArr[])(int, int) = { NULL, Add, Sub, Mul, Div };增加相应的功能,然后增加相应功能的代码块!

比如,你想要增加位运算(&, |, ^)的功能:

  1. 增加位运算函数:
nint And(int x, int y) {
  return x & y;
}

int Or(int x, int y) {
  return x | y;  
}

int Xor(int x, int y) {
  return x ^ y;
}
  1. 修改菜单显示:
void menu() {

  printf("******************************\n");
  printf("****  1. add     2. sub   ****\n"); 
  printf("****  3. mul     4. div   ****\n");
  printf("****  5. &       6. |     ****\n");
  printf("****  7. ^              ****\n");  
  printf("****  0. exit             ****\n");
  printf("******************************\n");

}
  1. 增加函数指针:
int (*pfArr[])(int, int) = {NULL, Add, Sub, Mul, Div, And, Or, Xor};
• 1
  1. 判断函数选择范围:
if(input >= 1 && input <= 7) {

  ret = pfArr[input](x, y);

}

这样就增加了位运算的功能选择了。


如果还需要其他运算,可以继续增加对应的函数和菜单显示即可。


但是,思考———>

int (*p[5])(int x, int y) = { NULL,add,sub,mul,div };那函数的add,sub,mul,div这些地址是不是也和一维数组一样,存储在函数指针数组里面,他们的地址是否是连续的呢?

解释:

函数地址在函数指针数组中的存储方式与一维数组类似,但有一点不同:

  • 函数指针数组pfArr中,add、sub等函数地址的存储是连续的,就像一维数组元素一样,如下标0,1,2,3,4这样连续存储后就可以访问了。
  • 但是,函数本身的代码可能不一定存储在连续内存地址中

举个例子:

假设add函数代码在地址0x00001000,sub函数代码在0x00002000,mul在0x00003000

那么在函数指针数组pfArr中:

fArr[1] 指向 add函数地址 0x00001000  
pfArr[2] 指向 sub函数地址 0x00002000
pfArr[3] 指向 mul函数地址 0x00003000

我们可以看到,pfArr[1]、pfArr[2]、pfArr[3]中的函数地址是以连续的方式存储在数组中的。


但是函数本身的代码地址0x00001000、0x00002000、0x00003000并不连续。


所以总结来说:


函数指针数组pfArr中函数地址是连续存储的

但函数代码本身不一定连续存储在内存中


【C指针(五)】6种转移表实现整合longjmp()/setjmp()函数和qsort函数详解分析&&模拟实现3:https://developer.aliyun.com/article/1474742

相关文章
|
23天前
|
存储 C语言 C++
如何通过指针作为函数参数来实现函数的返回多个值
在C语言中,可以通过将指针作为函数参数来实现函数返回多个值。调用函数时,传递变量的地址,函数内部通过修改指针所指向的内存来改变原变量的值,从而实现多值返回。
|
23天前
|
存储 搜索推荐 C语言
如何理解指针作为函数参数的输入和输出特性
指针作为函数参数时,可以实现输入和输出的双重功能。通过指针传递变量的地址,函数可以修改外部变量的值,实现输出;同时,指针本身也可以作为输入,传递初始值或状态。这种方式提高了函数的灵活性和效率。
|
1月前
|
C++
指针中的回调函数与qsort的深度理解与模拟
本文详细介绍了回调函数的概念及其在计算器简化中的应用,以及C++标准库函数qsort的原理和使用示例,包括冒泡排序的模拟实现。
17 1
|
1月前
利用指针函数
【10月更文挑战第2天】利用指针函数。
17 1
|
1月前
|
算法 搜索推荐 C语言
【C语言篇】深入理解指针4(模拟实现qsort函数)
【C语言篇】深入理解指针4(模拟实现qsort函数)
23 2
|
5月前
|
机器学习/深度学习 搜索推荐 算法
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
|
2月前
|
Linux
在Linux内核中根据函数指针输出函数名称
在Linux内核中根据函数指针输出函数名称
|
3月前
|
程序员 C语言
指针在函数参数和返回值中的使用
指针在函数参数和返回值中的使用
47 9
|
3月前
|
存储 搜索推荐 C语言
C语言中的指针函数:深入探索与应用
C语言中的指针函数:深入探索与应用
|
5月前
|
编译器 C++
函数指针和函数对象不是同一类型怎么替换
函数指针和函数对象不是同一类型,为何可替换用作同一函数的参数