函数的调用,有调用者和被调用者,其中main函数只能是调用者,函数之间可以相互调用,也可在函数中调用另一个函数,层层下去,这个叫函数的嵌套,但是注意,函数不支持函数的嵌套定义,只可嵌套调用。
1、函数的嵌套:
函数嵌套有内部原理知识,假设有个main函数,里面调用一个函数,此函数中再调用一个函数,在这个被调用的函数中再调用一个函数,形成嵌套,这就是函数的嵌套。
我们知道,程序都是在内存上运行,函数实现的功能代码都去一段对应的内存上运行,每一个函数都占一个内存空间,函数名相当于是函数的入口地址,输入函数名进入该函数,接收到返回值结束函数,pc program counter 程序计数器,是一种寄存器,寄存器直接跟cpu打交道,从主函数跳到别的函数时,cpu会保存现场,再返回时会恢复现场,那么如何保存现场呢?用了一种很巧妙的结构,栈,栈的本质是内存上一段空间,栈的特点是先进后出,从结构上来说,划分为栈底和栈顶,栈顶指向有效数据,保存现场用了栈这种结构普,入栈,出栈,保护现场就是把main函数相关数据压进栈中,调用函数相当于把函数中的数据再压进栈中,所以程序按顺序执行,出栈,入栈,栈的先进后出的特点保证了先进的最后执行,所以实现了由主函数开始的对函数的层层调用。 栈帧;
1、1栈
一种数据结构,表示数的组织形式。
特点,先进后出(First In Last Out)
C语言角度的栈本质是一块内存空间,只是按照栈这种数据结构来处理和使用的
栈上的变量是局部变量,?自动申请,自动变量。
c语言程序把内存划分了五个区域:
栈:主要用来存放自动变量或函数调用的数据,默认是8兆,可以修改
堆:空间大 ,堆上的空间手动申请,手动释放;
字符串常量区:“hello”,这块区域只读,不可修改
静态区(全局区):全局变量和静态变量,不初始化默认初始化成0;
代码区:只读的
程序 = 代码+数据
修改:一定命令 or 内核
函数层层嵌套调用中,有一种特殊的嵌套调用:递归(递推 ---递推结束的条件 ---回归)
递归:(类似循环)运行到最后会栈崩溃,有时候会说递归是一种特殊的循环;
直接递归,间接递归(最后要调到自己),记得判断要不要加函数声明
递归思路:求问题n,依赖于问题n-1的解决;
举例:求前100的和:
1、用到函数,实现前100项的和;
2、求前99项的和 +100
3、……
#include <stdio.h>
int sum(int n)
{
if (n == 1)
{
return 1;
}else
{
return sum(n-1) + n;
}
}
递归代码实现思路:(找每一次的结果)
1、递推关系
2、递推结束的条件
这一次调用的结果 = 这一次的值
练习:求n项的阶乘;
阶乘:前第n-1项的结果乘第n项;所以前第n-1项需要作为返回的结果,然后*n;
int factorial(int n)
{
if (n == 1)
{
return 1;
}else
{
return factorial(n-1) * n;
}
}
练习:求斐波那契数列第n项的值
int fibo(int n)
{
if (n == 1 || n == 2)
{
return 1;
}else
{
return fibo(n-1) + fibo(n-2);
}
}
数组作为函数参数:
1、数组元素作为函数参数;
2、数组本身作为函数参数;
2、一维整型数组做函数参数
形参: ---写成数组形式 (int a[ ]) 还需要数组长度 len
实参 :---数组名(不加[ ]),数组长度
代码举例:
//写成函数形式
void array(int a[],int len) //
//主函数中调用形式
array(a,len)
练习:准备一个数组,实现一个函数,找最大值;
int max(int a[],int len)
{
int m = a[0];
int i = 0;
for(i = 0;i<len ; i++)
{
if(m < a[i])
{
m = a[i];
}
}
return m;
}
int main()
{
int a[] = {1,2,3,4,5,6,7,8};
int len = sizeof(a) / sizeof(a[0]);
printf("%d\n",max(a,len));
}
3、一维字符型数组做函数参数
一维字符型数组,主要作用是处理字符串。
因为处理的是字符串数据,字符串操作的依据是‘\0’
注意:不需要传长度
一维字符型数组做函数参数
形参 数组形式
实参 数组名
4、二维数组做函数参数
总结:
形参 --- 二维数组形式 + 行数 //本质 一维数组 + 长度
实参 --- 数组名 + 行数 //
举例:实现一个函数,求二维数组元素的和 :
int sumOfArray(int a[][4],int row)
{
int i = 0;
int j = 0;
int sum = 0;
for (i = 0; i < row; ++i)
{
for (j = 0; j < 4; ++j)
{
sum = sum + a[i][j];
}
}
return sum;
}
找出二维数组中主对角上最大值:
int maxOfArray(int a[][4],int row)
{
int i = 0;
int j = 0;
int max = a[0][0];
for (i = 0; i < row; ++i)
{
for (j = 0; j < 4; ++j)
{
if (i==j && a[i][j] > max )
{
max = a[i][j];
}
}
}
return max;
}
5、二维字符数组做函数参数:
与二维整型数组 使用方式相同
形参 --- 二维数组形式 + 行数 //本质 一维数组 + 长度
实参 --- 数组名 + 行数 //
举例:
实现一个输入多个字符串函数 inputStr()
void inputStr(char (*s)[10],int row)
{
int i = 0;
for (i = 0; i < row; ++i)
{
gets(s[i]);
}
}