【C语言】深入理解函数指针和函数指针数组

(一)什么是函数指针

(1)函数指针的定义

  • 简单来说,是一种指向函数地址的指针。
  • 定义函数指针语法:
    返回值类型 (*指针名)(形参类型列表);
  • 使用函数指针语法:
    函数指针变量名 = 函数名;
    函数指针变量名 = &函数名;

注意:

  • 函数指针具有类型
    根据所指的函数参数类型、个数、以及返回值的类型不同,所定义的函数指针类型不同
  • 定义也可使用typedef 进行类型重命名
    typedef int (*pfun)(int, int) TYPE_FUN;
    TYPE_FUN 函数指针变量 = 函数名;

(2)函数指针的使用

下面简单使用函数指针,直接调用sum函数

#include <stdio.h>
int sum(int a, int b)
{
    
    
	return  a + b;
}
int main()
{
    
    
	int a =10;
	int b = 20;
	//int (*pfun)(int, int) = sum;
	int (*pfun)(int, int) = &sum;
	//printf("a + b = %d \n", pfun(a, b));
	printf("a + b = %d \n", (*pfun)(a, b));
	return 0;
}

结果:
在这里插入图片描述

(二)回调函数

(1) 回调函数定义

函数形参列表中含有函数指针变量的函数叫做回调函数。

(2) 回调函数的作用

通过回调函数去调用函数指针所指向的函数。

(3)回调函数的使用

  • 众所周知,linux下的多线程的创建函数thread_create(),就是一个回调函数,下面是这个函数的声明,我们简单来看看。
    int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
    我们可以看到函数的第三个形参void *(*start_routine) (void *)这就是一个函数指针,该函数指针形参类型是一个void*类型,函数的返回值也是void*类型
    这个函数就暂时看到这…

  • 下面我们自己编写一个回调函数,并使用它

  1. 写个冒泡排序,从小到大,从大到小两种输出结果,但只能手动调用同一个排序函数
#include <stdio.h>
//从小到大
int SmallToBig(int a, int b)
{
    
    
	return a > b ? 1 : 0;
}
//从大到小
int BigToSmall(int a, int b)
{
    
    
	return a < b ? 1 : 0;
}
void Swap(int* p, int* q)
{
    
    
	int tmp = 0;
	tmp = *p;
	*p = *q;
	*q = tmp;
}
void BubbleSort(int* arr, int len, int (*compare)(int, int))
{
    
    
	if(arr == NULL || compare == NULL || len <= 0)
		return;
	int i = 0;
	int j = 0;
	for(i = 0; i < len - 1; i++)
	{
    
    
		for(j = 0; j < len - i - 1; j++)
		{
    
    
			if((*compare)(arr[j], arr[j + 1]) == 1)
			{
    
    
				Swap(&arr[j], &arr[j + 1]);
			}
		}
	}
}

void ShowArr(int* arr, int len)
{
    
    
	if(arr == NULL || len <= 0) 
		return;
	int i;
	for(i = 0; i < len; i++)
	{
    
    
		printf("%d ", arr[i]);
	}
	printf("\n");
}
int main()
{
    
    
	int arr[] = {
    
    12, 22, 10, 8, 45, 26, 30, 15, 16, 12};
	int len = sizeof(arr) / sizeof(arr[0]);
	
	printf("small to big: ");
	BubbleSort(arr, len, SmallToBig);
	ShowArr(arr, len);	
	
	printf("big to small: ");
	BubbleSort(arr, len, BigToSmall);
	ShowArr(arr, len);
	return 0;
}

结果:
在这里插入图片描述

(三)什么是函数指针数组

  • 是一个数组
  • 是一个存放函数指针的数组

(1)函数指针数组的定义

  • 定义语法:
    • 返回值类型 (*变量名[元素个数])(形参类型..) = {同类型函数名};
    • (推荐写法)typedef 返回值类型 (*函数指针变量名)(参数类型..);
      函数指针变量名 数组名[元素个数];
  • 调用函数指针数组中的函数
    变量名[下标](实参列表);

(2)函数指针数组的使用

分别写出加减乘除的四个函数,将其存放在函数指针数组中,通过数组中的元素来调用四个函数。
代码:

#include <stdio.h>
#include <limits.h>
int sum(int a, int b)
{
    
    
	return a + b;
}

int sub(int a, int b)
{
    
    
	return a - b;
}
int mul(int a, int b)
{
    
    
	return a * b;
}

int div(int a, int b)
{
    
    
	if (b == 0) return INT_MAX;
	return a / b;
}

int main()
{
    
    
	int (*pfun[4])(int, int) = {
    
     &sum, &sub, &mul, &div };

	int a = 100;
	int b = 50;
	printf("a + b = %d\n", pfun[0](a, b));
	printf("a - b = %d\n", pfun[1](a, b));
	printf("a * b = %d\n", pfun[2](a, b));
	printf("a / b = %d\n", pfun[3](a, b));

	return 0;
}

分析:我们来看看函数指针数组中的元素的类型
在这里插入图片描述
结果:
在这里插入图片描述

(四)函数指针实现泛型编程

(1)实现一个输出函数,输出不同类型数组中所有元素

#include <stdio.h>

void Show_Int(const void* vp)
{
    
    
	if(vp == NULL) return;
	const int* p = (const int*)vp;
	printf("%d ", *p);
}

