目录1. 回调函数2. qsort 使用举例2.1 使用qsort来排序整型数组2.2 使用qsort来排序结构体数据3.qsort函数的模拟实现1. 回调函数定义回调函数是一种函数指针地址作为参数传递给另一个函数的机制。调用方式回调函数本身不是直接由程序显式调用的。它是在特定的事件或条件发生时由被传入的另一方函数调用的。使用目的回调函数通常用于对特定事件或条件做响应。也就是当某件事情发生或某个条件满足时程序会触发回调函数执行对应的逻辑。特点总结传递灵活可以在运行时把不同的函数作为参数传入动态改变行为。事件驱动常用于事件驱动编程如 GUI 操作、异步操作、定时器等。解耦合调用者只负责触发事件不需要知道回调函数的具体实现提高代码可维护性。// 定义回调函数接受两个整数并返回整数intAdd(intx,inty){returnxy;}// Compute函数接受两个整数和一个回调函数指针intCompute(inta,intb,int(*p)(int,int)){// 调用回调函数 p实际调用的是 Addreturnp(a,b);}intmain(){//将Add函数作为回调函数传入ComputeintrCompute(2,3,Add);printf(%d\n,r);// 输出 5return0;}这里需要用到函数指针的知识知识点回顾C语言指针深入浅出4。学习完回调函数后我们就又可以改写在C语言指针深入浅出4中讲解转移表简易计算器的实现的代码。代码实现intAdd(intx,inty){returnxy;}intSub(intx,inty){returnx-y;}intMul(intx,inty){returnx*y;}intDiv(intx,inty){returnx/y;}voidmenu(){printf(-----------------------------------\n);printf(------ 1. add 2. sub --------\n);printf(------ 3. mul 4. div --------\n);printf(------ 0. exit --------\n);printf(-----------------------------------\n);}voidcalc(int(*p)(int,int)){intx0;inty0;printf(请输入两个数字:);scanf(%d %d,x,y);intrp(x,y);//调用的是对应的函数被调用的函数就是回调函数printf(结果是%d\n,r);}intmain(){intr0;intinput1;menu();do{printf(请选择);scanf(%d,input);switch(input){case1:calc(Add);break;case2:calc(Sub);break;case3:calc(Mul);break;case4:calc(Div);break;case0:printf(退出计算器\n);break;default:printf(输入错误请重新输入\n);break;}}while(input);return0;}下面我再通过图片的方式对于这段代码中回调函数的使用进行讲解2. qsort 使用举例qsort是 C 标准库提供的通用排序函数用于对数组中的任意类型元素进行排序。它内部使用快速排序Quick Sort算法但只需要提供数组和比较方法即可qsort的返回值是void类型。qsort函数原型下面我来对qsort函数中的参数逐一进行说明void *base指向要排序数组的首元素的指针。由于是通用排序类型用void*表示可以指向任意类型的数组。小tipvoid*也被称为泛型指针在C语言深入浅出1中讲解了void*指针相关内容。size_t num数组中元素的数量。size_t size数组中每个元素占用的字节数。int (*compar)(const void *, const void *)比较函数的指针也叫回调函数。函数接收两个元素的指针返回值表示这两个元素的相对顺序 0第一个元素排在前0两个元素相等 0第一个元素排在后这个函数决定了qsort的排序规则。更加大白话的理解函数的返回值能体现出p1和p2指向的数据的大小。p1指向的数据 p2指向的数据, 返回 0的数字p1指向的数据 p2指向的数据, 返回 0的数字p1指向的数据 p2指向的数据, 返回 0如果对于上述还有不理解的地方下面这张图片可以加深对于qsort函数的理解2.1 使用qsort来排序整型数组#includestdio.h#includestdlib.h//使用qsort函数要包含头文件intcmp_int(constvoid*p1,constvoid*p2){// void* 类型的指针不能直接解引用取值// 需要先强制转换为 int*再解引用得到整数return*((int*)p1)-*((int*)p2);}intmain(){intarr[10]{8,7,6,9,5,4,3,1,2,0};intszsizeof(arr)/sizeof(arr[0]);qsort(arr,sz,sizeof(arr[0]),cmp_int);// 将比较函数 cmp_int 作为回调函数传给 qsortfor(inti0;isz;i)printf(%d ,arr[i]);return0;}qsort函数工作原理示意图2.2 使用qsort来排序结构体数据讲解之前我们要讲解之前C语言操作符详解中还没讲解的结构体成员间接访问的方式我们还需要补充一个操作符结构体指针访问操作符-, 当我们通过结构体指针访问结构体成员时可以使用-操作符。结构体成员访问1.结构体变量.成员名2.结构体指针-成员名structStu{charname[20];intage;};intmain(){inta0;structStup1{zhangsan,18};structStu*p2p1;// 通过结构体指针访问结构体成员printf(%s %d\n,p2-name,p2-age);//修改结构体成员p2-age20;return0;}讲解完这个后C语言操作符详解的介绍就正式告一段落了接下来我们继续学习。他由于下面我创建的结构体成员是char name[20]和int age,相应的比较方式也不同我们一一进行学习。第一种情况:比较年龄#includestdio.h#includestdlib.h//使用qsort函数要包含头文件structStu{charname[20];intage;};intcmp_stu_by_age(constvoid*p1,constvoid*p2){return((structStu*)p1)-age-((structStu*)p2)-age;// p1 和 p2 指向的是结构体数组中的元素所以需要强转为 struct Stu* 类型(结构体指针类型)}intmain(){// 定义结构体数组用来存储学生信息structStup[]{{zhangsan,21},{lisi,19},{wangwu,20}};//结构体的比较要分情况进行比较在这个示例中要么比较年龄要么比较名字intszsizeof(p)/sizeof(p[0]);//计算数组的元素个数qsort(p,sz,sizeof(p[0]),cmp_stu_by_age);//qsort(结构体数组首地址, 学生个数, 每个学生结构体的大小, 按年龄比较);for(inti0;isz;i){printf(%s %d\n,p[i].name,p[i].age);//结构体成员的访问}return0;}注意在qsort函数的第三个参数时容易出错因为比较的是年龄但排序移动的是整个结构体所以第三个参数必须是sizeof(p[0])不能是sizeof(int)。第二种情况比较姓名因为在 C 语言中字符串不能直接使用、、来比较内容大小所以需要使用库函数strcmp。strcmp是字符串比较函数用于按照字典序比较两个字符串的大小。项目说明函数名strcmp头文件#include string.h函数原型int strcmp(const char* str1, const char* str2);功能比较两个字符串的大小比较方式从两个字符串的第一个字符开始逐个比较直到遇到不同字符或字符串结束标志\0比较规则按字符的 ASCII 码值进行比较注意事项strcmp比较的是字符串内容不是字符串长度参数含义str1第一个要比较的字符串str2第二个要比较的字符串返回值含义 0str1小于str2 0str1等于str2 0str1大于str2#includestdio.h#includestring.h//运用strcmp要包含头文件#includestdlib.hstructStu{charname[20];intage;};intcmp_stu_by_name(constvoid*p1,constvoid*p2){returnstrcmp(((structStu*)p1)-name,((structStu*)p2)-name);}intmain(){// 定义结构体数组用来存储学生信息structStup[]{{zhangsan,29},{lisi,30},{wangwu,10}};intszsizeof(p)/sizeof(p[0]);//计算数组的元素个数qsort(p,sz,sizeof(p[0]),cmp_stu_by_name);for(inti0;isz;i){printf(%s %d\n,p[i].name,p[i].age);}return0;}3.qsort函数的模拟实现在通用排序算法中通常有以下几步由于qsort函数内部使用快速排序Quick Sort算法我们暂时没有讲到我们就用冒泡的方式来实现冒泡排序的相关讲解C语言深入浅出3。注意事项1.base是void*类型不能直接进行下标访问。2.由于void*不知道元素大小所以要强转为char*按字节移动。3.第 j 个元素的地址为(char*)base j * width4.width表示每个元素占用的字节数。5.cmp用来比较两个元素的大小传入的是两个元素的地址。6.Swap按width 个字节交换交换的是整个元素因为我们将数组强制类型转化为char*,所以我们只能逐字节地进行交换交换次数即为数组每个元素所占用的字节数width。7.排序依据由cmp决定交换大小由width决定。代码实现#includestdio.h#includestring.hvoidSwap(char*buf1,char*buf2,size_twidth){for(inti0;iwidth;i){chartmp*buf1;*buf1*buf2;*buf2tmp;buf1;buf2;}}voidbubble_sort(void*base,size_tsz,size_twidth,int(*cmp)(constvoid*p1,constvoid*p2)){for(size_ti0;isz;i){for(size_tj0;jsz-1-i;j){if(cmp((char*)basej*width,(char*)base(j1)*width)0){Swap((char*)basej*width,(char*)base(j1)*width,width);}}}}intcmp_arr(constvoid*p1,constvoid*p2){return*((int*)p1)-*((int*)p2);}structStu{charname[20];intage;};intcmp_stu_by_name(constvoid*p1,constvoid*p2){returnstrcmp(((structStu*)p1)-name,((structStu*)p2)-name);}intmain(){intarr[10]{9,8,7,6,5,4,0,3,2,1};structStup[]{{zhangsan,21},{lisi,19},{wangwu,20}};intsz1sizeof(arr)/sizeof(arr[0]);intsz2sizeof(p)/sizeof(p[0]);bubble_sort(arr,sz1,sizeof(int),cmp_arr);bubble_sort(p,sz2,sizeof(p[0]),cmp_stu_by_name);for(inti0;isz1;i)printf(%d ,arr[i]);printf(\n\n);for(inti0;isz2;i)printf(%s %d\n,p[i].name,p[i].age);return0;}完
C语言指针深入浅出5
发布时间:2026/5/15 21:58:08
目录1. 回调函数2. qsort 使用举例2.1 使用qsort来排序整型数组2.2 使用qsort来排序结构体数据3.qsort函数的模拟实现1. 回调函数定义回调函数是一种函数指针地址作为参数传递给另一个函数的机制。调用方式回调函数本身不是直接由程序显式调用的。它是在特定的事件或条件发生时由被传入的另一方函数调用的。使用目的回调函数通常用于对特定事件或条件做响应。也就是当某件事情发生或某个条件满足时程序会触发回调函数执行对应的逻辑。特点总结传递灵活可以在运行时把不同的函数作为参数传入动态改变行为。事件驱动常用于事件驱动编程如 GUI 操作、异步操作、定时器等。解耦合调用者只负责触发事件不需要知道回调函数的具体实现提高代码可维护性。// 定义回调函数接受两个整数并返回整数intAdd(intx,inty){returnxy;}// Compute函数接受两个整数和一个回调函数指针intCompute(inta,intb,int(*p)(int,int)){// 调用回调函数 p实际调用的是 Addreturnp(a,b);}intmain(){//将Add函数作为回调函数传入ComputeintrCompute(2,3,Add);printf(%d\n,r);// 输出 5return0;}这里需要用到函数指针的知识知识点回顾C语言指针深入浅出4。学习完回调函数后我们就又可以改写在C语言指针深入浅出4中讲解转移表简易计算器的实现的代码。代码实现intAdd(intx,inty){returnxy;}intSub(intx,inty){returnx-y;}intMul(intx,inty){returnx*y;}intDiv(intx,inty){returnx/y;}voidmenu(){printf(-----------------------------------\n);printf(------ 1. add 2. sub --------\n);printf(------ 3. mul 4. div --------\n);printf(------ 0. exit --------\n);printf(-----------------------------------\n);}voidcalc(int(*p)(int,int)){intx0;inty0;printf(请输入两个数字:);scanf(%d %d,x,y);intrp(x,y);//调用的是对应的函数被调用的函数就是回调函数printf(结果是%d\n,r);}intmain(){intr0;intinput1;menu();do{printf(请选择);scanf(%d,input);switch(input){case1:calc(Add);break;case2:calc(Sub);break;case3:calc(Mul);break;case4:calc(Div);break;case0:printf(退出计算器\n);break;default:printf(输入错误请重新输入\n);break;}}while(input);return0;}下面我再通过图片的方式对于这段代码中回调函数的使用进行讲解2. qsort 使用举例qsort是 C 标准库提供的通用排序函数用于对数组中的任意类型元素进行排序。它内部使用快速排序Quick Sort算法但只需要提供数组和比较方法即可qsort的返回值是void类型。qsort函数原型下面我来对qsort函数中的参数逐一进行说明void *base指向要排序数组的首元素的指针。由于是通用排序类型用void*表示可以指向任意类型的数组。小tipvoid*也被称为泛型指针在C语言深入浅出1中讲解了void*指针相关内容。size_t num数组中元素的数量。size_t size数组中每个元素占用的字节数。int (*compar)(const void *, const void *)比较函数的指针也叫回调函数。函数接收两个元素的指针返回值表示这两个元素的相对顺序 0第一个元素排在前0两个元素相等 0第一个元素排在后这个函数决定了qsort的排序规则。更加大白话的理解函数的返回值能体现出p1和p2指向的数据的大小。p1指向的数据 p2指向的数据, 返回 0的数字p1指向的数据 p2指向的数据, 返回 0的数字p1指向的数据 p2指向的数据, 返回 0如果对于上述还有不理解的地方下面这张图片可以加深对于qsort函数的理解2.1 使用qsort来排序整型数组#includestdio.h#includestdlib.h//使用qsort函数要包含头文件intcmp_int(constvoid*p1,constvoid*p2){// void* 类型的指针不能直接解引用取值// 需要先强制转换为 int*再解引用得到整数return*((int*)p1)-*((int*)p2);}intmain(){intarr[10]{8,7,6,9,5,4,3,1,2,0};intszsizeof(arr)/sizeof(arr[0]);qsort(arr,sz,sizeof(arr[0]),cmp_int);// 将比较函数 cmp_int 作为回调函数传给 qsortfor(inti0;isz;i)printf(%d ,arr[i]);return0;}qsort函数工作原理示意图2.2 使用qsort来排序结构体数据讲解之前我们要讲解之前C语言操作符详解中还没讲解的结构体成员间接访问的方式我们还需要补充一个操作符结构体指针访问操作符-, 当我们通过结构体指针访问结构体成员时可以使用-操作符。结构体成员访问1.结构体变量.成员名2.结构体指针-成员名structStu{charname[20];intage;};intmain(){inta0;structStup1{zhangsan,18};structStu*p2p1;// 通过结构体指针访问结构体成员printf(%s %d\n,p2-name,p2-age);//修改结构体成员p2-age20;return0;}讲解完这个后C语言操作符详解的介绍就正式告一段落了接下来我们继续学习。他由于下面我创建的结构体成员是char name[20]和int age,相应的比较方式也不同我们一一进行学习。第一种情况:比较年龄#includestdio.h#includestdlib.h//使用qsort函数要包含头文件structStu{charname[20];intage;};intcmp_stu_by_age(constvoid*p1,constvoid*p2){return((structStu*)p1)-age-((structStu*)p2)-age;// p1 和 p2 指向的是结构体数组中的元素所以需要强转为 struct Stu* 类型(结构体指针类型)}intmain(){// 定义结构体数组用来存储学生信息structStup[]{{zhangsan,21},{lisi,19},{wangwu,20}};//结构体的比较要分情况进行比较在这个示例中要么比较年龄要么比较名字intszsizeof(p)/sizeof(p[0]);//计算数组的元素个数qsort(p,sz,sizeof(p[0]),cmp_stu_by_age);//qsort(结构体数组首地址, 学生个数, 每个学生结构体的大小, 按年龄比较);for(inti0;isz;i){printf(%s %d\n,p[i].name,p[i].age);//结构体成员的访问}return0;}注意在qsort函数的第三个参数时容易出错因为比较的是年龄但排序移动的是整个结构体所以第三个参数必须是sizeof(p[0])不能是sizeof(int)。第二种情况比较姓名因为在 C 语言中字符串不能直接使用、、来比较内容大小所以需要使用库函数strcmp。strcmp是字符串比较函数用于按照字典序比较两个字符串的大小。项目说明函数名strcmp头文件#include string.h函数原型int strcmp(const char* str1, const char* str2);功能比较两个字符串的大小比较方式从两个字符串的第一个字符开始逐个比较直到遇到不同字符或字符串结束标志\0比较规则按字符的 ASCII 码值进行比较注意事项strcmp比较的是字符串内容不是字符串长度参数含义str1第一个要比较的字符串str2第二个要比较的字符串返回值含义 0str1小于str2 0str1等于str2 0str1大于str2#includestdio.h#includestring.h//运用strcmp要包含头文件#includestdlib.hstructStu{charname[20];intage;};intcmp_stu_by_name(constvoid*p1,constvoid*p2){returnstrcmp(((structStu*)p1)-name,((structStu*)p2)-name);}intmain(){// 定义结构体数组用来存储学生信息structStup[]{{zhangsan,29},{lisi,30},{wangwu,10}};intszsizeof(p)/sizeof(p[0]);//计算数组的元素个数qsort(p,sz,sizeof(p[0]),cmp_stu_by_name);for(inti0;isz;i){printf(%s %d\n,p[i].name,p[i].age);}return0;}3.qsort函数的模拟实现在通用排序算法中通常有以下几步由于qsort函数内部使用快速排序Quick Sort算法我们暂时没有讲到我们就用冒泡的方式来实现冒泡排序的相关讲解C语言深入浅出3。注意事项1.base是void*类型不能直接进行下标访问。2.由于void*不知道元素大小所以要强转为char*按字节移动。3.第 j 个元素的地址为(char*)base j * width4.width表示每个元素占用的字节数。5.cmp用来比较两个元素的大小传入的是两个元素的地址。6.Swap按width 个字节交换交换的是整个元素因为我们将数组强制类型转化为char*,所以我们只能逐字节地进行交换交换次数即为数组每个元素所占用的字节数width。7.排序依据由cmp决定交换大小由width决定。代码实现#includestdio.h#includestring.hvoidSwap(char*buf1,char*buf2,size_twidth){for(inti0;iwidth;i){chartmp*buf1;*buf1*buf2;*buf2tmp;buf1;buf2;}}voidbubble_sort(void*base,size_tsz,size_twidth,int(*cmp)(constvoid*p1,constvoid*p2)){for(size_ti0;isz;i){for(size_tj0;jsz-1-i;j){if(cmp((char*)basej*width,(char*)base(j1)*width)0){Swap((char*)basej*width,(char*)base(j1)*width,width);}}}}intcmp_arr(constvoid*p1,constvoid*p2){return*((int*)p1)-*((int*)p2);}structStu{charname[20];intage;};intcmp_stu_by_name(constvoid*p1,constvoid*p2){returnstrcmp(((structStu*)p1)-name,((structStu*)p2)-name);}intmain(){intarr[10]{9,8,7,6,5,4,0,3,2,1};structStup[]{{zhangsan,21},{lisi,19},{wangwu,20}};intsz1sizeof(arr)/sizeof(arr[0]);intsz2sizeof(p)/sizeof(p[0]);bubble_sort(arr,sz1,sizeof(int),cmp_arr);bubble_sort(p,sz2,sizeof(p[0]),cmp_stu_by_name);for(inti0;isz1;i)printf(%d ,arr[i]);printf(\n\n);for(inti0;isz2;i)printf(%s %d\n,p[i].name,p[i].age);return0;}完