目录
前言
一、 实现一个简单的计算器
1.1 - 代码一
1.2 - 代码二
二、qsort 函数的介绍
三、改进冒泡排序函数
前言
回调函数就是一个通过函数指针调用的函数。如果把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
下面通过两个示例加深对回调函数的理解。
一、 实现一个简单的计算器
实现一个用于整数之间加减乘除的计算器。
1.1 - 代码一
#include <stdio.h>
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, y = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
printf("请输入两个操作数:>");
scanf("%d %d", &x, &y);
printf("%d\n", Add(x, y));
break;
case 2:
printf("请输入两个操作数:>");
scanf("%d %d", &x, &y);
printf("%d\n", Sub(x, y));
break;
case 3:
printf("请输入两个操作数:>");
scanf("%d %d", &x, &y);
printf("%d\n", Mul(x, y));
break;
case 4:
printf("请输入两个操作数:>");
scanf("%d %d", &x, &y);
printf("%d\n", Div(x, y));
break;
case 0:
printf("退出计算器~\n");
break;
default:
printf("选择错误,请重新选择!\n");
break;
}
} while (input);
return 0;
}
程序运行后的效果如下图所示:
1.2 - 代码二
代码一中的一个不足之处在于各 case 语句中有一些重复的代码,造成冗余。可以使用回调函数来解决这一不足。
#include <stdio.h>
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;
}
void calc(int(*pf)(int, int))
{
int x = 0, y = 0;
printf("请输入两个操作数:>");
scanf("%d %d", &x, &y);
printf("%d\n", pf(x, y));
}
int main()
{
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
calc(Add);
break;
case 2:
calc(Sub);
break;
case 3:
calc(Mul);
break;
case 4:
calc(Div);
break;
case 0:
printf("退出计算器~\n");
break;
default:
printf("选择错误,请重新选择!\n");
break;
}
} while (input);
return 0;
}
二、qsort 函数的介绍
qsort
函数用于实现快速排序。
void qsort(void* base, size_t num, size_t width, int(*cmp)(const void* e1, const void* e2));
参数:
-
base
:指向待排序数组中第一个元素的指针,其被转换成void*
。 -
num
:待排序数组的元素个数。 -
width
:待排序数组中每个元素的大小(以字节为单位)。 -
cmp
:指向比较两个元素的函数的指针。比较两个元素的函数的返回值:
返回值 | 描述 |
< 0 | e1 指向的元素小于 e2 指向的元素 |
0 | e1 指向的元素等于 e2 指向的元素 |
> 0 | e1 指向的元素大于 e2 指向的元素 |
示例 1 - 使用 qsort
函数对整型数组进行排序(升序):
#include <stdio.h>
#include <stdlib.h>
int cmp_int(const void* e1, const void* e2)
{
return *(int*)e1 - *(int*)e2;
}
int main()
{
int arr[5] = { 5, 4, 3, 2, 1 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_int);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
// 1 2 3 4 5
return 0;
}
示例 2 - 使用 qsort
函数对结构体数组进行排序(升序):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Stu
{
char name[20];
int age;
};
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 main()
{
struct Stu s[3] = { {"zhangsan", 20}, {"lisi", 21}, {"wangwu", 19} };
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
for (int i = 0; i < sz; i++)
{
printf("%d ", s[i].age);
}
printf("\n");
// 19 20 21
qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
for (int i = 0; i < sz; i++)
{
printf("%s ", s[i].name);
}
printf("\n");
// lisi wangwu zhangsan
return 0;
}
三、改进冒泡排序函数
#include <stdio.h>
int cmp_int(const void* e1, const void* e2)
{
return *(int*)e1 - *(int*)e2;
}
void swap(char* buf1, char* buf2, size_t width)
{
for (size_t i = 0; i < width; i++)
{
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}
void bubble_sort(void* base, size_t num, size_t width, int(*cmp)(const void* e1, const void* e2))
{
for (size_t i = 0; i < num - 1; i++)
{
int flag = 1;
for (size_t 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);
flag = 0;
}
}
if (flag)
break;
}
}
int main()
{
int arr[5] = { 5, 4, 3, 2, 1 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
// 1 2 3 4 5
return 0;
}
void
指针的使用规则:
-
可以用任意类型的指针对
void
指针进行赋值。例如:int a = 10; int* pa = &a; void* p = pa;
如果要将
void
指针赋值给其他类型的值,则需要强制类型转换。 -
在 ANSI C 标准中,不允许对
void
指针进行一些算术运算,如p++
或p += 1
等,因为void
既然是无类型,那么每次算术运算时就不知道该操作几个字节。