欢迎光临
我们一直在努力

深入理解指针5

(一)回调函数

我们把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,被调用的函数就是回调函数。这句话是什么意思呢,回调函数又该如何去使用呢。

这里拿上一节完成的简单计算器代码说明,如下所示

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x – y;
}
int mlt(int x, int y)
{
return x * y;
}
int div(int x, int y)
{
return x / y;
}

void menu()
{
printf("…………………\\n");
printf("……1.Add………\\n");
printf("……2.Sub………\\n");
printf("……3.mlt……….\\n");
printf("……4.div……….\\n");
printf("……0.over……….\\n");

}

int main()

{

int a = 0;
int b = 0;
int input = 0;
int ret = 0;
do
{
menu();
printf("请选择:\\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("请输入两个操作数:\\n");
scanf("%d %d", &a, &b);
ret = Add(a, b);
printf("%d\\n", ret);
break;

case 2:
printf("请输入两个操作数:\\n");
scanf("%d %d", &a, &b);
ret = Sub(a, b);
printf("%d\\n", ret);
break;

case 3:
printf("请输入两个操作数:\\n");
scanf("%d %d", &a, &b);
ret = mlt(a, b);
printf("%d\\n", ret);
break;

case 4:
printf("请输入两个操作数:\\n");
scanf("%d %d", &a, &b);
ret = div(a, b);
printf("%d\\n", ret);
break;

case 0:
printf("退出游戏\\n");
break;

default:
printf("输入错误\\n");
break;

}

} while (input);

return 0;
}

我们之前就提到过,在switch语句中,有多个输入输出语句,这显的有点冗长多余,除了我们之前可以用函数指针数组来简化函数,我们这里也可以用回调函数来简化代码,这里我们需要创建一个新的函数Cal,将加减乘除运算函数的地址存入其中,当程序走到Cal函数时,我们需要选择我们所需要的运算,加减乘除分别对应,1,2,3,4,比如当我们在键盘上敲上1时,会调用加法函数来完成加法运算,而这时我们就可以把之前冗长重复的输入输出语句存放到Cal函数中,具体代码实现如下

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x – y;
}
int mlt(int x, int y)
{
return x * y;
}
int div(int x, int y)
{
return x / y;
}

void menu()
{
printf("…………………\\n");
printf("……1.Add………\\n");
printf("……2.Sub………\\n");
printf("……3.mlt……….\\n");
printf("……4.div……….\\n");
printf("……0.over……….\\n");

}
void Cal(int(*pf)(int,int))
{
int a = 0;
int b = 0;
int ret = 0;
printf("请输入两个操作数:\\n");
scanf("%d %d", &a, &b);
ret = pf(a, b);
printf("%d\\n", ret);
}

int main()

{

int input = 0;

do
{
menu();
printf("请选择:\\n");
scanf("%d", &input);
switch (input)
{
case 1:
Cal(Add);
break;

case 2:
Cal(Sub);
break;

case 3:
Cal(mlt);
break;

case 4:
Cal(div);
break;
case 0:
printf("退出游戏\\n");
break;

default:
printf("输入错误\\n");
break;

}

} while (input);

return 0;
}

(二)qsort函数

之前我们学过用冒泡排序来给一个数组里面的数字排列,但是有局限性,冒泡排序只能给整型变量排序,不能给字符或者其他变量排序,这时我们就可以学习一个新的函数,那就是qsort函数
qsort函数的使用一般格式包含4个部分,如下所示

int arr[] = { 1,2,7,4,3,8,3,1,9,4 };
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), int_cmp);
//arr:指向待排序数组的第一个元素
//sizeof(arr):待排序数组的元素个数
//sizeof(arr[0]):每个元素的大小,单位是字节
//int_cmp:函数指针,指向的函数可以比较数组中的两个元素

所以在使用qsort函数时我们需要创建一个比较函数,比如我们要比较一个整型数组,创建一个int_cmp()比较函数,如下所示

int int_cmp(const void* p1, const void* p2)
{
return (*(int*)p1 – *(int*)p2);
}

int_cmp()里面的两个指针分别代表指向待排序的两个元素,用void类型是因为接受的变量有可能是整型,有可能是浮点型,也有可能是其他类型,所以用void来定义
如果p1<p2,那么返回<0的数
如果p1=p2,那么返回>0的数
如果p1>p2,那么返回>0的数
(int*)p代表强制类型转化,将p转化为整型类型,然后再*(int*),表示解引用,取到两个整型,将它们作对比,完整代码如下:

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int int_cmp(const void* p1, const void* p2)
{
return (*(int*)p1 – *(int*)p2);
}

int main()

{
int arr[] = { 1,2,7,4,3,8,3,1,9,4 };
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), int_cmp);
//arr:指向待排序数组的第一个元素
//sizeof(arr):待排序数组的元素个数
//sizeof(arr[0]):每个元素的大小,单位是字节
//int_cmp:函数指针,指向的函数可以比较数组中的两个元素
for (i = 0; i < sz; i++)
{
//从小到大排序
printf("%d ", arr[i]);
}
}

