函数指针数组的简单应用(计算器)以及qsort函数

本文介绍了函数指针数组的概念和简单应用,展示了如何使用函数指针数组简化代码,以及回调函数的原理。同时,讨论了C语言中的qsort函数,包括其参数和工作原理,并给出了模拟qsort的冒泡排序实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1.函数指针数组

2.函数指针数组的简单应用

2.qsort函数

3.qsort的模拟实现


1.函数指针数组

函数指针数组是存放函数指针的数组,其本质上还是数组,其中的元素为函数指针。

int test(int a,int b)
{
   return a+b;
}

int(*p)(int,int)=test;

我们可知p为函数test的指针,那函数指针数组应该怎么写呢?

int(*p1[1])(int,int)={p};

这需要在函数指针的基础上进行书写,只要在指针名的后面加上数组的大小即可。

分析:p1先与[]结合,说明p是数组,将数组取出,剩下:int (*)(int,int),这表示数组中的元素都为函数指针,函数返回值为int类型。

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;

}

我们首先想到的就是用switch语句进行不同分支的判断,然后再使用相应功能的函数进行计算。

int main()
{
	int num = 0;
	do
	{
		menu();
		scanf_s("%d", &num);
		switch (num)
		{
		case 0:
			printf("exit!\n");
			break;
		case 1:
			printf("请输入操作数:");
	        scanf_s("%d %d", &a, &b);
	        int ret = add(a, b);
	        printf("%d\n", ret);
			break;
		case 2:
			printf("请输入操作数:");
	        scanf_s("%d %d", &a, &b);
	        int ret = sub(a, b);
	        printf("%d\n", ret);
			break;
		case 3:
			printf("请输入操作数:");
	        scanf_s("%d %d", &a, &b);
	        int ret = mul(a, b);
	        printf("%d\n", ret);
			break;
		case 4:
			printf("请输入操作数:");
	        scanf_s("%d %d", &a, &b);
	        int ret = div(a, b);
	        printf("%d\n", ret);
			break;
		default:
			printf("请重新输入:");
		}
	} while (num);
	return 0;
}

正如这段代码所示,虽然可以成功实现功能,但代码冗余度太大,我们仔细观察,会发现每次进入case后,只有调用的函数不同,其余都相同,因此我们可以利用函数指针数组来简化代码。

int main()
{
	int num = 0;
	int a = 0;
	int b = 0;
	int ret = 0;
	do
	{
		menu();
		printf("请输入:");
		scanf_s("%d", &num);
		int(*ptarr[5])(int, int) = { 0,add,sub,mul,div };
		if (num > 0 && num < 5)
		{
			printf("请输入操作数:");
			scanf_s("%d %d", &a, &b);
			ret = ptarr[num](a, b);
			printf("%d\n", ret);
		}
		else if (num == 0)
			printf("exit!\n");
		else
			printf("请重新输入:\n");
	} while (num);
	return 0;
}

我们使用一个函数指针数组存放这四种运算,通过输入下标来调用相对应的函数来实现对应的功能。这样做就减少了冗余度,提高了代码的通用性。

除这两种方法之外,我们还可以利用回调函数来实现。

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

//回调函数;通过调用函数指针来实现被调用函数的功能
void crl(int(*p)(int, int))//形参为函数指针,p为函数指针,指向被调用函数
{
	int a = 0;
	int b = 0;
	printf("请输入操作数:");
	scanf_s("%d %d", &a, &b);
	int ret = p(a, b);//利用函数指针
	printf("%d\n", ret);
}


int main()
{
	int num = 0;
	do
	{
		menu();
		scanf_s("%d", &num);
		switch (num)
		{
		case 0:
			printf("exit!\n");
			break;
		case 1:
			crl(add);
			break;
		case 2:
			crl(sub);
			break;
		case 3:
			crl(mul);
			break;
		case 4:
			crl(div);
			break;
		default:
			printf("请重新输入:");
		}
	} while (num);
	return 0;
}

