C语言函数详解(二)

5. 函数的嵌套调用和递归访问

5.1 函数的嵌套调用

我们知道,函数与函数之间是可以嵌套调用的,也就是一个函数中可以调用另一个函数,进行输出等一系列操作

下面我们写一段C语言的代码,来实现函数的嵌套调用

#include <stdio.h>

void print()
{
	printf("Hello world\n");
}

void three_lines()
{
	for (int i = 0; i < 3; i++)
	{
		print();
	}
}

int main()
{
	three_lines();

	return 0;
}

我们不看难出,我们实现了两个函数,第一个执行打印的操作,第二个执行循环的操作,并且在第二个函数中调用了第一个函数。

注:函数可以函数可以嵌套调用,但是不能嵌套定义。

5.2 函数的链式访问

把一个函数的返回值作为另一个函数的参数

这里我们以printf举例,在此之前,我想问一下,同学们知道printf函数的返回值是什么吗?

相信更多人的回答是不知道,那么没关系,我们打开CPP的官网,搜索printf,你会看到以下界面

在这里,我们不看看到,printf的返回值是字符的总数,看到这里,相信大家已经对printf这个函数相当熟悉了,那么我们接下来就进行printf嵌套调用的代码展示

#include <stdio.h>

int main()
{
    printf("%d", printf("%d", printf("%d", 43)));

    //结果是啥?
    //注:printf函数的返回值是打印在屏幕上字符的个数

    return 0;
}

我们不难看出,printf里面又嵌套调用了很多个printf,那么结果到底是啥呢?下面让我们一步一步来看

首先,最后一个printf("%d", 43)的返回值应该是2,对吧?因为43的字符总数是2。

所以这个表达式首先应该输出43,然后它的返回值是2,又作为倒数第二个printf的输入值,所以又输出一个2.

最后2的字符长度为1,所以又输出一个1.

所以最终答案为4321,你做对了吗?

6 函数的定义和声明

6.1 函数的定义

是指函数具体的实现

6.2 函数的声明

不对函数做具体的实现,只声明函数的返回值,函数名以及形式参数

那么就会有人问了,为什么对函数进行声明?我直接在main函数直接就作函数的定义不可以吗?写函数声明还浪费我的时间和空间。

其实不然,在以后我们工作中,不可能所有人都把所有代码都写在一个.cpp文件中,这个时候程序的头文件和源文件就派上用场了,在头文件里只进行函数的声明,在源文件里再进行函数的实现,这样 ,可以大大地提高工作效率,同时分多个模块来写,更容易debug程序。

7 函数的递归

下面就来到了今天的重头戏,函数的递归。

第一次接触的小伙伴,可能对这个概念比较陌生,但是我们不要着急,慢慢理解就好了。

首先,什么是递归?一句话来讲,就是函数在定义的时候调用自己本身。

举个例子,假如你想算n!

正常情况下,在你没学递归之前,你应该会写一个循环吧

int f(int n)
{
    int res = 1;
    for(int i = 1; i <= n; i ++) res *= i;
    
    return res;
}

但是我们如果用递归的方式来写呢?

首先我们思考,n!= n * (n - 1) * (n - 2) * ... * 2 * 1

(n - 1)!= (n - 1) * (n - 2) * ... * 2 * 1

那么我们是不是可以将n!写成 (n - 1)!* n

那么我们就可以写代码了

int f(int n)
{
    if(n == 1) return 1;
    else return f(n - 1) * n;
}

看,这个代码相比于上文的循环,是不是间接多了?

想必大家看到这里,对一些简单的递归还是有一点初步的了解了吧

但是大家可能会有一些疑问,这个递归的函数内部是如何实现的呢?

别急,我们先举一个简单的例子,让大家好好了解一下递归的本质。

我们先写一个代码

#include <stdio.h>

int f(int n)
{
	if (n == 1) return 1;
	else return f(n - 1) * n;
}

int main()
{
	int num = 0;
	scanf("%d", &num);

	printf("%d的阶乘为:%d", num, f(num));

	return 0;
}

我们现在想求4的阶乘,那么应该如何理解递归呢?

我们都知道,函数的形式参数创建在内存的栈区。

刚进入函数内部的时候,n = 4,返回值应该是f(3) * 4。

那么f(3)又等于什么呢?应该等于f(2) * 3;

f(2)又等于什么呢?应该等于f(1) * 2,而f(1) = 1,所以f(2)= 2

所以f(3) = 6,最终f(4) = 24。

所以韩式递归本质就是函数内部的调用,他们都创建在栈区,函数返回之后就销毁。

我们都知道栈的特点是先进后出,实现压栈操作,我们我们才先有递的操作,最后才能从栈底到栈顶实现归的的操作。

本质上来讲,递归可以分成两个动作,一个是递,就是压栈,另一个是归,也就是出栈。

希望在我讲解完递归之后,大家能对递归有一些基本的了解,不了解也不要紧,毕竟这个递归对初学者来说不是很友好,大家在课下可以多多练习递归,从而达到熟练掌握的程度。

好了,本期的分享就到这里了,大家如果喜欢的话,希望大家能点一个赞,毕竟你们的支持与鼓励才是我前进的动力~

谢谢大家!

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值