【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了

1.库函数

许多人认为库函数就是C语言直接规定的,但其实不是,C语言标准只是规定了库函数的功能,参数等,而库函数的实现是由编译器给出的。比如要想VS2022使用printf函数,他有自己的实现方式,要想在gcc上使用printf函数,也有gcc自己的实现方式,但是功能,参数等都是一样的。

比如

strcpy 字符串拷贝函数

功能:把源地址处的字符串拷贝到目标地址去,包括字符串的结束标志\0也会被拷贝过去。返回的是目的地址。

memset 函数

功能:把指定地址处的指定数量个字节内容修改成我们指定的内容。

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第1张图片

比如下面这个例子

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第2张图片

比如这样打印结果就是xxxxx bit

2.自定义函数中需要注意的一些问题

下面是一个交换两个数的代码,然而当我们运行的时候发现交换了个寂寞,这是为什么呢?

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第3张图片

实际传给swap的参数叫做实参,定义swap函数时的x和y是形参,对于形参的修改不会影响实参,究其原因,是因为我们在创建a和b的时候在内存中申请了两块空间,在创建x和y的时候又在内存中申请了两块新的空间,我们对于x和y的交换是在这个新的内存空间中进行的,当然不会影响实参。可以理解为形参是实参的一份临时拷贝。

也就是说造成这种bug的主要原因就是形参和实参所在的内存空间不一样,解决方法可以用指针,将swap函数的形参类型修改成int*类型同时实参传递a和b的地址即可解决。如图

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第4张图片

3.函数的实参可以是常量,变量,表达式,函数表达式,但是必须是确定的值,如图,以下写法均正确

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第5张图片

4.各种变量存储的区域

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第6张图片

练习

1.输出100~200之间的素数 使用函数方式

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第7张图片

首先偶数一定不是素数,那么我们直接从101开始i每次+2只判断100~200之间的奇数是不是素数即可。

齐次在判断一个数是否为素数的时候,如果小于等于根下x的数均不能被x整除,则这个数就是素数,因此用做除法的时候并不需要一直检验到x-1,只需要检验到根下x也即sqrt(x)即可。

输出1000~2000之间的闰年

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第8张图片

二分查找,用函数实现

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第9张图片

二分查找需要注意的几个点:1.应用条件为有序数组 2.while循环的条件是left小于等于right 3.修改的是left和right而不是mid 4.求mid的时候可以写成left+(right-left)/2,这样可以有效的防止溢出。但是千万不能写成mid=left/2+right/2,这种写法直接就是错误的,举个例子,(3+5)/2=4,但是3/2+5/2=3,显然这不是我们想要的mid

1.函数可以嵌套调用但是不能嵌套定义

2.函数的链式访问:把一个函数的返回值作为另一个函数的参数这种写法就叫做函数的链式访问

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第10张图片

打印结果是什么?

printf函数的返回值是其在屏幕上所打印的字符的个数,从内往外开始看,首先会打印数字43,这是两个字符,因此最内层的pritnf返回值是2,因此下一个pritnf函数会打印2,这是一个字符,因此第二个pritnf的返回值是1,下一个pritnf会打印1。因此打印结果为4321

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第11张图片

如果在printf的占位符后面加一个空格,打印结果是什么?

首先会打印一个43和空格,这是三个字符,因此第一个pritnf返回值是3,第二个printf打印的是第一个printf的返回值,因此他打印了3,又因为第二个printf的占位符后面也有一个空格,因此第二个printf打印的是3和空格,这是两个字符,因此第二个printf的返回值是2,第三个printf打印的是第二个printf的返回值加一个空格,因此最终打印结果为43 3 2

3.函数的定义与声明

函数的定义可以在调用之前,也可以在调用之后,但是在调用之后的话,应该声明。实际上函数的声明一般是放在头文件里面

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第12张图片

上面图中头文件里面是函数的声明,add.c里面是函数的定义,引上头文件add.h之后,test.c里面只需要调用函数即可。引用头文件的格式是#include "add.h"

4.函数递归