我们把重复的部分写成一个函数crl,形参为函数指针,所传入的实参为加减乘除的四个函数的地址。当我们想使用不同功能时,直接调用crl,只需要改变传入的实参部分即可。

2.qsort函数

void qsort (void* base, //指向了需要排序的数组的第一个元素
           size_t num, //排序的元素个数
           size_t size,//一个元素的大小,单位是字节
           int (*cmp)(const void*, const void*)//函数指针类型 - 这个函数指针指向的函数,能够比较base指向数组中的两个元素
           );

我们可以从cplusplus中得到qsort函数的定义,他的形参部分由以下四部分组成:指向需要排序数组首元素的无类型指针,需要排序的元素个数,一个元素的大小,指向一个可以实现比较功能的函数的指针。

以下为示例:

//qsort整形排序
int cmplete(const void* p1, const void* p2)
{
	return(*(int*)p1 - *(int*)p2);
}

void print(int arr[],int sz)

for (int i = 0; i < sz; i++)
	printf("%d ", arr[i]);


void test1()
{
	int arr[] = { 0,7,9,8,6,5,4,3,5,2,4,6,7 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmplete);
	print(arr, sz);
}

3.qsort的模拟实现

我们接下来用冒泡排序的思想来模拟实现qsort函数。

冒泡排序法:

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;
	     		}
			}
		}
	}

我们从中可以看到冒泡排序是有局限性的,它只能够排序整形,其他类型的就不能适用了。

用冒泡排序的思想模拟qsort有以下几点难处:

1.不确定数组类型

2.如何比较相邻两个元素的大小

3.如何交换相邻元素

以下是解决思路:

问题一:不确定数组类型

方法:我们将形参中的首地址元素改为void*类型,之后在使用时强转回所需类型(对应qsort函数形参中第一项)

问题二:如何比较相邻两个元素的大小

因为每种类型的比较方法大不相同,所以需要我们自己设计比较函数,(对应qsort函数形参中第四项)

问题三:如何交换相邻元素

因为每种类型的大小各不相同,因此,我们需要知道数组中的元素大小,然后一个字节一个字节的交换,最终实现交换相邻元素。(对应qsort函数形参中第三项)

以下代码为模拟qsort函数整形比较:

//测试整形比较
int cmp(void* p1, void* p2)//比较函数
{
	return(*(int*)p1 - *(int*)p2);
}

void swap(char* p1, char* p2,int size)//交换arr[j],arr[j+1],一个字节一个字节交换
{
	int i = 0;
	char tmp = 0;
	for (i = 0; i < size; i++)
	{
		tmp = *p1;
		*p1 = *p2;
		*p2 = tmp;
		p1++;
		p2++;
	}
}
void my_qsort(void* base, int sz, int size, int (*cmp)(void* , void* ))
{
	int i = 0;
	int j = 0;
	for (i = 0; i < sz; i++)
	{
		for (j = 0; j < sz - 1 - i; j++)
		{
			//假设升序cmp返回>0,交换
			if ((cmp((char*)base + size * j, (char*)base + size * (j + 1))) > 0)//比较大小,需要比较数的地址,用char为基础得到地址
			{
				swap((char*)base + size * j, (char*)base + size * (j + 1),size);
			}
		}
	}
}

