一、递归
1.递归的基本概念
递归调用:一个函数直接或间接地调用了它本身,就称为函数 的递归调用,简称递归。 你中有我,我中有你-函数的递归调用
2. 递归函数的执行过程
(求一个函数的n阶乘)
源代码:
主体:
int main( ) {
int n;
float y;
printf("\nInput n:");
scanf("%d",&n);
y=fact(n); /*函数调用*/
printf("%d!=%-10.0f\n",n,y);
return 0;
}
实现函数:
/*求一个数的阶乘函数*/
float fact (int n){
float f=0;
if(n<0) {
printf("n<0,error!");
}
else if (n==0 || n==1) /*递归结束*/{
f=1;
}
else {
f=n*fact(n-1);
}
return(f);
}
3、递归说明
• 当函数自己调用自己时,系统将自动把函数中当前 的变量和形参暂时保留起来,在下一轮的调用过程中 ,系统为新调用的函数所用到的变量和形参开辟另外 的存储单元(内存空间)。每次调用函数所使用的变 量在不同的内存空间。
• 递归调用的层次越多,同名变量的占用的存储单元 也就越多。
• 当本次调用的函数运行结束时,系统将释放本次调 用时所占用的内存空间。程序的流程返回到上一层的 调用点,同时取得当初进入该层时,函数中的变量和 形参所占用的内存空间的数据。
4 、数值类递归例题
编写程序,求数列1,1,2,3,5,8,13,21,…… 的第N项。
思路:
这是一个数值问题
第1步:找出表示数列第N项的递归公式: FN = FN-1 + FN-2
第2步:递归的结束条件,当N=1或N=2时,F N=1。 根据以上思路考虑编程。
long fib( int n ){ /* 第 N 项 */
if ( n <= 2 ) {
return( 1 ); /* 结束条件 */
}
else {
return fib( n - 1 ) + fib( n - 2 ); /*第 N - 1 项 + 第 N - 2 项*/
}
5、编写递归程序要点:
1)找到正确的递归算法,这是编写递归程序的基础;
2)确定递归算法的结束条件,这是决定递归程序能否正常结束 的关键。
数值问题, 可以表达为数学公式, 从数学公式推导出问题的 递归定义,然后确定问题的边界条件,从而确定递归的算法和递 归结束条件。
二、局部变量和全局变量
1、 变量的属性
操作属性 :变量的类型
存储属性:1)存储器类型:寄存器、静态存 储区、动态存储区
2)生存期:变量在某一时刻存在- ----静态变量与动态变量
3)作用域:变量在某区域内有效- ----局部变量与全局变量
2 、变量定义格式
格式: 存储类型 数据类型 变量表;
3 、局部变量与全局变量
int x,y;
int main( ){
int a,b,c;
int fun(int);
x=10;
y=11;
fun(a);
….
return 0;
}
int fun( int m){
x++;
y++;
…..
}
(1)局部变量---内部变量
定义 :在数或复合语句内定义 ,在定义它的数或复合语句内有效
•不同函数中同名变量, 占不同内存单元
• 形参属于局部变量
• 局部变量只在函数调用时起作用,函数调用结束有效值消失。
(2)全局变量---外部变量
定义:在函数外定义,可为本文件内所有函数共用。 有效范围是从定义该变量的位置开始到本源文件结束,及有 extern说明的其它源文件
三、动态变量与静态变量
1、变量的存储方式
静态存储:程序运行期间分配固定存储空间。
动态存储:程序运行期间根据需要动态分配存储空间。
2、变量的生存期 变量值保留的期限
静态变量: 从程序开始执行到程序结束。
动态变量: 从包含该变量定义的函数开始执行至函数执行结束。
3、变量的存储类型
(1)自动变量auto
自动变量存储特性:
•定义自动变量的函数被调用时,才为自动变量分配内存。
•函数调用结束时,为自动变量分配的内存被释放。
•自动变量仅在定义它的函数内部有效。
•自动变量被存放在内存的动态存储区。
结论:自动变量的生存期和可见性 自动变量的生存期和可见性(作用域)仅限于定义它的函数内部。自动变量是一种局部变量。
(2)静态变量static
静态变量static分为局部静态变量和全局静态变量。
静态变量存储在内存的静态存储区,有固定的地址。
静态变量在程序运行期间,变量值自始至终保留。
局部静态变量:函数内部定义,函数外不可见。程 序运行期间,值保留。
全局静态变量:函数外定义,仅本文件内部其他函 数可以访问。
静态变量存储特性 :
在编译阶段,为静态变量分配内存。静态变量被存放在内存的 静态存储区。
静态变量的生存期是在程序运行的整个时期,整个程序运行结束时,为静态变量分配的内存才被释放。
静态变量仅在定义它的函数内部有效。
在编译阶段定义静态变量的时,静态变量被置0。
关键字static和auto决定变量被存放在内存的哪个数据区。
(3)外部变量extern
外部变量的生存期是在程序运行的整个时期,可见性(作用域) 从定义它的位置到文件结束。
外部变量是一种全局变量。
同名的外部变量和局部变量,是不同的两个变量。函数内部说明了一个和外部变量同名的局部变量,则外部变量被屏蔽。
四、编译预处理
编译预处理:在源程序文件中,加入“编译预处理命令”,使编译 程序在对源程序进行通常的编译 包括词法分析 语法分析 编译预处理 ( 词法分析、语法分析、 代码生成、代码优化)之前,先对这些命令进行预处理,然后 将预处理的结果和源程序一起再进行通常的编译处理,以得到 目标代码(OBJ文件)。
C提供的编译预处理命令
宏命令
文件包含命令
条件编译命令
以#开头,以区别于语句。
1 、宏定义
也叫宏替换,是字符串之间的替换。
(1)不带参数的宏
形式:#define PI 3.1415926
作用:用标识符(称为“宏名”)PI代替字符串“3.1415926”。 在预编译时,将源程序中出现的宏名PI替换为字符串 “3.1415926”, 替换过程称为“宏展开”。
(2) 带参数的宏
一般形式: #define 宏名(参数表) 字符串
作用:带参数的宏在展开时,将程序中出现的带实参的宏名 , 替换成由实参组成的字符串 。
注意:带参数的宏中括号的使用
思考:分别用函数和带参数的宏实现输出10以内自然数的平方。
2 、文件包含
格式 : #include “文件名”
作用:预处理时,把“文件名”指定的文件内容复制到本文件,再对合并后的文件进行编译。
在file1.c文件中,有文件包含命令#include "file2.c",预处理时, 先把file2.c的内容复制到文件file1.c,再对file1.c进行编译。
从理论上说,#include命令可以包含任何类型的文件,只要这些文 件的内容被扩展后符合C语言语法。
一般#include命令用于包含扩展名为.h的“头文件”,如stdio.h、 string.h、math.h。在这些文件中,一般定义符号常量、宏,或声明函数原型。