目录
十、回调函数和qsort函数
1、回调函数
2、简单介绍size_t 数据类型
3、qsort 排序函数
3.1 qsort函数简单举例1(升序排序)
3.2 qsort函数简单举例2(字符串长度排序)
3.3 简单讲解 -> 操作符
3.4 常见符号的ASCII码值
3.5 简单介绍strcmp函数
3.6 使用qsort排序结构数据
4、qsort函数的模拟实现(利用冒泡排序算法)
十、回调函数和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语言中的一种数据类型,通常用于表示对象的大小(以字节为单位)或数组的索引。它是无符号整数类型,在不同的系统上的大小可能会有所不同,但通常被定义为能够容纳系统中最大对象大小的无符号整数类型。字节大小如下:
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;
}