【C语言】函数

专栏:c语言                                                                                                                              作者:无名编程小白   

目录

#函数参数

#函数调用

#函数的嵌套调用和链式访问

#函数的声明和定义

#函数的递归


#函数参数

函数参数分为实际参数(实参)和形式参数(形参);

实参:真实传递给函数的参数,可以是变量、常量、表达式、函数等;

形参:函数名后括号内的变量,之所以称为形参是因为它只有在函数被调用时会被实例化,函数调用完成后会自动销毁,所以形参也只在函数内部存在(有效)。

#函数调用

void Test1(int x,int y){
     int tmp=0;
     tmp=x;
     x=y;
     y=tmp;
}
void Test2(int* px,int* py){
     int tmp=0;
     tmp=*px;
     *px=*py;
     *py=tmp;
}
int Test3(int x,int y){
    int tmp=0;
    tmp=x+y;
    return tmp;
} 
     

对比运用Test1和Test2函数不难发现,当你给定两个整型变量a,b,想通过上述函数进行交换数值时会发现Test1函数无法实现该操作,而如果用Test2函数则可以。

由此我们不难看出Test1函数被调用时,形参x,y拥有自己的空间,将值传递给x,y进行数值交换并不能改变原来a,b的值,所以我们可以认为:形参是实参的临时拷贝

由此可以看出如果想要改变某一变量的值就需要将其地址传过去,如Test2函数。当然如果简单比较或计算传值调用也可处理如Test3函数实现简单加法。

这样我们也顺理成章引出传址调用的概念:把函数外部创建变量的地址作为函数参数传递给函数的一种调用函数的方式。

其特点是直接对函数外变量所在内存进行修改变动。

#函数的嵌套调用和链式访问

1.嵌套调用

函数可以嵌套调用但是不可以嵌套定义。

#include<stdio.h>
void Print1(){
printf("hehe");
}
void Print2(){
printf("haha");
Print1();
}
int main(){
Print1();
Print2();
return 0;
}

2.链式访问

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

//利用printf函数进行链式访问得到4321

#include<stdio.h>

int main(){

     printf("%d",printf("%d",printf("43")));

     return 0;

}

//这里打印出4321的原因是printf函数返回值是输出的字符数

#函数的声明和定义

1.函数的声明

告诉编译器这个函数叫什么,参数,返回类型分别是什么

函数的声明一般在函数使用之前,先声明后使用

函数的声明一般在头文件中

//例如加法函数的声明

int Add(int x,int y);

2.函数的定义

指函数具体实现过程,交代其功能如何实现

test.h:放置函数的声明

test.c:放置函数的实现

#函数的递归

递归条件:

1.存在限制条件,当满足限制条件,递归结束

2.每次递归逐步靠近该限制条件

//斐波那契数列(常见的递归模型)
int Fib(int n){
    if(n<=2)
       return 1;
    else
       return Fib(n-1)+Fib(n-2);
}

使用后容易发现,我们在使用Fib计算第五十个斐波那契数时程序就会非常慢,这是为什么呢?

我们发现Fib函数在调用时很多计算在一直重复,比如计算Fib(5)时需要计算一次Fib(4),两次Fib(3),三次Fib(2),五次Fib(1)和三次Fib(0),效率极低。

不仅如此,系统分配给程序的栈空间是有限的,如果出现死循环或者死递归,这样可能导致一直开辟栈空间最终栈空间耗尽的情况,我们称之为“栈溢出”。

因此,递归虽好,但不要贪杯哟

最后研究两个经典递归问题:

1.青蛙跳台阶问题

简述:一只青蛙一次可以跳1级台阶,也可以跳2级台阶。求青蛙跳上n级台阶共有几种跳法。

思路:首先,假设f(n)代表跳法,当n=1时,青蛙只有一种跳法,即f(1)=1;

n=2时,可以跳一级或者两级,共两种跳法,即f(2)=2;

n>2时,如果第一次跳一级,那么剩下的跳法就是f(n-1)种;如果第一次跳两级,那么剩下f(n-2)种跳法,加起来即为总数f(n)=f(n-1)+f(n-2)

#include<stdio.h>
int up_step(int n){
     if(n==1)
        return 1;
     else if(n==2)
        return 2;
     else 
        return up_step(n-1)+up_step(n-2);
}
int main(){
     int n=0;
     scanf("%d",&n);
     int sum=up_stmp(n);
     printf("%d",sum);
     return 0;
}

2.汉诺塔问题

简述:现有三根杆子A,B,C,

A杆上有N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小,要求按下列规则将所有圆盘移至C杆:

1.每次只能移动一个圆盘

2.小圆盘上不能放大圆盘

可以将圆盘临时置于B杆,也可将从A杆移出的圆盘重新移回A杆,但必须遵循以上规则。

求移动过程

思路: 其移动规律为一次只能移动一个圆盘,并且小圆盘要在大圆盘上,假设A有n个圆盘,我们要先把n-1个圆盘从A移动到B上,再把第n个圆盘移动到C上,最后把n-1个圆盘移动到C,不管n为多少(n>1)都满足这一大思路,满足递归思想。

我们把移动第一步中的n-1个圆盘的次数看作f(n-1),第二步则步数为1,第三步移动B上的n-1个圆盘方法同f(n-1),因此递归公式满足f(n)=2*f(n-1)+1

#include<stdio.h>
int han_step(int n)
{
 if(n<=1)
  return 1;
 else
  return 2*han_step(n-1)+1;
}
int main()
{
 int n = 0;
 scanf("%d",&n);
 int ret = han_step(n);
 printf("%d\n",ret);
 return 0;
}

文章到此结束,一名c语言初学者,我们下篇见!点个关注不迷路!!

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值