【C进阶】回调函数(指针进阶2,详解,小白必看)

这篇具有很好参考价值的文章主要介绍了【C进阶】回调函数(指针进阶2,详解,小白必看)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

6. 函数指针数组

6.1简单计算器

6.2函数指针数组实现计算器

7. 指向函数指针数组的指针(仅作了解即可)

8.回调函数

8.1关于回调函数的理解​编辑

8.1.1用回调函数改良简单计算器

8.2qsort库函数的使用

8.2.1冒泡排序

8.2.2qsort的概念

8.3冒泡排序思想实现qsort


         这篇文章包括但不限于函数指针数组指向函数指针数组的指针,回调函数等知识点的总结。承接着上文指针进阶(1)知识点总结,传送门-- > http://t.csdn.cn/mgVGJ

指针进阶(3):指针和数组笔试题解析总结,传送门--> http://t.csdn.cn/aKVsj 

        如有错误,欢迎大家指点与纠正,感谢你的来访!

6. 函数指针数组

数组是一个存放相同类型数据的存储空间,那我们已经学习了指针数组,
比如:
int * arr [ 10 ];
//数组的每个元素是int*

那要把函数的地址存到一个数组中,那这个数组就叫函数指针数组,那函数指针的数组如何定义呢?

int ( * parr1 [ 10 ])();//1
int * parr2 [ 10 ]();//2
int ( * )() parr3 [ 10 ];//3

 答案是:parr1 //1

parr1 先和 [] 结合,说明 parr1 是数组,数组的内容是什么呢?
int (*)() 类型的函数指针。-->对于一个变量来说去掉它的名字,就是它的类型。
int my_strlen(const char* str)
{
	return 0;
}
int main()
{
  //指针数组
	char* arr[10];
  //数组指针
	int arr2[5] = { 0 };
	int(*p)[5] = &arr2;//p是一个指向数组的指针变量

	//函数指针
    int (*pf)(const char*) = my_strlen;//pf是一个指向函数的函数指针变量
	
	//函数指针数组-存放函数指针的数组
	int (*pfArr[10])(const char*);
    //1.pf先与[10]结合,代表这是一个数组,数组有10个元素;
    //2.去掉pf[10],剩余int (*)(int,int)为数组每个元素的类型--函数指针类型

	return 0;
}

以下三种写法均等价
1.   *(*pf)("abcdef");
2.   pf ("abcdef");
3.   my_strlen("abcdef");

我们通过实现一个计算器的函数来说明,函数指针数组的用途用在哪里:

6.1简单计算器

按照咱们正常的思路,写一个简单的计算器实现整数的加减乘除的功能,应该大致写成这种代码:

【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

那么执行一下,看一下状况如何:

【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

以上出现的问题是,输入0之后,没有立即打印"退出计算器"然后结束程序,而是要继续输入两个操作数之后才打印信息,还顺便打印了个6,这样的代码肯定存在问题,咱们稍微改进一下。

//写一个计算器能完成整数的+ - * /
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 menu()
{
	printf("*************************\n");
	printf("***  1.Add     2.Sub   **\n");
	printf("***  3.Mul     4.Div   **\n");
	printf("***  0.Exit            **\n");
	printf("*************************\n");
}
int main()
{
	int input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;
	do {
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入两个操作数:>");
			scanf("%d %d", &x, &y);
			ret = Add(x, y);
			printf("%d\n", ret);
			break;
		case 2:
			printf("请输入两个操作数:>");
			scanf("%d %d", &x, &y);
			ret = Sub(x, y);
			printf("%d\n", ret);
			break;
		case 3:
			printf("请输入两个操作数:>");
			scanf("%d %d",&x,&y);
			ret = Mul(x, y);
			printf("%d\n", ret);
			break;
		case 4:
			printf("请输入两个操作数:>");
			scanf("%d %d", &x, &y);
			ret = Div(x, y);
			printf("%d\n", ret);
			break;
		case 0:
			printf("退出计算器\n");
			break;
		default :
			printf("选择错误\n");
			break;
		}
	}while(input);
	return 0;
}

