C/C++学习笔记——C提高: 函数指针和递归函数

函数指针

函数类型

通过什么来区分两个不同的函数?
一个函数在编译时被分配一个入口地址,这个地址就称为函数的指针,函数名代表函数的入口地址。
函数三要素: 名称、参数、返回值。C语言中的函数有自己特定的类型。
c语言中通过typedef为函数类型重命名:

typedef int f(int, int);		// f 为函数类型
typedef void p(int);		// p 为函数类型

这一点和数组一样,因此我们可以用一个指针变量来存放这个入口地址,然后通过该指针变量调用函数。
注意:通过函数类型定义的变量是不能够直接执行,因为没有函数体。只能通过类型定义一个函数指针指向某一个具体函数,才能调用。

typedef int(p)(int, int);

void my_func(int a,int b){
	printf("%d %d\n",a,b);
}

void test(){

	p p1;
	//p1(10,20); //错误,不能直接调用,只描述了函数类型,但是并没有定义函数体,没有函数体无法调用
	p* p2 = my_func;
	p2(10,20); //正确,指向有函数体的函数入口地址
}

函数指针(指向函数的指针)

  • 函数指针定义方式(先定义函数类型,根据类型定义指针变量);
  • 先定义函数指针类型,根据类型定义指针变量;
  • 直接定义函数指针变量;
int my_func(int a,int b){
	printf("ret:%d\n", a + b);
	return 0;
}

//1. 先定义函数类型,通过类型定义指针
void test01(){
	typedef int(FUNC_TYPE)(int, int);
	FUNC_TYPE* f = my_func;
	//如何调用?
	(*f)(10, 20);
	f(10, 20);
}

//2. 定义函数指针类型
void test02(){
	typedef int(*FUNC_POINTER)(int, int);
	FUNC_POINTER f = my_func;
	//如何调用?
	(*f)(10, 20);
	f(10, 20);
}

//3. 直接定义函数指针变量
void test03(){
	
	int(*f)(int, int) = my_func;
	//如何调用?
	(*f)(10, 20);
	f(10, 20);
}

函数指针数组

函数指针数组,每个元素都是函数指针。

void func01(int a){
	printf("func01:%d\n",a);
}
void func02(int a){
	printf("func02:%d\n", a);
}
void func03(int a){
	printf("func03:%d\n", a);
}

void test(){

#if 0
	//定义函数指针
	void(*func_array[])(int) = { func01, func02, func03 };
#else
	void(*func_array[3])(int);
	func_array[0] = func01;
	func_array[1] = func02;
	func_array[2] = func03;
#endif

	for (int i = 0; i < 3; i ++){
		func_array[i](10 + i);
		(*func_array[i])(10 + i);
	}
}

函数指针做函数参数(回调函数)

函数参数除了是普通变量,还可以是函数指针变量。

//形参为普通变量
void fun( int x ){}
//形参为函数指针变量
void fun( int(*p)(int a) ){}
函数指针变量常见的用途之一是把指针作为参数传递到其他函数,指向函数的指针也可以作为参数,以实现函数地址的传递。
//加法计算器
int plus(int a,int b){
	return a + b;
}

//减法计算器
int minus(int a,int b){
	return a - b;
}

//计算器
#if 0
int caculator(int a,int b,int(*func)(int,int)){
	return func(a, b);
}
#else
typedef int(*FUNC_POINTER)(int, int);
int caculator(int a, int b, FUNC_POINTER func){
	return func(a, b);
}
#endif

注意:函数指针和指针函数的区别:

  • 函数指针是指向函数的指针;
  • 指针函数是返回类型为指针的函数;

递归函数

递归函数基本概念

C通过运行时堆栈来支持递归函数的实现。递归函数就是直接或间接调用自身的函数。

普通函数调用

void funB(int b){
	printf("b = %d\n", b);
}

void funA(int a){
	funB(a - 1);
	printf("a = %d\n", a);
}

int main(void){
	funA(2);
    printf("main\n");
	return 0;
}

函数的调用流程如下:
在这里插入图片描述

递归函数调用

void fun(int a){
	
	if (a == 1){
		printf("a = %d\n", a);
		return; //中断函数很重要
	}

	fun(a - 1);
	printf("a = %d\n", a);
}

int main(void){
	
	fun(2);
	printf("main\n");

	return 0;
}

函数的调用流程如下:
在这里插入图片描述

作业:

递归实现给出一个数8793,依次打印千位数字8、百位数字7、十位数字9、个位数字3。

void recursion(int val){
	if (val == 0){
		return;
	}
	int ret = val / 10;
	recursion(ret);
	printf("%d ",val % 10);
}

递归实现字符串反转

int reverse1(char *str){
	if (str == NULL)
	{
		return -1;
	}

	if (*str == '\0') // 函数递归调用结束条件
	{
		return 0;
	}
	
	reverse1(str + 1);
	printf("%c", *str);

	return 0;
}

char buf[1024] = { 0 };  //全局变量

int reverse2(char *str){
	if (str == NULL) 
	{
		return -1;
	}

	if ( *str == '\0' ) // 函数递归调用结束条件
	{
		return 0;
	}

	reverse2(str + 1);
	strncat(buf, str, 1);

	return 0;
}

int reverse3(char *str, char *dst){
	if (str == NULL || dst == NULL) 
	{
		return -1;
	}

	if (*str == '\0') // 函数递归调用结束条件
	{
		return 0;
	}

	reverse3(str + 1);

	strncat(dst, str, 1);

	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章