void test()
{
	int arr[] = { 0,7,9,8,6,5,4,3,5,2,4,6,7 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	my_qsort(arr, sz, sizeof(arr[0]), cmp);
	print(arr,sz);
}

感谢您的观看!

本人拙见,大佬勿怪  ^v^

<think>嗯,用户想了解Excel中的VLOOKUP函数的用法和参数含义。首先,我需要回忆一下VLOOKUP的基本结构。VLOOKUP是垂直查找函数,用于在表格的首列查找指定的值,然后返回该行中指定列的数据。它的四个参数分别是查找值、表格范围、列索引号和匹配模式。 接下来,我得确认每个参数的具体作用。第一个参数是lookup_value,也就是用户要查找的值,比如产品ID或者姓名。第二个参数是table_array,即查找的范围,这里要注意的是,查找值必须位于这个范围的第一列,否则函数无法正确工作。第三个参数是col_index_num,也就是用户想要返回的数据在表格范围中的第几列,这个列数是从表格范围的第一列开始算起的,不是整个工作表的列。第四个参数是range_lookup,决定是精确匹配还是近似匹配,通常用FALSE或0来指定精确匹配,避免错误。 然后,用户可能需要一个具体的例子来理解如何使用。比如,假设有一个产品价格表,用户想根据产品ID查找对应的价格。这时候,VLOOKUP就可以在ID列查找,然后返回价格列的数据。同时,要提醒用户注意表格范围最好使用绝对引用,比如$A$2:$C$100,这样在拖动公式时范围不会变化。 可能遇到的问题也需要考虑。比如,如果查找值不在表格的第一列,或者列索引号超过了表格的列数,函数会返回错误。此外,数据格式不一致也可能导致问题,比如查找值是数字,而表格中是文本格式的数字,这时候需要统一格式。还有,当出现#N/A错误时,可能是查找值不存在,或者匹配模式设置不正确,需要检查参数是否正确。 用户可能还会问到如何避免常见的错误,比如部分数据匹配出错的情况。这时候需要检查是否有多余的空格,或者数据格式不一致,或者表格范围没有锁定导致拖动时偏移。此外,XLOOKUP作为VLOOKUP的升级版,可能在某些情况下更方便,比如可以向左查找或者返回多列数据,这也是可以提及的内容。 最后,整理步骤,从基础语法到参数说明,再到具体案例,逐步引导用户理解如何使用VLOOKUP函数。同时,提供常见错误和解决方法,帮助用户在实际应用中避免问题。如果有必要,还可以比较VLOOKUP和其他查找函数的区别,比如HLOOKUP或XLOOKUP,但根据用户的问题,主要集中在VLOOKUP本身即可。</think>### Excel VLOOKUP函数详解 #### 一、基础语法与参数说明 VLOOKUP函数的语法为: $$=VLOOKUP(lookup\_value, table\_array, col\_index\_num, [range\_lookup])$$ 包含4个参数: 1. **lookup_value**(必填):要查找的值(如单元格引用或具体值) 2. **table_array**(必填):包含数据的表格范围(必须包含查找列和返回列) 3. **col_index_num**(必填):返回值所在列的序号(从table_array第一列开始计数) 4. **range_lookup**(可选):匹配类型 - `TRUE`/`1`:近似匹配(默认值,需数据升序排列) - `FALSE`/`0`:精确匹配(常用选项) [^1][^2] #### 二、使用步骤演示(工资表查询案例) 假设需要根据员工编号查询工资: 1. 建立查询单元格(如`B12`) 2. 输入公式: ```excel =VLOOKUP(A12, $A$2:$D$100, 4, 0) ``` - `A12`:待查询的员工编号 - `$A$2:$D$100`:锁定数据区域(绝对引用) - `4`:返回第4列(工资列) - `0`:精确匹配 [^2][^3] #### 三、常见错误与解决方法 | 错误现象 | 原因 | 解决方案 | |---------|------|---------| | #N/A | 查找值不存在 | 检查数据源或改用`IFERROR`容错 | | #REF! | 列序号超出范围 | 确认col_index_num ≤ 表格列数 | | 部分匹配失败 | 数据格式不一致 | 统一数值/文本格式 | | 结果错位 | 表格未锁定 | 使用`$`符号固定区域引用 | [^3][^4] #### 四、进阶技巧 1. **多条件查询**: 使用辅助列合并多个条件字段 ```excel =VLOOKUP(A2&B2, $D$2:$F$100, 3, 0) ``` 2. **通配符匹配**: `"*"`匹配任意字符,`"?"`匹配单个字符 ```excel =VLOOKUP("张*", $A$2:$C$100, 3, 0) ``` 3. **跨表查询**: 引用其他工作表数据 ```excel =VLOOKUP(A2, Sheet2!$A$2:$D$100, 4, 0) ``` [^1][^4]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值