执行代码,继续测试:

【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

 问题是解决了,可是又发现新的问题:

【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

 以上的代码的switch case语句太多了,当我想要在这个计数器里面增加: << >> & | ^ && ||等功能,case语句的就会越来越多,那应该怎么去纠正呢?

这时候就要用到函数指针数组了。

例子:

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;
}
int main()
{
	//存放函数指针的数组 - 函数指针数组
	int (*pf[4])(int, int) = {Add,Sub,Mul,Div };
	                        // 0    1   2   3
	int i = 0;
	for (i = 0; i < 4; i++)
	{
		int ret = pf[i](8, 4);
		printf("%d\n", ret);
	}

	return 0;
}

【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

这段代码使用了函数指针数组,将四个运算函数的地址存储在数组中,然后通过循环遍历数组,依次调用四个运算函数进行计算并输出结果。这种方式可以减少代码的重复量,提高代码的可维护性。

 6.2函数指针数组实现计算器

//函数指针数组实现计算器
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 menu()
{
	printf("*************************\n");
	printf("***  1.Add     2.Sub   **\n");
	printf("***  3.Mul     4.Div   **\n");
	printf("***  0.Exit            **\n");
	printf("*************************\n");
}
int main() 
{
	int input = 0;//选择菜单的功能
	int x = 0;
	int y = 0;
	int ret = 0;//用于接收值
   
    //转移表 - 函数指针的数组
	int (*pfArr[5])(int, int) = { NULL,Add,Sub,Mul,Div };
							 //   0    1   2   3    4
	//NULL的作用是为了占用0下标,然后让函数指针数组的元素下标对应上菜单的功能
	do {
		//菜单
		menu();
		//进行选择
		printf("请选择:>");
		scanf("%d", &input);
		//用函数指针数组代替switch
		if (input == 0)
		{
			printf("退出计算器\n");
			return 0;
		}
		else if (input >= 1 && input <= 4)
		{
			printf("请输入两个操作数:>");
			scanf("%d %d",&x,&y);
			ret = (***pfArr[input])(x, y);//其实比函数指针的用法就多了一个[input]
			 //跟函数指针一样,调用函数的时候 * 是没有任何意义的
			printf("%d\n",ret);
		}
		else
		{
			printf("选择错误\n");
		}
	} while (input);
	return 0;
}

【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

函数指针数组是一个数组,其中的元素是函数指针。每个函数指针指向一个特定的函数,可以通过函数指针调用相应的函数。 函数指针数组可以用来解决代码冗余的问题,可以方便地遍历、调用不同的函数,从而简化代码的结构和逻辑,提高代码的可维护性和可扩展性。

函数指针数组的用途:转移表

7. 指向函数指针数组的指针(仅作了解即可)

//指向函数指针数组的指针
int Add(int a, int b)
{
	return a + b;
}
int Sub(int a, int b)
{
	return a - b;
}
int main()
{   //函数指针
	int(*pf)(int, int) = Add;
	//函数指针数组
	int (*pfArr[4])(int, int) = { Add,Sub };
	//指向函数指针数组的指针
	 int (*(*ppfArr)[4])(int,int) = &pfArr;

	 return 0;
}

如何理解指向函数指针数组的指针:

【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

8.回调函数

概念

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。
回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
代码冗余问题:第一版简单的计算器存在的问题
【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

存在着较多逻辑相同,代码冗余的部分。

 这时候就需要用到回调函数解决问题了:

8.1关于回调函数的理解

8.1.1用回调函数改良简单计算器

#include<stdio.h>
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;
}
//将冗余重复部分用Calc函数封装(只用了一个函数),通过这个函数里面传入的函数指针调用计算器函数
void Calc(int(*pf)(int, int))//pf函数指针,传过来哪个函数地址就用哪种类型计算
{
	int x = 0;
	int y = 0;
	int ret = 0;
	printf("请输入两个操作数:>");
	scanf("%d %d", &x, &y);
    ret = pf(x, y);
	printf("%d\n", ret);
}
void menu()
{
	printf("*************************\n");
	printf("***  1.Add     2.Sub   **\n");
	printf("***  3.Mul     4.Div   **\n");
	printf("***  0.Exit            **\n");
	printf("*************************\n");
}
int main()
{
	int input = 0;
	int ret = 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;
}

