递归
在学习完函数的声明和定义后,《C Prime Plus》直接就开始介绍递归这一个重要知识点了。
在学习这本书之前,主要是接触Python来编程的,由于只会很基础的语法和调包,所以对算法啥的没有任何概念。但是递归这个小怪兽经常从其他博客里听说,据说很难,今天开始学习发现,确实不好搞懂,有种回到了高中学习数列的感觉(确信)。
《C Prime Plus》对递归定义很简短,函数自己调用自己的过程。。。难点在于如何结束递归。 书中用一个求阶乘的例子来简单的讲述了递归的使用:
long rfact(int n){
long ans;
if (num > 0)
ans = n* rfact(n-1); //函数自我调用,递归过程。
else
ans = 1; //0的阶乘为1
一个简短的函数,就包含了递归的基本特征。如何去解析这个函数呢?ans = n* rfact(n-1)
是怎么工作的?类似于俄罗斯套娃,层层调用:(设n=4)这里的等号并不是实际的代码,主要是方便理解
rfact(4) = 4*rfact(3)
rfact(3) = 3*rfact(2)
rfact(2) = 2*rfact(1)
rfact(1) = 1*rfact(0)
当n=0时,rfact(0)执行了else语句后面的,ans取值为1,所以我们得到了rfact(1) = 1 * 1 = 1;
rfact(1) = 1代入rfact(2) = 2*rfact(1),继续得到rfact(2) = 2 * 1 = 2;
rfact(2) = 2代入rfact(3) = 3*rfact(2),继续得到rfact(3) = 3 * 2 = 6;
rfact(3) = 6代入rfact(4) = 4*rfact(3),最后得到rfact(4) = 4 * 6 = 24;
整个过程中,经历了n不断减小,直到n达到了rfact()里else语句的情况,触发递归结束的条件,然后再反方向一个一个数乘回去。 n 那么,看到这里,最简单的递归的要点就是--递归怎么结束。这个目前先作为了解的内容,以后学算法再回来补习吧~
递归的优缺点
书中直接说了,递归的优点是为某些编译问题提供了最简单的解决方案。这里不是很理解,目前粗暴的理解为,这属于编译环节方面的问题?不需要初学者深究?
递归的缺点很明显,层层调用,会消耗大量的内存资源(也就是会内存泄漏?)
书中说,如果可以选择的话,循环会比递归更好一些,当然啦,对于初学者,循环用起来容易一些。
编译多源代码文件
这一节首次讲述了把main()、函数原型、函数定义分在不同的文件中来进行编译的具体做法,这对我来说也是开启了C语言模块化编程的大门。
头文件不仅只是标准库提供给我们的,我们也可以自己编写自己的头文件。在这一节中,书本范例将预处理定义符号常量和函数原型放在一个自定义的头文件中,并在main.c文件、函数支持模块文件中用#include "file.h"
的方式引入。
函数支持模块文件包含了main.c文件中使用到的函数的具体定义。
最后,三个文件编译好后,对于gcc编译器,只需使用以下命令即可把main.c文件、函数支持模块文件整合编译。
gcc main.c function.c
另外,这里还用到了经典的处理用户输入非法字符的方法:
scanf("%*s")
小结
总的来说,这两节内容收获不小,初次学习到了递归,也知晓了实际项目中,C语言程序的多文件编译方法。