上面是升序排序,如果想要降序排序只需将int_cmp函数里的p1,p2调换位置即可

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int int_cmp(const void* p1, const void* p2)
{
return (*(int*)p2 – *(int*)p1);
}

int main()

{
int arr[] = { 1,2,7,4,3,8,3,1,9,4 };
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), int_cmp);
//arr:指向待排序数组的第一个元素
//sizeof(arr):待排序数组的元素个数
//sizeof(arr[0]):每个元素的大小,单位是字节
//int_cmp:函数指针,指向的函数可以比较数组中的两个元素
for (i = 0; i < sz; i++)
{
//从小到大排序
printf("%d ", arr[i]);
}
}

我们再比较浮点数的大小,主函数部分和上述代码一样,但是比较函数float_cmp()部分与比较整型部分不同,我们不能直接将两个代比较的数相减,因为比如1-0.5,应该是返回0.5,也就是>0的数,但是浮点数转化成整数时会舍弃小数点后面的数字,直接返回0,所以我们用if比较大小,如果p1>p2,返回1,也就是>0的数,依次类推

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int float_cmp(const void*p1,const void*p2)
{
if (*(float*)p1 > *(float*)p2)
return 1;
else if (*(float*)p1 < *(float*)p2)
return -1;
else
return 0;
}
int main()

{
int i = 0;
float arr2[] = { 0,1.0,6.0,3.0,5.0,9.0 };
int sz = sizeof(arr2) / sizeof(arr2[0]);
qsort(arr2, sz, 4, float_cmp);
for (i = 0; i < sz; i++)
{
printf("%.2f ", arr2[i]);
}

return 0;
}

qsort函数也可以用来比较结构体中的内容,比如创建一个结构体如下

struct Stu
{
char name[20];
int age;
};

我们如果要比较结构体中的内容,我们需要选定一个要比较的类型,比如上述结构体中,我们可以分别按照年龄排序或者按照名字排序,比较名字大小就是比较字符串的长度,首先,我们选择按照年龄排序

1.比较函数:

int age_cmp(const void* p1, const void* p2)
{
return (*(struct Stu*)p1).age – (*(struct Stu*)p2).age;
}

2.主函数:

int main()

{
struct Stu s[] = { {"zhangsan",18},{"lisi",10},{"wangwu",20} };
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), age_cmp);
return 0;
}

3.完整代码:

struct Stu
{
char name[20];
int age;
};

int age_cmp(const void* p1, const void* p2)
{
return (*(struct Stu*)p1).age – (*(struct Stu*)p2).age;
}

int main()

{
struct Stu s[] = { {"zhangsan",18},{"lisi",10},{"wangwu",20} };
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), age_cmp);
return 0;
}

通过调试可以发现数组中的内容按照年龄从小到大排序:
其次,我们再选择按照姓名排序

按照姓名排序就是比较字符串大小,比较字符串大小我们用到strcmp函数,它需要头文件<string.h>,它的使用方法如下所示

#include <stdio.h>
#include <string.h>

int main() {
char s1[] = "abc";
char s2[] = "abd";
char s3[] = "abc";

int res1 = strcmp(s1, s2); // c < d → 返回负数
int res2 = strcmp(s1, s3); // 完全相等 → 返回0

printf("res1 = %d\\n", res1);
printf("res2 = %d\\n", res2);

return 0;
}

将两个字符串用逗号隔开,如果第一个字符串>第二个,返回>0的数,如果相等,则返回0,如果小于,则返回小于0的数

字符串大小比较的规则:

1.从左到右逐个字符对比,找到第一个不相等的字符就停止比较,后续字符不再参与

2.比较依据:单个字符的 ASCII 数值大小

若当前字符 str1[i] > str2[i] → 字符串 1 更大

若当前字符 str1[i] < str2[i] → 字符串 2 更大

3.前面所有字符全都相等时,再比较字符串长度:

短字符串先遇到结束符 \\0,则短的更小。

例:"app" < "apple"

数字(48~57) < 大写字母A~Z(65~90) < 小写字母a~z(97~122)

了解到字符串大小比较规则,和strcmp的使用后,我们来完成按照姓名顺序的排序

1..比较函数:

int name_cmp(const void* p1, const void* p2)
{
return strcmp((*(struct Stu*)p1).name, (*(struct Stu*)p2).name);
}

2.主函数:

int main()

{
struct Stu s[] = { {"zhangsan",18},{"lisi",10},{"wangwu",20} };
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), name_cmp);
return 0;
}

3.完整代码:

struct Stu
{
char name[20];
int age;
};

int name_cmp(const void* p1, const void* p2)
{
return strcmp((*(struct Stu*)p1).name, (*(struct Stu*)p2).name);
}

int main()

{
struct Stu s[] = { {"zhangsan",18},{"lisi",10},{"wangwu",20} };
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), name_cmp);
return 0;
}

通过调试可以发现数组中的内容按照姓名从小到大排序:

赞(0)
未经允许不得转载:171主机测评 » 深入理解指针5
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址