C语言——函数指针数组(转移表的使用)、指向函数指针数组的指针和回调函数(qsort函数的使用)的理解

一、函数指针数组

1.函数指针数组的声明

函数指针数组的声明如下,所谓函数指针数组就是在之前的函数指针的基础上增加了[],由于[]的优先级高于*,故 pf先与[]结合,说明它是一个数组,再与*结合说明数组中的元素的类型是指针,再看后面的参数列表,说明每一个指针都指向一个函数的入口地址,并且指向的函数的返回类型为int。

int (*pf[])(int, int);
2.函数指针数组的用途:转移表

例如:(原始计算器)

#define _CRT_SECURE_NO_WARNINGS 
#include <stdio.h>
#include <stdlib.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;
 while (input) {
  printf("*************************\n");
  printf(" *****1:Add   2:Sub *****\n");
  printf(" *****3:Mul   4:Div *****\n");
  printf("*************************\n");
  printf("请选择:>");
  scanf("%d", &input);
  switch (input) {
  case 1:
   printf("请输入操作符:>");
   scanf("%d %d", &x, &y);
   ret = Add(x, y);
   break;
  case 2:
   printf("请输入操作符:>");
   scanf("%d %d", &x, &y);
   ret = Sub(x, y);
   break;
  case 3:
   printf("请输入操作符:>");
   scanf("%d %d", &x, &y);
   ret = Mul(x, y);
   break;
  case 4:
   printf("请输入操作符:>");
   scanf("%d %d", &x, &y);
   ret = Div(x, y);
   break;
  default:
   printf("选择错误\n");
   break;
  }
  printf("ret = %d\n", ret);
 }
 system("pause");
 return 0;
}

使用转移表之后的计算器:

#define _CRT_SECURE_NO_WARNINGS 
#include <stdio.h>
#include<stdlib.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;
 //转移表,函数指针数组的使用
 int(*p[5])(int x, int y) = { 0, Add, Sub, Mul, Div }; 
 while (input) {
  printf("*************************\n");
  printf("**** 1:Add     2:Sub ****\n");
  printf("**** 3:Mul     4:Div ****\n");
  printf("*************************\n");
  printf("请选择:>");
  scanf("%d", &input);
  if ((input < 5 && input > 0)) {
   printf("请输入操作符:>");
   scanf("%d %d", &x, &y);
   ret = (*p[input])(x, y);
  }
  else
   printf("输入有误!\n");
  printf("ret = %d\n", ret);
 }
 system("pause");
 return 0;
}

二、指向函数指针数组的指针

在此,仅作介绍,它也叫函数指针数组的指针。下面的定义怎么理解呢?首先,p和 * 结合说明是一个指针,之后与[]结合,说明是一个数组指针,再与 * 结合说明用一个指针指向了数组指针,之后又指向了一个函数的入口地址,该函数有两个int类型参数,返回值是int。

int (*(*p)[])(int, int);

总而言之,指向函数指针数组的指针就是在函数指针数组的基础上,再加一个*表示一个指针去指向它。当然,既然有函数指针数组的指针,则必然还有函数指针数组的指针数组,只不过一般的编程用到的情况很少,如果读者有兴趣的话,可以去研究一下。

三、回调函数

什么是回调函数?

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

我的简单理解:假设现在有两个函数一个a函数,一个b函数,我们将a函数的地址存在一个函数指针里边,传给b函数,然后b函数通过一些条件对这个函数指针进行使用来调用它所指向的函数,既(a函数),那么就称为a函数为回调函数。

首先演示一下qsort函数的使用:

