学习C语言 8.2 函数

目录

一、函数调用的关系

二、函数调用的本质    

三、递归

四、数组作为函数参数


 

一、函数调用的关系

调用者 
被调用者 

int main(void) 
{
   printf("%d\n",getMonthDays()); 
   return 0;
}

这个里面:
main ---成为调用者  ---main函数是整个程序的入口,只能调用者 
getMonthDays --- 在此处是 被调用者
              

getMonthDays()
{
   isLeapYear();
} //函数的嵌套调用 


main -->getMonthDays -->   isLeapYear

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

  
函数名 --- 函数的入口地址

 

二、函数调用的本质    

实际是利用的栈的结构  ---先进后出 --保证了函数可以层层嵌套调用

栈:
  数据结构 --- (表示数组组织形式)
  特点:
      先进后出 (First In Last Out) //FILO 
  

C语言角度的栈:
  1.本质上是一块内存空间
  2.只是按照 栈 这种数据结构 来处理和使用的
  
  栈:存放局部变量       //空间 自动申请 自动释放  
 
C语言程序:
  把内存划分了5个区域 

栈             //主要    用来存放, 自动变量 或 函数调用的数据 
堆             //空间大  堆上的空间 ,手动申请,手动释放 
字符串常量区           // 如:"hello" (只读)
静态区(全局区)         // 全局变量 和 静态变量  
代码区         // 只读的 
程序 = 代码 + 数据 

 

三、递归

特殊嵌套调用 --- 递归 

递归:可以认为是 自己调用自己(类似循环 --- 递归是一种特殊的循环 )
直接递归 
间接递归 

eg:1到100的累加求和
sum(100)
  |--sum(99) + 100
      |--sum(98)+99
           |--sum(97)+98
                ...
                  |--sum(3)+4
                        |--sum(2)+3
                            |--sum(1) + 2
                                 1                            
递归思路:
   要求问题n 
   依赖于问题n-1的解决 
   
递归代码实现思路:
1.递推关系 
  怎么从 问题 n 到 问题n-1

  sum(100) => sum(99)+100
  sum(99)  => sum(98)+99
  
  sum(n) = sum(n-1)+n;
2.递推结束条件 
  n = 1

ef76d6edbeca4f329fee8fb03efe53ef.png

递归是两个过程,先逐次向下推,直到结束条件,然后回归。

这个过程就需要用到栈从而保存现场和恢复现场,但是栈的大小是有限的,在64位平台上,一般默认为8M。所以当数字很大时,会出现栈崩溃。

#include <stdio.h>

int sum(int n)
{
	if(n==1)
	{
		return 1;
	}
	else
	{
		return sum(n-1)+n;
	}
}

int main(void)
{
	int a=0;
	scanf("%d",&a);
	int ret = sum (a);
	printf("%d\n",ret);

	return 0;
}

斐波拉契数列也可以通过递归实现
   
   1 1 2 3 5 8
  
   求斐波拉契数列第n项

fibo(5)
  |--fibo(4)+fibo(3) 
       |             |-- fibo(2) + fibo(1)
       |--fibo(3) + fibo(2)
             |-- fibo(2) + fibo(1)
                  1         1
     
fibo(n)
  |--fibo(n-1) + fibo(n-2)

#include <stdio.h>

int fibon(int n)
{
	if(n==1)
	{
		return 1;
	}
	else if(n==2)
	{
		return 1;
	}
	else
	{
		return fibon(n-1)+fibon(n-2);
	}
}

int main(void)
{
	int a=0;
	scanf("%d",&a);
	int ret = fibon(a);
	printf("%d\n",ret);

	return 0;
}

 汉诺塔(通过三个柱子A、B、C,每次只能搬一个盘子,盘子必须从大的在下,小的在上,将所有盘子从A移到C)是一个古老的数学问题,也可以通过递归实现

#include <stdio.h>

void move(int pole1,int pole2)
{
	printf("%c--->%c \n",pole1,pole2);
}

               //起始   辅助  目标 
void hanoi(int n,int A,int B,int C)
{
	if(n==1)
	{
		move(A,C);
	}
	else
	{
		hanoi(n-1,A,C,B);
		move(A,C);
		hanoi(n-1,B,A,C);
	}
}

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

	hanoi(a,'A','B','C');
	return 0;
}

只有一个盘子的时候,直接将盘子从A移到C

n个盘子时,考虑现将n-1个盘子移到B,再将最后一个大盘子从A移到C。这时n-1个盘子在B,移到C去,完成移动。对于n-1个盘子而言,一开始的起始位置是A,辅助位置是B,目标位置是C。移动到B之后等最后一个盘子移动完成,要移到C,才算结束。此时n-1个盘子的起始位置是B,要移到C,所以目标位置是C,辅助位置是A。

 

四、数组作为函数参数

1.数组元素作为函数参数 

int add(int a,int b)
{
   return a + b;
}

int a[10] = {1,2,3};
add(a[0],a[1]); //这种就是将数组元素作为函数参数


2.数组本身作为函数参数 

#include <stdio.h>

void printArray(int a[],int len)
{
	int i=0;
	for(i=0;i<len;++i)
	{
		printf("a[%d] = %d\n",i,a[i]);
	}
}

int main(void)
{
	int a[]={1,2,3,4,5,6,7,8,9};
	int len=sizeof(a)/sizeof(a[0]);

	printArray(a,len);

	return 0;
}

注意在函数中,int a[ ]表明是个数组,实际上编译器是将其当成int * a理解的,所以不能在函数里计算数组的长度,函数里的sizeof(a)认为是这个数组的地址,而不是这个数组整个的大小

50f3aec924ab43dca2533563d899f006.png

所以实际上形参写int a[10]也没关系,中间的长度并不重要,编译器都当成int *处理,但在函数里照样当数组处理。 


总结:
   1. 一维整型数组 做函数参数 
      形参  --写成数组形式  还需要数组长度 
      实参  --数组名,数组长度

     eg:
       printArrray(int a[],int len)    //形参 
       //printArrray (int *a,int len) ---编译器最终理解的形式 
        printArray(a,len);    //调用
      

int a[10];
数组名 代表类型 ---int[10] 这种数组类型 
数组名 代表的值 ---首元素的地址 //(数组所占内存空间的首地址)

 

 

  • 16
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值