4.2.6 把函数作为函数的参数

把函数作为函数的参数,有一个非常典型的应用--排序
C语言的stdlib.h中有一个叫qsort的库函数,实现了著名的快速排序算法,他的声明是这样的
void qsort(void* base, size_t num, size_t size, int (*comparator)(const void*, const void*));
前三个参数分别是待排序的数组起始地址,元素个数和每个元素的大小
size_t 类型应该是其中自定义的类型,类似存储整数的数据结构(待商榷)
最后一个参数比较特别,是一个指向函数的指针,该函数应当具有这样的形式
int cmp(const void*, const void*){...}
这里的新内容是指向常数的“万能”的指针: const void*,它可以通过强制类型转化成任意类型的指针,对于古老的密码这道题来说排序的对象是整型数组,因此要这样写:
int cmp(const void* a, const void* b){
return *(int *)a - *(int *)b;
}
一般的,需要先把参数a和b转化为真实的类型,然后让cmp函数当a<b,a=b,a>b是分别返回负数,0和整数就可以了,虽然qsort是C元以内的标准函数,但在算法竞赛中一般不使用他,而是使用C++中的sort函数
总之,将一个函数作为参数传递给另外一个参数是很有用的

古老的密码AC代码:

点击查看代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char s1[105], s2[105];
int cnt1[26], cnt2[26];
int cmp(const void* a, const void* b)
{
	return *(int *)a - *(int *)b;
}

void paint(int* s)
{
	for(int i = 0; i < 26; i++)
		printf("%d ", s[i]);	
	printf("\n");
}

int main()
{
	while(scanf("%s%s", s1, s2) == 2)
	{
		memset(cnt1, 0, sizeof(cnt1));
		memset(cnt2, 0, sizeof(cnt2));
		int flag = 1;
		for(int i = 0; i < strlen(s1); i++)
		{
			cnt1[s1[i] - 'A']++;
			cnt2[s2[i] - 'A']++;
		}
		qsort(cnt1, 26, sizeof(int), cmp);
		qsort(cnt2, 26, sizeof(int), cmp);
		for(int i = 0; i < 26; ++i)
		{
			if(cnt1[i] != cnt2[i])
			{
				flag = 0;
				printf("NO\n");
				break;
			}
		}
		if(flag)
			printf("YES\n");
	}
	return 0;
} 

void*指针可以强制转化为其他任意类型的指针,可以理解为void指针是一张白纸,原先只是存储了变量的基本信息,类似于首元素的地址等,但是后面的信息,类似于所占的字节数等问题需要强制转化类型才可以实现,也就是void是一个万能的接口,其功能实现非常强大
但是好像指向常量的void型指针可以改变常量的值(待商榷)

点击查看代码
#include<stdio.h>

int main()
{
	const int b = 10;
	const void* a = &b;
	*(int *) a = 100;
	printf("%d %d\n", *(int*)a, b);	//100 10
	printf("%d %d %d\n", a, (int*)a, &b);//6487572 6487572 6487572
	const char s[10] = "abcde";
	const void* c = s;
	*(char*)c = 'e';
	printf("%c %c\n", *(char*)c, s[0]);//e e
	printf("%s %s\n", (char*)c, s);//ebcde ebcde
	return 0;	
} 

注意以上的代码的实现是因为笔者是通过c++编译器来编译的,注意在C语言中编写的话,就会产生改变其指针所指向的值,如果在C++中编译的话,就会产生上述的结果
注意:这边将会解释上述程序为什么会产生改变常量的结果
笔者认为(可能并不是真的,只是一种比较合理的解释),C语言中的数据存放和对于数据类型的定义是分开的,也就是这个数据的存储只是单纯的最简单的数据存储,类似于“abc”其所存储的就是abc,并不会说明他是不是字符串类型,也不会说明他是不是常量等相关信息,而这些信息的存储是在首字母也就是地址这个主要的因素,地址也就是指针中会存放这个数据的数据类型,以及是否是常量等信息,例如将上述的int * 改为 const int * 那么上述的程序就会报错,因为这个时候指针里面的信息说明指针指向的是一个常量,不能再次赋值。所以笔者认为在c语言里面,数据的存储和指针的指向是一个分割但是又有千丝万缕关系的一对相爱相恨的冤家。

posted @   banyanrong  阅读(316)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示