总结:

回调函数:被作为参数传递的函数,Add、Sub、Mul、Div四个函数就是回调函数,

而Calc函数则是工具人

8.2qsort库函数的使用

8.2.1冒泡排序

回顾一下冒泡排序的过程:

冒泡排序的思想:两两相邻的元素进行比较,假设要排成升序【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

怎么去写冒泡排序的代码:
①由元素个数确定趟数

②由趟数确定比较对数         

③两个元素两两交换排成升序

//冒泡排序 
void bubble_sort(int arr[], int sz)
{
	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");
}
int main()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0};
	//排序
	//使用
	int sz = sizeof(arr) / sizeof(arr[0]);

	bubble_sort(arr, sz);

	print_arr(arr, sz);
	return 0;
}

【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

不足:

但是这个冒泡排序的缺点也很明显,就是只能排整型int

如果遇到浮点型、结构体等类型的数据,就排不了,那么怎么可以解决呢?

这时候就要用到qsort了。

8.2.2qsort的概念

qsort-- quicksort

是一个库函数,是用来排序的库函数使用快速排序的方法

qsort的好处是

1.现成的

2.可以排序任意类型的数据

【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

 【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

qsort是可以排序任意类型的数据

1.比较2个整数的大小,> < ==

//qsort函数的使用者提供这个函数
//qsort 默认是升序
int cmp_int(const void* p1, const void* p2)
{
	return *(int*)p1 - *(int*)p2;
    //排成倒序的话,什么都不用动,只需要return *(int*)p2 - *(int*)p1;//调换顺序即可
}
void print_arr(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}
test1()
{
	int arr[] = { 3,1,5,2,4,9,8,6,5,7 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	//使用qsort来排序整型数组,这里就要提供一个比较函数,这个比较函数能够比较2个整数的大小
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	print_arr(arr, sz);
}
int main()
{
   test1();
}

 【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

2.比较2个字符串,strcmp -->回顾字符串知识:http://t.csdn.cn/V7E9a

3.比较2个结构体数据(学生:张三、李四)指定比较的标准

回顾结构体对象访问成员的知识:http://t.csdn.cn/DVEVj

//测试qsort 排序结构体数据
struct Stu {
	char name[20];
	int age;
};
void print_arr1(struct Stu* arr, int sz)//打印年龄
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		//printf("%d ", (*(arr + i)).age);
		//printf("%d ", (arr+i)->age);
		printf("%d ", arr[i].age);

	}
	printf("\n");
}
void print_arr2(struct Stu*arr, int sz)//打印姓名
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%s ", (arr+i)->name);
		//printf("%s ", (*(arr+i)).name);
		//printf("%s ", arr[i].name);

	}
	printf("\n");
}
//按照年龄来比较
int cmp_stu_by_age(const void*p1,const void* p2)
{
	return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;

}
int cmp_stu_by_name(const void* p1, const void* p2)
{
	return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}
void test2()
{
	struct Stu s[] = { {"zhangsan",30},{"lisi",25},{"wangwu",50} };
	int sz = sizeof(s) / sizeof(s[0]);
	//测试按照年龄来排序
	print_arr1(s, sz);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
	print_arr1(s, sz);
	//测试按照名字来排序
	/*print_arr2(s,  sz);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
	print_arr2(s, sz);*/
}

打印年龄:

【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

打印性别:

【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

8.3冒泡排序思想实现qsort

使用冒泡排序的思想来实现一个类似于qsort这个功能的冒泡排序函数bubble_sort()

【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

各参数组成:
base,num,width,cmp函数,elem1和elem2

接下来说明一下qsort各参数的设计思路:

①为什么base定义为void*类型?

void*是 C 语言中的一种通用指针类型,可以指向任意类型的数据。在 qsort 函数中,由于需要对不同类型的数据进行排序,因此需要使用void*类型的指针,以便能够接受各种类型的数据,base参数是一个指向要排序数组第一个元素的指针。由于它要指向任意类型的数据,所以使用void*是最通用的。