#include <stdio.h>
#include <stdlib.h>
//qosrt函数的使用者得实现一个比较函数 
int int_cmp(const void * p1, const void * p2) {
 return (*(int *)p1 > *(int *) p2); 
}
int main() { 
 int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
 int i = 0;
 qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);
 for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) { 
  printf("%d ", arr[i]); 
 }
 printf("\n");
 system("pause");
 return 0; 
}
使用回调函数,模拟实现qsort(采用冒泡的方式)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int int_cmp(const void*p1, const void*p2) {
 return (*(int*)p1) - (*(int*)p2);
}
//比较函数
void swap(char *e1, char *e2, int width) {
 while (width--) {
  char temp = *e1;
  *e1 = *e2;
  *e2 = temp;
  e1++;
  e2++;
 }
}
void bubble_sort(void *base, int sz, int width, int(*cmp)(const void *e1, const void *e2)) {
//用函数指针接收
 int i = 0;
 for (i = 0; i < sz - 1; i++) {
  int j = 0;
  for (j = 0; j < sz - 1 - i; j++) {
   if (cmp((char *)base + j * width, (char *)base + (j + 1)*width)>0) {
    //通过函数指针调用函数int_cmp
    swap((char *)base + j * width, (char *)base + (j + 1)*width, width);
   }
  }
 }
}
int main() {
 int i = 0;
 int arr[] = { 1, 2, 4, 6, 8, 3, 0 };
 int sz = sizeof(arr) / sizeof(arr[0]);
 bubble_sort(arr, sz, sizeof(int), int_cmp);
 //传参int_cmp为函数的地址,是一个函数指针
 for (i = 0; i < sz; i++) {
  printf("%d ", arr[i]);
 }
 printf("\n");
 system("pause");
 return 0;
}
练习使用qsort函数排序各种类型的数据以及模仿qsort的功能实现一个通用的冒泡排序
#define _CRT_SECURE_NO_WARNINGS 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
struct Stu {
 char name[20];
 int age;
};
void print_arr(int *arr, size_t sz)
{
 unsigned int i = 0;
 for (i = 0; i < sz; i++)
 {
  printf("%d ", arr[i]);
 }
}
int cmp_int(const void *e1, const void *e2) 
{
 return *(int *)e1 - *(int *)e2;
}
int cmp_stu_by_age(const void *e1, const void *e2) 
{
 return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
int cmp_stu_by_name(const void *e1, const void *e2)
{
 return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
int cmp_str(const void* e1, const void* e2)
{
 return strcmp(*(char**)e1, *(char **)e2);
}
void _Swap(char *buf1, char *buf2, size_t width)
{
 unsigned int i = 0;
 assert(buf1&&buf2);
 for (i = 0; i < width; i++)
 {
  char tmp = *buf1;
  *buf1 = *buf2;
  *buf2 = tmp;
  buf1++;
  buf2++;
 }
}
void bubble_sort(void *base, int num, int width, int(*cmp)(const void*e1, const void*e2))
{
 int i = 0;
 int j = 0;
 assert(base&&cmp);
 for (i = 0; i < num - 1; i++)
 {
  for (j = 0; j < num - 1 - i; j++)
  {
   if (cmp((char*)base + j * width, (char*)base + (j + 1)*width) > 0)
   {
    //交换
    _Swap((char*)base + j * width, (char*)base + (j + 1)*width, width);
   }
  }
 }
}
int main()
{
 //利用qsort测试整型排序
 int arr[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
 int sz = sizeof(arr) / sizeof(arr[0]);
 qsort(arr, sz, sizeof(arr[0]), cmp_int);
 print_arr(arr, sz);
 利用qsort测试结构体排序
 //struct Stu arr[] = { { "zhangsan", 20 }, { "lisi", 15 }, { "wangwu", 8 } };
 //int sz = sizeof(arr) / sizeof(arr[0]);
 //qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
 //qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
 利用bubble_qsort测试结构体排序
 //struct Stu arr[] = { { "zhangsan", 20 }, { "lisi", 15 }, { "wangwu", 8 } };
 //int sz = sizeof(arr) / sizeof(arr[0]);
 //bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
 利用bubble_qsort测试字符串排序
 //char *arr[] = { "abcdef", "qqqqq", "bbbbbb" };
 //int sz = sizeof(arr) / sizeof(arr[0]);
 //bubble_sort(arr, sz, sizeof(arr[0]), cmp_str);
 printf("\n");
 system("pause");
 return 0;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值