C语言——指针(下)讲解回调函数;冒泡排序;介绍并模拟qsort函数,strlen函数,strcpy函数

C语言——指针(下)讲解回调函数;冒泡排序;介绍并模拟qsort函数,strlen函数,strcpy函数
本章从回调函数入手介绍qsort函数strlen函数strcpy函数讲解冒泡排序并尝试模拟qsort函数strlen函数strcpy函数一、回调函数是什么?回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数当这个指针被用来调用其所指向的函数时被调用的函数就是回调函数。回调函数不是由该函数的实现方直接调用而是在特定的事件或条件发生时由另外的一方调用的用于对该事件或条件进行响应。如下面代码所示下面代码有的地方只有调用函数的逻辑是有差异的我们可以把调用的函数的地址以参数的形式 传递过去使用函数指针接收函数指针指向什么函数就调用什么函数这里其实使用的就是回调函 数的功能。不使用回调函数#includestdio.hintadd(inta,intb){returnab;}intsub(inta,intb){returna-b;}intmul(inta,intb){returna*b;}intdiv(inta,intb){returna/b;}voidmenu(){printf(*********************************\n);printf(1.add 2.sub\n);printf(3.mul 4.div\n);printf(0.exit ***************\n);printf(*********************************\n);}intmain(){intinput0;inta0;intb0;intret0;do{menu();scanf(%d,input);switch(input){case1:printf(请输入两个操作数:);scanf(%d %d,a,b);retadd(a,b);printf(%d\n,ret);break;case2:printf(请输入两个操作数);scanf(%d %d,a,b);retsub(a,b);printf(%d\n,ret);break;case3:printf(请输入两个操作数);scanf(%d %d,a,b);retmul(a,b);printf(%d\n,ret);break;case4:printf(请输入两个操作数);scanf(%d %d,a,b);retdiv(a,b);printf(%d\n,ret);break;case0:printf(退出游戏\n);break;default:printf(输入错误请重新输入);break;}}while(input);return0;}使用回调函数后#includestdio.hintadd(inta,intb){returnab;}intsub(inta,intb){returna-b;}intmul(inta,intb){returna*b;}intdiv(inta,intb){returna/b;}voidcalc(int(*pf)(int,int))//回调函数{intret0;inta0;intb0;printf(请输入操作数);scanf(%d %d,a,b);retpf(a,b);printf( %d\n,ret);}voidmenu(){printf(*****************************\n);printf(****1.add 2.sub****\n);printf(****3.sul 4.div****\n);printf(****0.exit ****\n);printf(*****************************\n);}intmain(){intinput1;do{menu();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;}二、qsort函数1. 什么是qsort函数qsort 是 C 标准库stdlib.h中提供的一个通用排序函数采用快速排序算法可以对任意类型的数组进行排序。2. 函数原型voidqsort(void*base,size_tcount,size_tsize,int(*compar)(constvoid*,constvoid*));1参数介绍base指向待排序数组首元素的指针。count数组中的元素个数。size数组中每个元素的大小单位是字节。compar比较函数的指针这个函数需要你自己定义用来告诉 qsort 两个元素的先后顺序。2函数compar怎么写在排序过程中qsort函数会回调compar函数并依照相应的写法进行排序规则如下需要定义一个函数接收两个 const void * 类型的参数指向数组中的两个元素并返回一个 int以升序为例返回值 0a 排在 b 前面返回值 0两者相等返回值 0a 排在 b 后面举例要以abcd···的方式排列intchar_cmp(constvoid*p1,constvoid*p2){return(*(char*)p1-*(char*)p2);//强制类型转化}需要注意的是p1,p2的指针类型是void*无法直接解引用需要强制类型转化为对应的指针类型再解引用qsort函数排序整型数据举例1#includestdlib.h//conpar函数规定规则intint_cmp(constvoid*pa,constvoid*pb){return(*(int*)pa-*(int*)pb);}intmain(){intarr[]{1,3,5,7,9,2,4,6,8,0};intszsizeof(arr)/sizeof(arr[0]);//调用qsort函数排序qsort(arr,sz,sizeof(arr[0]),int_cmp);//传入conpar函数地址for(inti0;isz;i){printf(%d ,arr[i]);}return0;}使用qsort排序结构数据使用age排序structStu{charname[20];intage;};intage_cmp(void*p1,void*p2){return(*(structStu*)p1).age-(*(structStu*)p2).age;//return *(struct Stu*)p1 - age - *(struct Stu*)p2 - age;//也可以这样写}intmain(){structStuarrs[]{{zhansan,20},{lisi,25},{wanwu,15}};intszsizeof(arrs)/sizeof(arrs[0]);qsort(arrs,sz,sizeof(arrs[0]),age_cmp);return0;}使用进行name排序structStu{charname[20];intage;};intname_cmp(void*p1,void*p2){returnstrcmp(((structStu*)p1)-name,((structStu*)p2)-name);}intmain(){structStuarrs[]{{zhansan,20},{lisi,25},{wanwu,15}};intszsizeof(arrs)/sizeof(arrs[0]);qsort(arrs,sz,sizeof(arrs[0]),name_cmp);return0;}三、qsort 函数的模拟实现我们尝试使用冒泡排序的方法实现这个功能首先我们先了解一下什么是冒泡排序比如说我们想将下列数组由小到大排序arr[10] {1,4,2,6,3,8,10,5,9,7}我们可以创建一个for循环用于计算趟数每次循环将最大的数往后排每趟那如何排呢我们再创建一个for循环从前往后检查相邻的两个数如果前面的数比后面的数小把交换两个数如果前面的数比后面的数大跳过本次循环形象地理解第一趟 arr[10] {······ ,10}进行9次判断 第二趟 arr[10] {······ ,9,10}进行8次判断 第一趟 arr[10] {······ 8,9,10}进行7次判断照这样下去一共要循环9塘写一个冒泡排序函数voidbubble(intsz,intarr[10]){for(inti0;isz-1;i){intflag1;//是否排好(注释的不写也行)for(intj0;jsz-i-1;){if(arr[j]arr[j1]){flag0;//进入内循环说明还没拍好inttmparr[j];arr[j]arr[j1];arr[j1]tmp;}}if(flag1)//没进内循环排好了跳出循环break;}}如果已经理解了我们就尝试模拟qsort函数吧voidsup_f(char*a,char*b,intsize){//逐个交换每个字节for(inti0;isize;i){intsmp*a;*a*b;*bsmp;a;b;}}voidbubble(void*base,intcount,intsize,int(conper)(void*,void*)){for(inti0;icount-1;i){intflag1;for(intj0;jcount-i-1;j){//判断大小丢给conper判断每次判断完指针向后移size位if((conper((char*)basej*size,(char*)base(j1)*size))0){flag0;//交换funssup_f((char*)basej*size,(char*)base(j1)*size,size);}}if(flag1)break;}}把之前的数组拿来测试一下intint_cmp(constvoid*pa,constvoid*pb){return(*(int*)pa-*(int*)pb);}voidsup_f(char*a,char*b,intsize){for(inti0;isize;i){intsmp*a;*a*b;*bsmp;a;b;}}voidbubble(void*base,intcount,intsize,int(conper)(constvoid*,constvoid*)){for(inti0;icount-1;i){intflag1;for(intj0;jcount-i-1;j){//判断大小if((conper((char*)basej*size,(char*)base(j1)*size))0){flag0;//交换sup_f((char*)basej*size,(char*)base(j1)*size,size);}}if(flag1)break;}}intmain(){intarr[]{1,3,5,7,9,2,4,6,8,0};intszsizeof(arr)/sizeof(arr[0]);bubble(arr,sz,sizeof(arr[0]),int_cmp);for(inti0;isz;i){printf(%d ,arr[i]);}return0;}运行成功四、模拟strlen函数 strlen 函数string功能计算字符串的长度。原型size_t strlen(const char *str);说明从字符串首地址开始向后计数直到遇到空字符 ‘\0’ 时停止。计算出的长度不包括 ‘\0’。返回值返回字符串中的字符个数类型为 size_t。下面我们来尝试模拟一下这个函数//计数器intmy_strlen(constchar*a){intcount0;while(*a){count;}returncount;}//指针-指针intmy_strlen2(constchar*a){intstarta;while(*a);returna-start;}//递归intmy_strlen3(constchar*a){if(*a){a;return1my_strlen3(a);}else{return0;}}五、模拟strcpy函数 strcpy 函数string功能字符串拷贝复制。原型char *strcpy(char *dest, const char *src);说明将 src 指向的字符串包括结尾的 ‘\0’完整地复制到 dest 指向的内存空间中。返回值返回目标字符串 dest 的首地址。下面我们来尝试模拟一下这个函数char*my_strcpy(char*dest,constchar*cop){intretdest;while(*dest*cop);returnret;}

最新新闻

日新闻

周新闻

月新闻