举例:

int a = 10;

void* p = &a;

优点:

无具体类型的指针,所以它可以接收任何类型的地址

缺点:

*p  //-->  void*的指针不能解引用操作符

p++  //-->  因为不知道是什么数据类型,不能直接++

正确用法:

*(int*)p;//也可以转化成其它类型

②为什么num要设计成size_t?

  • size_t 在 C 语言中是一种无符号整数类型,用于表示大小、长度和索引值,使用它表示数组元素个数很合适。
  • 数组元素个数是一个非负的值,使用无符号类型size_t可以避免出现负数,更加合理。

  • 使用专门的 size_t 类型比简单的 unsigned int 更能表明这个参数的语义 - 它表示一个大小或长度,而不是一个整数。

③为什么width要设计成size_t

在qsort函数中,width参数表示每个数组元素的大小(以字节为单位)

  1. width表示一个"大小"的概念,使用size_t类型可以更清楚地表达这个参数的语义。

  2. width的单位是字节,size_t通常是无符号整数类型,不会有负数,所以更适合表示正的值。

  3. width需要足够大的范围来表示任意数据类型的大小。size_t类型依赖平台,但通常是机器字大小,能满足大多数数据元素的大小需求。

  4. 在访问数组元素时,索引位置需要乘以元素大小才能获得地址偏移量。既然索引是size_t类型,那么两者相乘的结果也应该是size_t类型,以避免溢出问题。

④为什么要设计一个函数指针cmp?

  1. qsort 本身是一个通用的排序函数,不能知道要排序的元素类型,也就无法直接比较两个元素。采用函数指针可以将比较操作的实现留给用户。

  2. 通过函数指针,用户可以自行实现针对自己数据类型的比较函数,将具体的比较逻辑封装起来。这提高了qsort的通用性和灵活性。

  3. 对于不同的数据类型,比较操作的逻辑可能不同。使用函数指针实现可以避免在qsort中写大量的条件分支逻辑。

  4. 函数指针提供了一种扩展机制。如果用户需要改变比较操作的逻辑,只需要传入一个新的函数指针就可以,而不需要改动qsort函数本身。

⑤为什么elem1和elem2类型是const void*类型?

  1. qsort要对任意类型的数据进行排序,所以比较函数需要能处理任意类型的元素。使用void*可以指向任意类型的数据,const用于表示不应修改指针指向的内容。

  2. qsort要对任意类型的数据进行排序,所以比较函数需要能处理任意类型的元素。使用void*可以指向任意类型的数据,const用于表示不应修改指针指向的内容。

  3. 在调用qsort时可以直接将数组元素的地址强制转换为const void* 类型传给比较函数,简化调用。

  4. qsort函数本身不需要了解元素具体类型,只要把void*指针传给比较函数,由比较函数转换并解释指针内容即可。

开始模拟实现:冒泡排序大题思路不需要改变,只需要对排序方式进行即可

int cmp_int(const void* p1, const void* p2)
{
	return *(int*)p1 - *(int*)p2;
}
//假设排序为升序
//希望这个bubble_sort函数可以排序任意类型的数据
void Swap(char* buf1, char* buf2, int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}
}

