【C语言】函数指针,函数指针数组小结

  • 理解函数指针和定义

先看一下一段代码:

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
#include <stdlib.h>

void test()
{
	printf("hehe\n");
}

int main()
{
	printf("%p\n", test);
	printf("%p\n", &test);
	system("pause");
	return 0;
}

输出的是两个地址,且是相同的,而此地址就是test函数的地址,那么同理就能使用指针来存储,那么函数指针又是怎么样的呢?

看下面代码:

#define _CRT_SECURE_NO_WARNINGS 1

void test()
{
	printf("hehe\n");
}

int main()
{
	void(*pfun1)();
}

pfun1可以存放,pfun1先和*结合,说明Pfun1是指针,指针指向的是一个函数,指向的函数无参数,返回类型是void。

  • 理解函数指针数组和定义,转移表使用

函数指针数组,顾名思义就是把函数的地址存在一个数组当中,那么这个数组就是函数指针数组。

int(*parr1[10])();

parr1先和[]结合,说明parr1是数组,数组的内容是int(*)()类型的函数指针

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

例子:(原始计算器)

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
#include <stdlib.h>


int Add(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)
{
	return a / b;
}

int main()
{
	int x, y;
	int input = 1;
	int ret = 0;
	while (input)
	{
		printf("*************************\n");
		printf(" *****1:Add   2:Sub *****\n");
		printf(" *****3:Mul   4:Div *****\n");
		printf("*************************\n");
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入操作符:>");
			scanf("%d %d", &x, &y);
			ret = Add(x, y);
			break;
		case 2:
			printf("请输入操作符:>");
			scanf("%d %d", &x, &y);
			ret = Sub(x, y);
			break;
		case 3:
			printf("请输入操作符:>");
			scanf("%d %d", &x, &y);
			ret = Mul(x, y);
			break;
		case 4:
			printf("请输入操作符:>");
			scanf("%d %d", &x, &y);
			ret = Div(x, y);
			break;
		default:
			printf("选择错误\n");
			break;
		}
		printf("ret = %d\n", ret);
	}
	system("pause");
	return 0;
}

(使用转移表之后的计算器)

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int Add(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)
{
	return a / b;
}

int main()
{
	int x, y;
	int input = 1;
	int ret = 0;
	int(*p[5])(int x, int y) = { 0, Add, Sub, Mul, Div }; //转移表,函数指针的使用
	while (input)
	{

		printf("*************************\n");
		printf("**** 1:Add     2:Sub ****\n");
		printf("**** 3:Mul     4:Div ****\n");
		printf("*************************\n");
		printf("请选择:>");
		scanf("%d", &input);
		if ((input < 5 && input > 0))
		{
			printf("请输入操作符:>");
			scanf("%d %d", &x, &y);
			ret = (*p[input])(x, y);
		}
		else
			printf("输入有误!\n");
		printf("ret = %d\n", ret);
	}
	return 0;
}
  • 理解指向函数指针数组的指针和定义

void test(const char* str)
{
	printf("%s\n", str);
}

int main()
{
	//函数指针 pfun
	void(*pfun)(const char*) = test;
	//函数指针的数组 pfunArr
	void(*pfunArr[5])(const char* str);
	pfunArr[0] = test;
	//指向函数指针数组 pfunArr 的指针 ppfunArr
	void(*(*ppfunArr)[10])(const char*) = &pfunArr;
	return 0;
}
  • 理解回调函数的使用

回调函数就是一个通过函数指针调用的函数,如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其他指向的函数时,我们就说这时回调函数,回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时又另一方调用的,用于该事件或条件进行响应。

例子:

练习使用qsort函数排序各种类型的数据以及模仿qsort的功能实现一个通用的冒泡排序。

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

struct Stu
{
	char name[20];
	int age;
};

void print_arr(int *arr, size_t sz)
{
	unsigned int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}

int cmp_int(const void *e1, const void *e2)
{
	return *(int *)e1 - *(int *)e2;
}

int cmp_stu_by_age(const void *e1, const void *e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}

int cmp_stu_by_name(const void *e1, const void *e2)
{
	return strcmp(((struct Stu*)e1)->name , ((struct Stu*)e2)->name);
}

int cmp_str(const void* e1, const void* e2)
{
	return strcmp(*(char**)e1, *(char **)e2);
}

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

void bubble_sort(void *base, int num, int width, int (*cmp)(const void*e1, const void*e2))
{
	int i = 0;
	int j = 0;
	assert(base&&cmp);
	for (i = 0; i < num - 1; i++)
	{
		for (j = 0; j < num - 1 - i; j++)
		{
			if (cmp((char*)base + j*width, (char*)base + (j + 1)*width)>0)
			{
				//交换
				_Swap((char*)base + j*width, (char*)base + (j + 1)*width, width);
			}
		}
	}
}

int main()
{
	////利用qsort测试整型排序
	//int arr[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
	//int sz = sizeof(arr) / sizeof(arr[0]);
	//qsort(arr, sz, sizeof(arr[0]), cmp_int);
	//print_arr(arr, sz);
	//
	////利用qsort测试结构体排序
	//struct Stu arr[] = { { "zhangsan", 20 }, { "lisi", 15 }, { "wangwu", 8 } };
	//int sz = sizeof(arr) / sizeof(arr[0]);
	//qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
	//qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);

	////利用bubble_qsort测试结构体排序
	//struct Stu arr[] = { { "zhangsan", 20 }, { "lisi", 15 }, { "wangwu", 8 } };
	//int sz = sizeof(arr) / sizeof(arr[0]);
	//bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);

	////利用bubble_qsort测试字符串排序
	//char *arr[] = { "abcdef", "qqqqq", "bbbbbb" };
	//int sz = sizeof(arr) / sizeof(arr[0]);
	//bubble_sort(arr, sz, sizeof(arr[0]), cmp_str);

	system("pause");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41562665/article/details/81325509