目录
十、回调函数和qsort函数
ps:关于函数指针的内容在深入理解c指针(六)
1、回调函数
还是以加、减、乘、除四个函数的应用为例,在如下代码中,红色框中的代码是重复出现的,其中虽然执行计算的函数是有区别的,但是输入输出操作是冗余的,有没有办法,简化一些呢?
因为红色框中的代码,只有调用函数的逻辑是有差异的,我们可以把调用的函数的地址以参数的形式传递过去,使用函数指针接收,函数指针指向什么函数就调用什么函数,这里其实使用的就是回调函数的功能。
如下是使用回调函数的代码:
//使⽤回到函数改造后
#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;
}
void calc(int(*pf)(int, int))
{
int ret = 0;
int x, y;
printf("输⼊操作数:");
scanf_s("%d %d", &x, &y);
ret = pf(x, y);
printf("ret = %d\n", ret);
}
int main()
{
int input = 1;
do
{
printf("*************************\n");
printf(" 1:add 2:sub \n");
printf(" 3:mul 4:div \n");
printf(" 0:exit \n");
printf("*************************\n");
printf("请选择:");
scanf_s("%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;
}
2、简单介绍size_t 数据类型
size_t
与int 、double一样是C语言中的一种数据类型,通常用于表示对象的大小(以字节为单位)或数组的索引。它是无符号整数类型,在不同的系统上的大小可能会有所不同,但通常被定义为能够容纳系统中最大对象大小的无符号整数类型。字节大小如下:
同时 size_t 数据类型以%zd形式打印:
#include<stdio.h>
int main()
{
size_t a = 20;
printf("%zd",a);
return 0;
}
3、qsort 排序函数
在C语言中,qsort
函数是stdlib.h标准库中的一个函数,用于对任意数据类型进行快速排序。qsort
函数的原型如下:
base
:指向要排序的数组的指针,接收数组首元素地址。nmemb
:数组中元素的个数。size
:数组中每个元素的大小(以字节为单位)。compar
:指向比较函数的指针,用于指定元素之间的比较规则。(函数指针)
比较函数compar
接受两个指向元素的指针,返回一个整数值来指示这两个元素的大小关系。如果返回值是负数,则表示第一个元素应该排在第二个元素之前;如果返回值是正数,则表示第二个元素应该排在第一个元素之前;如果返回值是零,则表示两个元素相等。
3.1 qsort函数简单举例1(升序排序)
3.2 qsort函数简单举例2(字符串长度排序)
当我们调用qsort
函数时,需要传递四个参数:要排序的数组指针、数组中元素的个数、每个元素的大小以及比较函数指针。
假设我们有一个包含字符串的数组,我们想要按照字符串长度进行排序。首先,我们需要定义一个比较函数,该函数将根据字符串的长度来比较两个字符串。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 比较函数,按字符串长度升序排序
int compare(const void *a, const void *b)
{
size_t len_a = strlen(*(char **)a);
size_t len_b = strlen(*(char **)b);
return len_a - len_b;
}
int main()
{
char *arr[] = {"apple", "banana", "orange", "kiwi", "pear"};
int n = sizeof(arr) / sizeof(arr[0]);
qsort(arr, n, sizeof(char *), compare);
for (int i = 0; i < n; i++)
{
printf("%s\n", arr[i]);
}
return 0;
}
在这个例子中,我们定义了一个字符串数组arr
,并且定义了一个比较函数compare
,用于按照字符串长度升序排序。在比较函数中,我们使用strlen
函数获取字符串的长度,并将其转换为size_t
类型进行比较。
在main
函数中,我们调用qsort
函数对字符串数组arr
进行排序,将每个元素的大小(指向字符串的指针)作为sizeof(char *)
传递给qsort
函数。
3.3 简单讲解 -> 操作符
-> 操作符,用于访问结构体和联合体类型的成员,通过指向结构体或联合体的指针进行成员访问。它通常用于简化指针访问结构体成员的操作。
具体来说,如果有一个结构体指针ptr
,需要访问它所指向的结构体中的成员变量member
,可以使用ptr->member
来实现,这样就可以通过指针直接访问结构体中的成员,而不需要先解引用指针再使用 .
操作符。示例如下:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
struct Person
{
char name[20];
int age;
};
int main()
{
struct Person person1;
struct Person *ptr = &person1;
// 使用strcpy函数给name成员赋值
strcpy(ptr->name, "John Doe");
ptr->age = 25;
// 输出成员变量name和age的值
printf("Name: %s, Age: %d\n", ptr->name, ptr->age);
return 0;
}
在上面的示例中,ptr->age
用于访问结构体Person
中的成员变量age
,而不需要通过(*ptr).age
的方式来访问。
3.4 常见符号的ASCII码值
3.5 简单介绍strcmp函数
strcmp
函数是C语言中用于比较两个字符串大小的函数,其原型定义在string.h
头文件中。该函数用于按字典顺序比较两个字符串,并返回一个整数值来表示比较结果。原型如下:
int strcmp(const char *str1, const char *str2);
函数接受两个参数,分别是指向要比较的字符串的指针str1
和str2
。它们分别指向以null结尾的C字符串(即以null字符\0
作为字符串的结束标志)。
只要记住:
1.这个函数比较的是两个字符串对应位置元素的ASCII码值,如果str1
对应元素的ASCII码值在str2
对应元素之前,则返回一个负整数,在其之后返回正整数,如果相等,则比较下一个元素。
2.该函数是对字符串元素依次进行比较,如果相等则比较下一个,一旦发现不相等的字符就能确定两个字符串的大小关系,后面的元素就不比较了。
3.如果两个字符串长度不相等,且前几个元素ASCII码值相同,那么短的比长的小。(如果短的是第一个字符串则返回负数,如果短的是第二个字符串则返回正数)
3.6 使用qsort排序结构数据
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//定义Stu结构体
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);
}
//按照年龄来排序
void test2()
{
struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
//打印排序结果
int i = 0;
for (i = 0; i < sizeof(s) / sizeof(s[0]); i++)
{
printf("Student %d:\n", i + 1);
printf("Name: %s\n", s[i].name);
printf("Age: %d\n", s[i].age);
printf("\n");
}
}
//按照名字来排序
void test3()
{
struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
//打印排序结果
int i = 0;
for (i = 0; i < sizeof(s) / sizeof(s[0]); i++)
{
printf("Student %d:\n", i + 1);
printf("Name: %s\n", s[i].name);
printf("Age: %d\n", s[i].age);
printf("\n");
}
}
int main()
{
test2();
test3();
return 0;
}
4、qsort函数的模拟实现(利用冒泡排序算法)
ps:冒泡排序的基本思想在深入理解指针(五)
#include <stdio.h>
#include<stdlib.h>
int int_cmp(const void* p1, const void* p2)
{
return (*(int*)p1 - *(int*)p2);
}
void _swap(void* p1, void* p2, int size)
{
int i = 0;
for (i = 0; i < size; i++)
{
char tmp = *((char*)p1 + i);
*((char*)p1 + i) = *((char*)p2 + i);
*((char*)p2 + i) = tmp;
}
}
void bubble(void* base, int count, int size, int(*cmp)(void*, void*))
{
int i = 0;
int j = 0;
//趟
for (i = 0; i < count - 1; i++)
{
//每一趟冒泡排序过程
for (j = 0; j < count - i - 1; j++)
{
//if(arr[j]>arr[j+1]
if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
{
// int tmp=arr[j];
// arr[j]=arr[j+1];
// arr[j+1]=tmp;
_swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
}
}
}
}
int main()
{
int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
int i = 0;
bubble(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");
return 0;
}