//假设排序为升序
//希望这个bubble_sort函数可以排序任意类型的数据
void bubble_sort(void* base, size_t num, size_t width,
	int (*cmp)(const void* p1, const void* p2))
{
    //冒泡排序大题思路不需要改变,只需要对排序方式进行即可
	//要确定趟数
	size_t i = 0;
	for (i = 0; i < num - 1; i++)
	{
		int flag = 0;//假设已经有序了
		//一趟冒泡排序的过程
		size_t j = 0;
		for (j = 0; j < num - 1 - i; j++)
		{
			//两个相邻的元素比较
			//arr[j] arr[j+1]
			if (cmp((char*)base + j * width, (char*)base+(j+1)*width)>0)
			{
				//交换
				flag = 0;
				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 test3()
{
	int arr[] = { 3,1,5,2,4,9,8,6,5,7 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("排序前:");
	print_arr(arr, sz);
	bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);
	printf("排序后:");
	print_arr(arr, sz);
}

qsort对于代码的解析:

【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

如何交换数据:

为什么这个地方写成char*?

在bubble_sort函数中,由于不知道base指向的数据类型,因此需要将其强制转换为char*类型,从而让指针的步长为1。这样,在进行指针的加减运算时,就可以根据width参数来控制指针的步长,从而实现对任意数据类型的排序。

注意:width对于char来说是1个字节的意思,但是对于其它类型来说就不是了,width是根据参数不同来设置不同的数据类型,控制指针步长的。

交换的流程:1,2,3,4表示顺序 

【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

 代码的整体流程:

【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

排序:

【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

通过新定义的冒泡排序排序年龄以及姓名

struct Stu {
	char name[20];
	int age;
};
int cmp_stu_by_age(const void*p1,const void* p2)
{
	return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;

}
int cmp_stu_by_name(const void* p1, const void* p2)
{
	return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}
void Swap(char* buf1, char* buf2, int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}
}
//假设排序为升序
//希望这个bubble_sort函数可以排序任意类型的数据
void bubble_sort(void* base, size_t num, size_t width,
	int (*cmp)(const void* p1, const void* p2))
{
	//要确定趟数
	size_t i = 0;
	for (i = 0; i < num - 1; i++)
	{
		int flag = 0;//假设已经有序了
		//一趟冒泡排序的过程
		size_t j = 0;
		for (j = 0; j < num - 1 - i; j++)
		{
			//两个相邻的元素比较
			//arr[j] arr[j+1]
			if (cmp((char*)base + j * width, (char*)base+(j+1)*width)>0)
			{
				//交换
				flag = 0;
				Swap((char*)base+j*width,(char*)base+(j+1)*width,width);
			}
		}
	}


}
void print_arr3(struct Stu* s, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", (s + i)->age);
		//printf("%s ", (*(arr+i)).name);
		//printf("%s ", arr[i].name);

	}
	printf("\n");

}
void print_arr4(struct Stu* s, int sz)
{
	int i = 0;
		for (i = 0; i < sz; i++)
		{
			printf("%s ", (s+i)->name);
			//printf("%s ", (*(arr+i)).name);
			//printf("%s ", arr[i].name);
	
		}
		printf("\n");

}
void test4()
{
	struct Stu s[] = { {"zhangsan",30} ,{"lisi",25},{"wangwu",50}};
	int sz = sizeof(s) / sizeof(s[0]);
	//测试按年龄来排序
	/*print_arr3(s, sz);
	bubble_sort(s, sz, sizeof(s[0]), cmp_stu_by_age);
	print_arr3(s, sz);*/
	//测试按照名字来排序
	print_arr4(s, sz);
	bubble_sort(s, sz, sizeof(s[0]), cmp_stu_by_name);
	print_arr4(s, sz);

}

按姓名排序:

【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

 按年龄排序

【C进阶】回调函数(指针进阶2,详解,小白必看),C进阶,c语言,开发语言,笔记,vscode

这篇文章到这里就结束了,如有错误欢迎大家指正,然后下来就是这篇关于sizeof和strlen的详细总结:,指针和数组笔试题解析总结,传送门--> http://t.csdn.cn/aKVsj

欢迎大家来访。文章来源地址https://www.toymoban.com/news/detail-627914.html

到了这里,关于【C进阶】回调函数(指针进阶2,详解,小白必看)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C/C++面向对象(OOP)编程-回调函数详解(回调函数、C/C++异步回调、函数指针)

    本文主要介绍回调函数的使用,包括函数指针、异步回调编程、主要通过详细的例子来指导在异步编程和事件编程中如何使用回调函数来实现。 🎬个人简介:一个全栈工程师的升级之路! 📋个人专栏:C/C++精进之路 🎀CSDN主页 发狂的小花 🌄人生秘诀:学习的本质就是极致

    2024年02月03日
    浏览(39)
  • 【C语言】——指针五:转移表与回调函数

    1.1、转移表的定义      在之前的学习中,我们学习了 函数指针数组 (详情请看【C语言】——指针四:字符指针与函数指针变量),在最后。我曾问到:函数指针数组有什么用呢?别急,本文给大家细细道来。      函数指针数组常常被用在 转移表 中,那转移表是

    2024年03月26日
    浏览(43)
  • C 语言高级3--函数指针回调函数,预处理,动态库的封装

    目录 1.函数指针和回调函数 1.1 函数指针 1.1.1 函数类型 1.1.2 函数指针(指向函数的指针) 1.1.3 函数指针数组        1.1.4 函数指针做函数参数(回调函数)  2.预处理 2.1 预处理的基本概念 2.2 文件包含指令(#include) 2.2.1 文件包含处理  2.2.2 #incude和#include\\\"\\\"区别 2.3 宏定义 2.3.1 无参

    2024年02月14日
    浏览(38)
  • 【C语言】指针进阶:字符指针&&数组指针&&函数指针

    ✨作者:@平凡的人1 ✨专栏:《C语言从0到1》 ✨一句话:凡是过往,皆为序章 ✨说明: 过去无可挽回, 未来可以改变 🌹 感谢您的点赞与关注,同时欢迎各位有空来访我的 🍁平凡舍 回想之前,我们学了 指针 的一些基础👉 指针与结构体 我们知道了指针的概念: 指针就是

    2023年04月08日
    浏览(43)
  • 计算字符串的长度几种方法 | 递归 | 指针减指针 | 计数器 | C语言 | 详解 | 期末考试必看!!!

    1,题目描述 2,分析题目 Ⅰ,题目中要求 除了函数的形参,函数中不能够使用多余的变量 (这是比较 苛刻 的要求)。 Ⅱ,根据此,很自然的想到需要使用 递归 来解决问题。 Ⅲ, 字符串的结束标志是\\\'\\0\\\',因此可以将 读取到\\\'\\0\\\' 作为结束条件 3,关于递归的基本知识 Ⅰ,递

    2024年02月03日
    浏览(51)
  • Go语言进阶:函数、指针、错误处理

    函数是基本的代码块,用于执行一个任务。 Go 语言最少有个 main() 函数。 你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。 函数声明包括函数名﹑形式参数列表﹑返回值列表(可省略)以及函数体。 形式参数列表描逑了函数的参数名以及参数类型。这

    2024年02月12日
    浏览(40)
  • 【C语言进阶(五)】指针进阶详解(上)

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:C语言学习分享⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习更多C语言知识   🔝🔝 本篇文章将讲解以下几个方面内容: 字符指针 数组指针 指针数组 数组传参和指针传参 函数指针 在这之前先温故一下指针的概念

    2024年02月12日
    浏览(62)
  • C语言——指针详解(进阶)

    前言: 学完 C语言初阶 后,应该对指针有了初步的了解,下面学习进阶的内容,让我们更快的掌握C语言指针。 指针的概念: 指针就是一个变量,用来存放地址,地址与内存空间一一对应 指针的大小是固定的4/8个字节(32位平台/64位平台) 指针是有类型的,指针的类型决定

    2024年02月16日
    浏览(37)
  • C语言:指针详解【进阶】后篇

    前言: 在C语言:指针详解【进阶】前篇中我们深入学习了 字符指针 , 数组指针 , 指针数组 以及 数组传参和指针传参 。我们对指针的应用有了较为深刻的认识,今天这里我们将更加深入的进行对更复杂的指针的探究。 在前面我们知道一个指针变量可以指向一块内存的地

    2024年02月05日
    浏览(34)
  • 【C语言】回调函数,qsort排序函数的使用和自己实现,超详解

    先记录一下访问量突破2000啦,谢谢大家支持!!! 这里是上期指针进阶链接,方便大家查看:添加链接描述 大家好呀,今天分享一下上期指针进阶中剩余的内容——回调函数,这个很重要滴,让我们一起来学会学懂他吧!!! 标准概念: 回调函数就是一个通过函数指针调

    2024年02月12日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包