深入理解指针(5)

目录

[1 回调函数是什么?](#1 回调函数是什么?)

[2 qsort 使⽤举例](#2 qsort 使⽤举例)

[2.1 使⽤qsort函数排序整型数据](#2.1 使⽤qsort函数排序整型数据)

[2.2 使⽤qsort排序结构数据](#2.2 使⽤qsort排序结构数据)

[3 qsort函数的模拟实现](#3 qsort函数的模拟实现)


1 回调函数是什么?

如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被⽤来调⽤其所指向的函数时,被调⽤的函数就是回调函数。回调函数不是由该函数的实现⽅直接调⽤,⽽是在特定的事件或条件发⽣时由另外的⼀⽅调⽤的,⽤于对该事件或条件进⾏响应。
//回调函数

int Add(int x, int y)
{
return x + y;
}

void test(int (*pf)(int, int))
{
int r = pf(10, 20);
printf("%d\n", r);
}

int main()
{
test(Add);

return 0;
}

改写计算器代码

void menu()

{

printf("****************************\n");

printf("****** 1. add 2. sub ******\n");

printf("****** 3. mul 4. div ******\n");

printf("****** 0. exit ******\n");

printf("****************************\n");

}

int Add(int x, int y)

{

return x + y;

}

int Sub(int x, int y)

{

return x - y;

}

int Mul(int x, int y)

{

return x * y;

}

int Div(int x, int y)

{

return x / y;

}

//函数的参数是函数指针,可以接收不同函数的地址

//接收的地址不同,调用的函数就不同

//这个函数根据参数的不同就能完成不同的功能

void Calc(int (*pf)(int, int))

{

int x = 0;

int y = 0;

int r = 0;

printf("请输入两个操作数:");

scanf("%d %d", &x, &y);

//r = (*pf)(x, y);

r = pf(x, y);

printf("%d\n", r);

}

int main()

{

int input = 0;

do

{

menu();

printf("请选择:");

scanf("%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 qsort 使⽤举例

2.1 使⽤qsort函数排序整型数据

qsort是c语言中提供的一个排序函数

quick sort是基于快速排序算法思想的一种排序算法

qsort的好处:

1.现成的排序算法,学会了直接就能使用 ,不需要自己实现了

2.大部分的情况下效率都比冒泡排序高的

  1. qsort函数可以排序任意类型的数据
    我们自己实现过的冒泡排序函数,只能排序整型

利用冒泡排序来演示

冒泡排序

void bubble_sort(int arr[], int sz)

{

//1. 趟数

//2. 一趟内部的比较:比较的对数

int i = 0;

for (i = 0; i < sz - 1; i++)

{

int j = 0;

for (j = 0; j < sz - 1 - i; j++)

{

if (arr[j] > arr[j + 1]) //交换

{

int tmp = arr[j];

arr[j] = arr[j + 1];

arr[j + 1] = tmp;

}

}

}

}

void print_arr(int arr[], int sz)

{

int i = 0;

for (i = 0; i < sz; i++)

{

printf("%d ", arr[i]);

}

printf("\n");

}

void test1()

{

int arr[] = { 3,1,5,8,7,9,2,4,6,0 };

int sz = sizeof(arr) / sizeof(arr[0]);

print_arr(arr, sz);

bubble_sort(arr, sz);

print_arr(arr, sz);

}

int main()

{

test1();

return 0;

}

使用qsort函数排序整型数据

void qsort(void* base, //是指针,指向了被排序数组的第一个元素

size_t num, //base指向的被排序数组的元素个数

size_t size, //base指向的被排序数组的元素的大小(长度),单位是字节

int (*compar)(const void*, const void*)//是什么?函数指针,指针指向的函数是用来比较被排序数组中的两个元素的

);

//cmp_int函数是用来比较两个整型数据的大小的

//p1指向了一个整型数据

//p2指向了一个整型数据

//升序
//int cmp_int(const void* p1, const void*p2)
//{
// if (*(int*)p1 > *(int*)p2)
// return 1;
// else if (*(int*)p1 < *(int*)p2)
// return -1;
// else
// return 0;
//}

//降序
//int cmp_int(const void* p1, const void* p2)
//{
// if (*(int*)p2 > *(int*)p1)
// return 1;
// else if (*(int*)p2 < *(int*)p1)
// return -1;
// else
// return 0;
//}

//升序

int cmp_int(const void* p1, const void* p2)

{

return (*(int*)p1 - *(int*)p2);

}

//降序
//int cmp_int(const void* p1, const void* p2)
//{
// return (*(int*)p2 - *(int*)p1);
//}

#include <stdlib.h>//qsort函数的头文件

//打印

void print_arr(int arr[], int sz)

{

int i = 0;

for (i = 0; i < sz; i++)

{

printf("%d ", arr[i]);

}

printf("\n");

}

//测试qsort函数,排序整型数组

void test2()

{

int arr[] = { 3,1,5,8,7,9,2,4,6,0 };

int sz = sizeof(arr) / sizeof(arr[0]);

print_arr(arr, sz);

//排序

//使用qsort函数的程序员,就得自己写一个比较函数,来比较两个整型数据的大小

qsort(arr, sz, sizeof(arr[0]), cmp_int);

print_arr(arr, sz);

}

int main()

{

test2();

return 0;

}

2.2 使⽤qsort排序结构数据

介绍结构指针和结构体成员访问操作符 -> ;

//一

struct Stu

{

char name[30];

int age;

};

void test(struct Stu* ps)

{

//printf("%s\n", (*ps).name);
//printf("%d\n", (*ps).age);

printf("%s\n", ps->name);//结构体成员访问操作符:-> 结构体指针->成员名

printf("%d\n", ps->age);

}

void test3()

{

struct Stu s = { "zhangsan", 20 };

//printf("%s\n", s.name);
//printf("%d\n", s.age);

test(&s);

}

int main()

{

test3();

return 0;

}

//二

//年龄

struct Stu

{

char name[30];

int age;

};

//按照年龄来比较

//p1指向了一个结构体变量

//p2指向了一个结构体变量
//int cmp_stu_by_age(const void* p1, const void* p2)
//{
// return (*(struct Stu*)p1).age - (*(struct Stu*)p2).age;
//}

int cmp_stu_by_age(const void* p1, const void* p2)

{

return (((struct Stu*)p1)->age - ((struct Stu*)p2)->age);

}

//打印

void print_stu(struct Stu arr[], int sz)

{

int i = 0;

for (i = 0; i < sz; i++)

{

printf("%s: %d\n", arr[i].name, arr[i].age);

}

printf("\n");

}

//测试qsort函数排序结构体数据

void test4()

{

struct Stu arr[] = { {"zhangsan", 20},{"lisi", 38},{"wangwu", 18} };

int sz = sizeof(arr) / sizeof(arr[0]);

qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);

print_stu(arr, sz);

}

int main()

{

test4();

return 0;

}

//三

//名字

//strcmp的头文件#include <string.h>

struct Stu

{

char name[30];

int age;

};

//两个字符串在比较大小的时候,不能使用> >= < <= == !=

//应该使用strcmp()

int cmp_stu_by_name(const void* p1, const void* p2)

{

//return strcmp(((struct Stu*)p2)->name, ((struct Stu*)p1)->name);//降序

return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);//升序

}

//打印

void print_stu(struct Stu arr[], int sz)

{

int i = 0;

for (i = 0; i < sz; i++)

{

printf("%s: %d\n", arr[i].name, arr[i].age);

}

printf("\n");

}

//测试qsort函数排序结构体数据

void test5()

{

struct Stu arr[] = { {"zhangsan", 20},{"lisi", 38},{"wangwu", 18} };

int sz = sizeof(arr) / sizeof(arr[0]);

qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);

print_stu(arr, sz);

}

int main()

{

test5();

return 0;

}

3 qsort函数的模拟实现

使⽤回调函数,模拟实现qsort(采⽤冒泡的⽅式)。

//一
//升序
int cmp_int(const void* p1, const void* p2)
{
return (*(int*)p1 - *(int*)p2);
}

void Swap(char* buf1, char* buf2, size_t width)
{
int i = 0;
char tmp = 0;
for (i = 0; i < width; i++)
{
tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}

//排序任意类型的数据 - 泛型编程
//但是底层还是冒泡排序的算法思想
void bubble_sort2(void* base, size_t sz, size_t width, int (*cmp)(const void* p1, const void* p2))
{
//1. 趟数
//2. 一趟内部的比较:比较的对数
int i = 0;
for (i = 0; i < sz - 1; i++)
{
int j = 0;
for (j = 0; j < sz - 1 - i; j++)
{
//if (arr[j] > arr[j + 1]) //交换
if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
{
//交换arr[j], arr[j + 1]
Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
}
}
}
}
//打印
void print_arr(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
void test6()
{
int arr[] = { 3,1,5,8,7,9,2,4,6,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
print_arr(arr, sz);
bubble_sort2(arr, sz, sizeof(arr[0]), cmp_int);
print_arr(arr, sz);
}
int main()
{
test6();
return 0;
}

//二

//年龄

struct Stu

{

char name[30];

int age;

};

void Swap(char* buf1, char* buf2, size_t width)

{

int i = 0;

char tmp = 0;

for (i = 0; i < width; i++)

{

tmp = *buf1;

*buf1 = *buf2;

*buf2 = tmp;

buf1++;

buf2++;

}

}

int cmp_stu_by_age(const void* p1, const void* p2)

{

return (((struct Stu*)p1)->age - ((struct Stu*)p2)->age);

}

//排序任意类型的数据 - 泛型编程

//但是底层还是冒泡排序的算法思想

void bubble_sort2(void* base, size_t sz, size_t width, int (*cmp)(const void* p1, const void* p2))

{

//1. 趟数

//2. 一趟内部的比较:比较的对数

int i = 0;

for (i = 0; i < sz - 1; i++)

{

int j = 0;

for (j = 0; j < sz - 1 - i; j++)

{

//if (arr[j] > arr[j + 1]) //交换

if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)

{

//交换arr[j], arr[j + 1]

Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);

}

}

}

}

//打印

void print_stu(struct Stu arr[], int sz)

{

int i = 0;

for (i = 0; i < sz; i++)

{

printf("%s: %d\n", arr[i].name, arr[i].age);

}

printf("\n");

}

void test7()

{

struct Stu arr[] = { {"zhangsan", 20},{"lisi", 38},{"wangwu", 18} };

int sz = sizeof(arr) / sizeof(arr[0]);

bubble_sort2(arr, sz, sizeof(arr[0]), cmp_stu_by_age);

print_stu(arr, sz);

}

int main()

{

test7();

return 0;

}

//三

//名字

struct Stu

{

char name[30];

int age;

};

void Swap(char* buf1, char* buf2, size_t width)

{

int i = 0;

char tmp = 0;

for (i = 0; i < width; i++)

{

tmp = *buf1;

*buf1 = *buf2;

*buf2 = tmp;

buf1++;

buf2++;

}

}

//两个字符串在比较大小的时候,不能使用> >= < <= == !=

//应该使用strcmp()

int cmp_stu_by_name(const void* p1, const void* p2)

{

return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);

}

//排序任意类型的数据 - 泛型编程

//但是底层还是冒泡排序的算法思想

void bubble_sort2(void* base, size_t sz, size_t width, int (*cmp)(const void* p1, const void* p2))

{

//1. 趟数

//2. 一趟内部的比较:比较的对数

int i = 0;

for (i = 0; i < sz - 1; i++)

{

int j = 0;

for (j = 0; j < sz - 1 - i; j++)

{

//if (arr[j] > arr[j + 1]) //交换

if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)

{

//交换arr[j], arr[j + 1]

Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);

}

}

}

}

//打印

void print_stu(struct Stu arr[], int sz)

{

int i = 0;

for (i = 0; i < sz; i++)

{

printf("%s: %d\n", arr[i].name, arr[i].age);

}

printf("\n");

}

void test8()

{

struct Stu arr[] = { {"zhangsan", 20},{"lisi", 38},{"wangwu", 18} };

int sz = sizeof(arr) / sizeof(arr[0]);

bubble_sort2(arr, sz, sizeof(arr[0]), cmp_stu_by_name);

print_stu(arr, sz);

}

int main()

{

test8();

return 0;

}

相关推荐
居然是阿宋8 分钟前
C语言的中断 vs Java/Kotlin的异常:底层机制与高级抽象的对比
java·c语言·kotlin
zhangpeng4555479409 分钟前
数据结构-非线性结构-二叉树
数据结构
sco528220 分钟前
SpringBoot 自动装配原理 & 自定义一个 starter
java·spring boot·后端
曼岛_28 分钟前
[Java实战]Spring Boot 快速配置 HTTPS 并实现 HTTP 自动跳转(八)
java·spring boot·http
_Itachi__39 分钟前
LeetCode 热题 100 543. 二叉树的直径
java·算法·leetcode
风吹落叶32571 小时前
线程的一些事(2)
java·java-ee
是代码侠呀1 小时前
飞蛾扑火算法matlab实现
开发语言·算法·matlab·github·github star·github 加星
weixin_428498491 小时前
在Lua中使用轻量级userdata在C/C++之间传递数据和调用函数
c语言·c++·lua
养军博客2 小时前
Spring boot 简单开发接口
java·spring boot·后端
C++ 老炮儿的技术栈2 小时前
C++中什么是函数指针?
c语言·c++·笔记·学习·算法