前言:本期内容将承接上期C语言基础之——函数(上)的内容来继续讲解函数方面的知识。
目录
一.函数的嵌套调用和链式访问
1.嵌套调用
2.链式访问
二.函数的声明与定义
1.函数的声明
2.函数的定义
三.函数递归
1.什么是递归
2.递归的两个必要条件
四.总结
函数与函数之间可以根据实际的需求进行组合,也就是说,使用一个函数时,可以在它的函数体里边在调用另一个函数,这便是嵌套调用。
#include
void fun1()
{
printf("hehe\n");
}
void fun2()
{
printf("haha\n");
fun1();
}
int main()
{
fun2();
return 0;
}
我们来看这样一段简单的代码,我们在函数fun2里调用了函数fun1,然后再在main函数中调用函数fun2,结果如下:
“hehe”和“haha”都被打印出来了,这便是嵌套调用。
这里要注意一点,函数虽然可以嵌套调用,但却不能嵌套定义,也就是说不能在一个函数中来定义另一个函数。
#include
void fun2()
{
void fun1()
{
printf("hehe\n");
}
printf("haha\n");
}
int main()
{
fun2();
return 0;
}
像上边这种代码就是绝对不允许的,这就和不能在main函数中定义函数一样。
把一个函数的返回值(函数尾),作为另一个函数的参数(函数头),我们可以理解为将几个函数按从头到尾的顺序连接在一起,像一条函数链,这便是链式访问。
我们来举一个常见的例子来帮助大家理解:
#include
#include
int main()
{
int arr[] = "1234567";
int len = strlen(arr);
printf("%d", len);
return 0;
}
-------------------------------------------------------------------------------------------
int main()
{
int arr[] = "1234567";
printf("%d", strlen(arr));
return 0;
}
strlen()函数和printf()函数都是我们常用的函数,我们先来看第一段代码,我们定义了整型变量len来接收strlen()函数的返回值, 而后len作为printf()函数的参数被打印。
再看第二段代码,我们并没有定义任何变量来接收strlen()函数的返回值,而是直接将strlen(arr)这样一个整体用做printf()函数的参数。
事实上,strlen(arr)便是strlen()函数对应的返回值,只是我们平时习惯于定义一个新变量来接收。
#include
int main()
{
int a = 2;
int b = 5;
Add(a, b);
return 0;
}
void Add(int x, int y)
{
printf("%d", x + y);
}
我们之前的讲解所写的代码,自定义函数都是在main函数的前边,但是现在我们把它放在main函数的后边,会有什么不一样吗???
很遗憾,这样的做法是错误的。
我们知道,编译器是从上到下一行一行阅读代码的,对于上述代码,因为Add函数在main函数之后,编译器在main函数中调用到Add函数时,编译器并不认识Add函数,所以就发生了错误。
但是如果这样的话,自定义函数就必须在main函数之后吗???当然不是:
#include
void Add(int x, int y);//提前声明
int main()
{
int a = 2;
int b = 5;
Add(a, b);
return 0;
}
void Add(int x, int y)
{
printf("%d", x + y);
}
我们只需要在main函数之前声明一下Add函数,便可以正常使用了。这里的声明只需要函数的头,便可以让编译器记住Add函数,不要忘记末尾要加上';'。
具体交代一个函数到底是什么构造,有什么作用,这便是函数的定义。
void Add(int x, int y)
{
printf("%d", x + y);
}
这便是一个简单的加法函数的定义。
简单来说,递归就是一个函数自己嵌套调用自己,也就是——套娃。意在于把大事化小。
下面给大家演示一个史上最简单的递归代码:
#include
int main()
{
printf("hehe\n");
main();
return 0;
}
结果如下:
它会无止境的打印“hehe”。
下面我们便正式借助一个例子来具体讲解函数递归:
接收一个整型值(无符号),按顺序打印出它的每一位。
例如:输入:1234,输出:1 2 3 4.
如果这个代码,我们不用递归,正常来写的话,只需要先判断这个数的位数,然后再利用辗转相除取商来实现,代码如下,仅供了解:
#include
int main()
{
int n;
scanf("%d", &n);
int count = 1;
int z = n;
while (z > 10)//循环统计位数
{
z /= 10;
count *= 10;
}
while (count > 0)//辗转相除取商
{
int x = n / count;
n = n % count;
count /= 10;
printf("%d ", x);
}
return 0;
}
我们可以看出,正常写虽然不是很难,但是代码有些过于繁琐,那么,递归又是怎么实现的呢?
#include
int print(int n)
{
if (n > 9)
{
print(n / 10);
}
printf("%d ", n % 10);
}
int main()
{
int n;
scanf("%d", &n);
print(n);
return 0;
}
下面我们就来具体讲解一下这段递归代码是怎么运转的。
首先呢,我们输入一个整数:1234
进入函数中,n > 9 便是一个限制条件
如果n > 9 那么我们就递归调用这个函数,并且将 n / 10 的商作为参数传入
直到 n == 1 时,我们才停止嵌套,随后开始从内向外的打印 n % 10 的余数
如果这样你还是不太理解的话,那么来看我接下来的操作:
#include
int print(int n)// n = 1234
{
if (n > 9)
{
int print(int n / 10) //n = 123
{
if (n > 9)
{
int print(int n/ 10)//n = 12
{
if (n > 9)
{
int print(int n / 10) //n = 1
{
if (n > 9)//不满足
{
print(n / 10);//不执行
}
printf("%d ", n % 10);//打印1
}
printf("%d ", n % 10);//打印2
}
printf("%d ", n % 10);//打印3
}
printf("%d ", n % 10);//打印4
}
如果是这样的形式,你是不是就豁然开朗啦哈哈哈,没错,其实本质就是这种套娃,但是我们不能这样写代码,一是冗杂,二是编译器也不能通过。
由于函数递归是C语言知识中的一个重点,也是一个难点,所以在此博主就不过多展开讲解啦,后续会抽时间做一期文章来专门详解函数递归,敬请期待!
好啦,关于函数的知识到这里就要结束啦,喜欢博主文章的小伙伴们不要忘记一键三连哦!
我们下期再见!