目录
一、函数的嵌套调用和链式访问
在编程的时候我们不难发现,我们所写的代码都是由函数组成的。函数和函数之间可以根据实际的需求进行组合,也就是互相调用。
1.1嵌套调用
在一个函数内调用另一个函数就是嵌套调用。
例:利用一个函数进行多次打印
#include<stdio.h>
//比如我们想利用一个函数打印几次
void one_line(void)//因为创建这个函数就是为了打印 所以不需要传入参数也不需要传出参数
{
printf("好好学习,天天向上\n");
}
void five_line(void)
{
int i = 0;
for (i = 0; i < 5; i++)
{
one_line();
}
}
int main()
{
five_line();
return 0;
}
注:函数可以嵌套调用,但是不能嵌套定义。(以下是错误的代码,函数不可以进行嵌套定义)
int main()
{
int Add(int x,int y)
{
return x+y;
}
return 0;
}
1.2链式访问
链式访问:把一个函数的返回值作为另外一个函数的参数。
注:printf函数的返回值是打印在屏幕上字符的个数
//链式访问的经典例子
//printf函数的返回值是打印在屏幕上的字符个数
#include<stdio.h>
int main()
{
printf("%d", printf("%d", printf("%d", 521)));
return 0;
}
二、函数的声明和定义
2.1函数的声明
函数声明:
(函数定义也是一种特殊的声明)
1.告诉编辑器有一个函数叫什么,参数是什么,返回值是什么。但是具体是不是存在,函数声明决定不了。
2.函数声明一般出现在函数的使用之前。要满足先声明后使用。
3.函数的声明一般要放在头文件中。(注意:包含自己的头文件要用" 头文件")
2.2函数的定义
函数的定义是指函数的具体实现交待函数的功能实现。
一般可以分三个文件来编写代码。
主文件写代码主题。
创建一个.c文件放置函数的实现。
创建一个头文件进行声明函数。
注:使用这种方法调用函数时,需要使用include"头文件" 来引用头文件。
三、函数递归
3.1什么是递归
程序调用自身编程技巧称为递归。
函数作为一种算法在程序设计语言中广泛应用。一个过程或函数在定义或说明中有直接或间接调用自身的一种方法,
它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。
只需少量的程序就可以描述出解题过程需要的多次重复计算,大大地减少程序的代码量。
递归的主要思考方式在于:把大事化小。
3.2递归的两个必要条件
- 存在限制条件,当满足这个限制条件的时候,递归便不再继续
- 每次递归调用之后越来越接近这个限制条件。
例:
打印5201314的每一位数
#include<stdio.h>
void print(int n)//函数的定义(函数定义也是一种特殊的声明)
{
if (n > 9)
{
print(n / 10);
}
printf("%d ", n);
}
int main()
{
int n = 5201314;
print(n);//自己创建一个函数对这个数进行打印
return 0;
}
3.3递归与迭代
我们先用一段代码帮助大家理解什么时候应该用递归,什么时候需要用非递归的方式去解决问题。
求第n个斐波那契数。(1,1,2,3,5,8,13,......,n)。
通过观察我们不难看出一些规律:
1 ----- (n<=2)
n=(n-1)+(n-2) ----- (n>2)
由此,我们通过递归的方式可以写成
#include<stdio.h>
int fib(int n)
{
if (n <= 2)
{
return 1;
}
else
return fib(n - 1) + fib(n - 2);
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = fib(n);
printf("%d\n", ret);
return 0;
}
如果我们仔细观察这段代码和代码逻辑,我们会发现一个问题。例如我们算的是10那么通过下图我们可以看出,一但我们要求的数比较大,那么在求它的过程运算量也是非常大的,这样就很可能会报错:stack overflow(栈溢出)。系统分配给程序的栈空间是有限的,但是如果出现了死循环,或者(死递归),这样有可能导致一 直开辟栈空间,最终产生栈空间耗尽的情况,这样的现象我们称为 栈溢出。
那么可以换种思路,采用非递归的方法进行计算。
#include<stdio.h>
int fib(int n)
{
int a = 1;
int b = 1;
int c = 1;
while (n >=3)
{
c = a + b;
a = b;
b = c;
n--;
}
return c;
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = fib(n);
printf("%d\n", ret);
return 0;
}
换为非递归的方法问题就解决了,我们正常的做法就是使用非递归的方法,虽然递归会使解决事情的效率更高一下,但是也是需要分清情况的。
当我们用递归写代码 如果没有任何问题 那么就可以用递归的方式。如果用递归的方式写,有明显的缺陷比如栈溢出 那么就应该用非递归的方式。
最后提醒大家:递归虽好,可好酒莫贪杯哦~