所谓函数递归就是函数自己调用了自己

递归练习

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第13张图片

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第14张图片

假如我们输入1234,在第一次调用的时候显然是大于9,因此进入if执行下一次print函数,而并没有去打印x%10,这时候传的参数是123,仍然大于9,继续执行print,也没有打印x%10,这时候传的参数是12,仍然大于9,继续执行print,也没有打印x%10,这时候传的参数是1,小于9不进入if而是执行下面的语句打印了x%10也就是1,而这次的print函数是从上一个print函数那里跳过来的,执行完这次就接着上一次的执行,因此打印2,接着是3,接着是4。可以参考下面的流程

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第15张图片

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第16张图片

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第17张图片

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第18张图片

注:每一次函数调用都会在栈区上分配一块内存空间来保存函数在调用过程中上下文的信息。函数递归是一定要有条件限制的,在使用函数递归的时候要避免出现递归过深而导致栈溢出的情况。

函数递归的两个必要条件

循环和递归非常的相似,都是在做一些重复的事情,但是递归一次就调用一次函数,那就要向内存申请一块空间,而循环可能自始至终都是在使用同一块数据。

练习2:

(1)求字符串长度,不允许使用库函数

(2)求字符串长度,不能使用库函数,且不允许创建临时变量(提示:使用函数递归)

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第19张图片

使用临时变量count作为计数器即可模拟实现strlen函数

常见的错误有:把count定义到了while循环的里面,形参应该是char*但是写成了int*,创建数组arr的时候应该是char arr[]但是写成了int arr[]

使用函数递归的方式

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第20张图片

如果传的是空字符串,那么长度自然是0,直接返回0即可,如果传的不是空字符串,比如abc,要求这个字符串的长度,其实就是求1+bc这个字符串的长度,也即1+1+c这个字符串的长度。有了这个思路,我们来画图解释一下

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第21张图片

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第22张图片

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第23张图片

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第24张图片

返回0之后倒数第二次调用就返回了1+0,再上一次就返回1+1+0,在上一次就返回了1+1+1+0,因此这个代码返回结果为3

练习3:求n的阶乘(使用函数递归方式)

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第25张图片

画图解释,假如我们输入3

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第26张图片

因此会再次调用Fac函数

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第27张图片

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第28张图片

因此上一次Fac返回值是2*1,在上一次是3*2*1最终结果是6

练习4:求第n个菲波那切数

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第29张图片

可以发现如果有公式的话使用函数递归的方式来写代码是非常容易的。

注:这个写法由于会进行大量重复的计算,效率非常低,因为要想知道第50个,就要先知道第48,49个,以此类推。推荐使用循环的方式去解决。

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第30张图片

这就是循环的写法,思路就是a+b=c,刚上来让a,b都是1,然后c便是2,然后把b赋给a,把c赋给b,再次进行a+b=c的操作重复上述过程,通过数学归纳法可知求第n个菲波那切数只需要n-2次循环。

练习5

青蛙跳台阶问题

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第31张图片

假设跳到第n级台阶有f(n)种跳法,由于跳到第n阶只能是从第n-1阶或者n-2阶开始跳,因此f(n)=f(n-1)+f(n-2),发现其实就是菲波那切数列。

练习6

汉诺塔问题

【C语言】函数的声明,定义,传参,调用,嵌套,递归(图解):汉诺塔问题,青蛙跳台阶问题。学会函数知识点,这一篇就够了_第32张图片

思路:如果只有一个盘子,直接从A柱移动到C柱即可

如果有n个盘子,可以想办法先把上面n-1个盘子先挪到B柱子上,然后再把A柱子上剩下的最底下那个挪到C柱子上,然后再把B柱子上n-1个挪到C柱子上。这里所说的想办法,其实就是重复了hanoi函数

然后是统计移动次数的代码,根据上面的过程,发现移动次数也就是上述三个过程的移动次数之和为mov_num(n-1)+1+mov_num(n-1),他们分别是上述三个过程的移动次数。

你可能感兴趣的:(c语言,java,算法,数据结构,c++)