void Show_Char(const void* vp)
{
    
    
	if(vp == NULL) return;
	const char* p = (const char*)vp;
	printf("%c ", *p);
}
void Show_Double(const void* vp)
{
    
    
	if(vp == NULL) return;
	const double* p = (const double*)vp;
	printf("%lf ", *p);
}
//arrname数组名,pfun函数指针,len数组元素个数,elemsize每个元素数据类型的大小	
void ShowArray(const void* arrname, void (*pfun)(const void*), int len, int elemsize)
{
    
    
	if(arrname == NULL || pfun == NULL || len <= 0)
		return;
	if(elemsize < 1 || elemsize > 8) 
		return;
	int i;
	const char* tmp = (const char*)arrname;
	for(i = 0; i < len; i++)
	{
    
    
		(*pfun)(tmp);
		tmp += elemsize;
	}
	printf("\n");
	
}

void Test()
{
    
    
	int arr[] = {
    
    1, 2, 3, 4, 5, 6, 7, 9, 10};
	int arr_len = sizeof(arr) / sizeof(arr[0]);
	ShowArray(arr, Show_Int, arr_len, sizeof(int));
	
	char crr[] = {
    
    'h', 'e' , 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd', '\0'};
	int crr_len = sizeof(crr) / sizeof(crr[0]);
	ShowArray(crr, Show_Char, crr_len, sizeof(char));
	
	double drr[] = {
    
    1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7};
	int drr_len = sizeof(drr) / sizeof(drr[0]);
	ShowArray(drr, Show_Double, drr_len, sizeof(double));
}

int main()
{
    
    
	Test();
	return 0;
}

结果:
在这里插入图片描述
(2)使用同一个排序函数,同一个打印函数,将int char类型的数组元素经过排序,打印。

#include <stdio.h>

void Swap_int(void* p, void* q)
{
    
    
	int tmp = (*(int*)p);
	(*(int*)p) = (*(int*)q);
	(*(int*)q) = tmp;
}
void Swap_char(void* p, void* q)
{
    
    
	char tmp = (*(char*)p);
	(*(char*)p) = (*(char*)q);
	(*(char*)q) = tmp;
}

void Swap_double(void* p, void* q)
{
    
    
	double tmp = (*(double*)p);
	(*(double*)p) = (*(double*)q);
	(*(double*)q) = tmp;
}



int Compare_int(const void* a, const void* b)
{
    
    
	return (*(int*)a) > (*(int*)b) ? 1 : 0;
}

int Compare_char(const void* a, const void* b)
{
    
    
	return (*(char*)a) > (*(char*)b) ? 1 : 0;
}

int Compare_double(const void* a, const void* b)
{
    
    
	return (*(double*)a) > (*(double*)a) ? 1 : 0;
}



void BubbleSort(void* arrname, int (*compare)(const void*, const void*), int (*pswap)(const void*, const void*), int len, int elemsize)
{
    
    
	if (arrname == NULL || compare == NULL || pswap == NULL || len <= 0 || elemsize < 1 || elemsize > 8)
		return;
	int i;
	int j;
	
	for (i = 0; i < len - 1; i++)
	{
    
    
		char* start = (char*)arrname;
		for (j = 0; j < len - i - 1; j++)
		{
    
    
			if (compare(start, start + elemsize))
			{
    
    
				pswap(start, start + elemsize);
			}
			start += elemsize;
		}
	}
}

void Show_Int(const void* vp)
{
    
    
	if (vp == NULL) return;
	const int* p = (const int*)vp;
	printf("%d ", *p);
}

void Show_Char(const void* vp)
{
    
    
	if (vp == NULL) return;
	const char* p = (const char*)vp;
	printf("%c ", *p);
}
void Show_Double(const void* vp)
{
    
    
	if (vp == NULL) return;
	const double* p = (const double*)vp;
	printf("%lf ", *p);
}


void ShowArray(const void* arrname, void (*pfun)(const void*), int len, int elemsize)
{
    
    
	if (arrname == NULL || pfun == NULL || len <= 0)
		return;
	if (elemsize < 1 || elemsize > 8)
		return;
	int i;
	const char* tmp = (const char*)arrname;
	for (i = 0; i < len; i++)
	{
    
    
		(*pfun)(tmp);
		tmp += elemsize;
	}
	printf("\n");

}

void Test()
{
    
    
	int arr[] = {
    
     2, 1, 3, 0, 8, 5, 7, 6, 10 };
	int arr_len = sizeof(arr) / sizeof(arr[0]);
	BubbleSort(arr, Compare_int, Swap_int, arr_len, sizeof(int));
	ShowArray(arr, Show_Int, arr_len, sizeof(int));

	char crr[] = {
    
     'h', 'e' , 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd' };
	int crr_len = sizeof(crr) / sizeof(crr[0]);
	BubbleSort(crr, Compare_char, Swap_char, crr_len, sizeof(char));
	ShowArray(crr, Show_Char, crr_len, sizeof(char));
	
	//暂不支持double,float类型的数据
	/*
	double drr[] = { 5.1, 2.4, 3.3, 1.4, 5.6, 9.6, 7.5 };
	int drr_len = sizeof(drr) / sizeof(drr[0]);
	BubbleSort(drr, Compare_double, Swap_double, drr_len, sizeof(double));
	ShowArray(drr, Show_Double, drr_len, sizeof(double));
	*/
	
}
int main()
{
    
    
	Test();
	return 0;
}

结果:
暂不支持double、float类型
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/xiaoxiaoguailou/article/details/121423690