C语言程序设计
2002 年第五章 函数与程序结构
5.1 C程序的一般结构
1。结构化程序设计基本思想:将一个复杂的问题分解成若干较简单的子问题。
必要时,对子问题进一步分解,每一个子问题称为一个模块,
通过逐步求精,直到分解成一些容易实现的模块(最底层)为止,最终完成算法的功能设置。 (自顶向下的程序设计)
教务管理学生记录 查询统计录入 修改 删除 按学号 综合查询
2,C程序的一般结构
C程序源文件1 源文件 n(n>0)源文件2
函数1 函数2
…..
….,函数 m(m>=0)
说明:
(1) n个源文件中有且仅有一个 main函数,n个源文件组成一个 project,每个源文件可独立编译;
(2) 源程序中仅有说明时,不包括函数;
(3) 函数分系统函数和用户自定义函数。
p1.c p2.c pn.c
…..
5.2 函数定义存储类型区分符 类型区分符 函数名(参数表)
{
说明部分语句部分
}
函数是一段有名称的程序,根据参数表提供的输入数据,
借助于说明部分的变量,通过语句部分的语句执行,实现特定的功能。
说明:
( 1)存储类型区分符说明函数的使用范围:
extern(缺省 ),外部函数,所有 C程序文件中都可以使用 ;
static 静态函数,仅在本 C程序文件中使用 。
( 2) 函数名,除 main之外的标识符。外部函数间不能同名;
同一 C源程序文件中的静态函数也间不能同名。
( 3) 类型区分符,函数的返回值类型,缺省为 int;
void 表示无返回值。
( 4) 参数表,形式参数表(简称 形参表 )
形式,参数说明,参数说明,。。。,参数说明参数说明,类型区分符 形参名
( 5) 函数体和函数返回值,
函数体为一复合语句;
说明部分说明的变量使用范围(作用域)局部于本函数;
函数体为空的函数为哑函数;
函数返回值应与定义的返回类型一致。
例:定义一函数名求整数 xn,x,n均为整数。
分析,在 math.h中有函数说明 double pow(double x,double y)
计算 xy,当 x=0 且 y<=0 或者 x<0且 y不是一整数时,定义域错 。
xn =x*x*….x 结果为一较大的整数。
extern long power(int x,int n)
{
int i; long p=1;
for(i=1;i<=n;i++)
p*=x;
return p;
}
5.3 函数名调用与参数传递
5.3.1 函数调用函数调用表示为使用函数的功能而执行函数。
函数调用形式:
函数名(参数表)
参数表的形式:参数 1,参数 2,。。。,参数 n
各参数是表达式,表达式的值是函数执行时要处理的实际数据。实际参数( 实参 )
例:输入整数 m,计算 m1,m2,….m 10
long power(int x,int n)
{
int i; long p=1;
for(i=1;i<=n;i++)
p*=x;
return p;
}
main()
{
int m,i;
scanf(“%d”,&m);
for(i=1;i<=10;i++)
{ long w;
w=power(m,i);
printf(“power(%d,%d)”
“=%10ld”,m,i,w);
}
}
控制转移,x,n分配单元。 m?x,i?n
释放本次调用分配的所有单元,控制转移,返回 xn
每次执行,
i,p分配单元。
注意:
( 1)实参与形参应在数目上、次序上和类型上一致。
( 2)有返回值的函数,函数调用可作为表达式或语句出现。
getchar (); 作为语句出现,目的等待输入一个字符。
c=getchar (); 作为表达式出现。
power(10,4); 作为语句出现,返回的 104没起作用。
( 3)无返回值(返回类型为 void)的函数,函数调用只能作为语句出现。
( 4)无参数的函数调用形式:函数名()
()不能省却参数的求值次序:
标准 C中,函数调用时,实际参数表达式的求值次序没有规定。 绝大多数编译程序 按 从右至左 进行实际参数表达式的求值(如 TURBO C)。
main()
{
int x=0;
printf(“%d,%d”,x++,x++);
}
TURBO C下,输出结果,1,0
在某些 C编译环境下,输出会是结果,0,1
函数调用转换与参数类型的一致性执行函数调用时所发生的下述实参和形参的类型转换称为 函数调用转换:
( 1) 如无函数说明(或函数说明为传统 C的形式),则对实参进行可能的整数提升,以及 float转换成 double,称为 参数提升 。
main()
{ short a=10,b=20;
long sum(); /*函数说明的传统 C形式,也可省略 */
printf(“sum=%ld”,sum(a,b)); /*对 a,b提升为 int,实参和形参
}
long sum(long x,long y)
{ return x+y; }
类型不匹配,结果不正确。 */
( 2)如函数说明为标准 C的形式,则将实参自动转变成形式参数的类型(类似于赋值)
main()
{ short a=10,b=20;
long sum(long,long); /*函数说明的原型说明 */
printf(“sum=%ld”,sum(a,b)); /*对 a,b自动转换成 long*/
}
long sum(long x,long y)
{ return x+y;
}
( 3) 如果函数定义为传统 C,需要则对形参进行可能的整数提升,而标准 C不需要。
short sum( x,y) /*标准 C的定义形式 */
short x; /*经过整数提升后,形参为 int,int */
short y;
{ return x+y;
}
实参和形参的一致性实参与形参应在数目上、次序上和以及转换后类型上一致。
否则,调用效果不确定。
参数的传递函数调用时,进行实参与形参匹配,即将实参表达式的值传递给形参变量,不是传递地址;
函数中对形参变量的处理,仅仅是对实参的副本,对实参本身无任何影响;
若需要传递地址,必须用指针。
void swap(int x,int y);
{ int temp;
temp=x;x=y;y=temp;
}
main()
{ int x=10,y=20;
swap(x,y);
printf(“x=%d,y=%d”,x,y);
}
main函数
swap(x,y)
第一实参表达式的值,10
第二实参表达式的值,20
swap函数
x:
y:
temp
5.4 函数说明函数说明是对函数的返回值类型、参数的数目和类型的说明;
函数应先定义或先说明,后调用。
1。函数说明的一般形式:
存储类型区分符 类型区分符 函数名(参数类型表)
例,main()
{ long power(int x,int n);
printf(“%ld”,power(10,4)); }
long power(int x,int n)
{ int i; long p=1;
for(i=1;i<=n;i++)
p*=x;
return p; }
一般省略说明:
( 1) 一次定义,多次说明。
( 2)静态函数说明必须指定 static;
( 3)形参为空的函数,说明时参数表应指定 void;
2。函数说明的作用域
( 1)函数说明在函数体外时,从函数说明起到本 C程序文件结束的范围内都能有效调用该函数。
( 2)函数说明在函数体内时,有效调用该函数局限于该函数体。
int f1(int,int);
float f2(…) {… 可调用 f1..}
double f3(….) {… 可调用 f1.,}
int f1(int x,int y)
{………}
float f2(…)
{int f1(int,int);可调用 f1 ….}
double f3(….) { 不可调用 f1,}
int f1(int x,int y)
{………}
数据类型
C变量属性存储类型分配存储单元的多少值域的范围合法的操作分配存储单元的时机变量的生命期变量的初始化方式变量的作用域
5.5 变量的存储类型存储类型分类,
( 1) auto (自动存储类) ( 2) extern (外部存储类)
( 3) static( 静态存储类) ( 4) register(寄存器存储类)
自动变量定义形式:
auto int m,n;
float x,y;
定义位置,函数内或复合语句内。
变量生命期,当函数被调用,或进入复合语句时,产生变量,
分配存储单元,函数执行完或退出复合语句时,释放变量存储单元,变量消亡。
作用域,函数内或复合语句内。
缺省初始化方式,不定显式初始化方式,int m=10; 等价于 。
int m;
m=10;
外部(全局)变量定义、说明形式,float x,y;
extern int m,n;
编译将第一次遇到的理解为定义、以后遇到的理解为说明。
定义位置,函数外。
变量生命期,当 C程序开始执行时,分配存储单元,程序执行完后,释放变量存储单元,变量消亡。生命期同于 C程序的执行时间。
作用域,所有 C源程序文件。定义之后的源程序部分都可以使用该变量,其他位置可先说明,后使用。
缺省省初始化方式,0 或 0.0 或 ‘ \0?
注意,显式初始化方式为变量的定义。 int a=10;
静态变量
( 1)外部静态变量定义形式:
static int m,n;
定义位置,函数外。
变量生命期,当 C程序开始执行时,分配存储单元,程序执行完后,释放变量存储单元,变量消亡。生命期同于 C程序的执行时间。
作用域,当前 C源程序文件。定义之后的源程序部分都可以使用该变量,其他位置可先说明,后使用。
缺省初始化方式,0 或 0.0 或 ‘ \0?
显式初始化方式,stactic int m=10;。
静态变量
( 2)局部静态变量定义形式:
static int m,n;
定义位置,函数内或复合语句内。
变量生命期,当 C程序开始执行时,分配存储单元,程序执行完后,释放变量存储单元,变量消亡。生命期同于 C程序的执行时间。
作用域,函数内或复合语句内。
缺省初始化方式,0 或 0.0 或 ‘ \0?
显式初始化方式,stactic int m=10; 不等价于 。
stactic int m; m=10; 且仅赋值一次。
寄存器变量定义形式:
register int m,n;
定义位置,函数内或复合语句内。
变量生命期,当函数被调用,或进入复合语句时,产生变量,
当有空闲寄存器时,分配寄存器,无则分配存储内存单元,
函数执行完或退出复合语句时,释放变量存储分配,变量消亡。
作用域,函数内或复合语句内。
缺省初始化方式,不定例 1:变量的作用域。
#include,stdio.h”
int x=10,y=20; /*外部变量 */
main()
{ float x=12.3; /*自动变量 */
int i;
{
char x=?a?; /*自动变量 */
printf(“x=%c”,x);
}
printf(“x=%f”,x);
}
变量作用域重叠时,
内层屏蔽外层。
例 2:多源程序文件组成的 C程序。
/********源程序 1,test1.c **************/
#include,stdio.h”
static int x=500; /*外部静态变量,与 test2.c的 x同名,
静态变量定义与说明同一 */
float y=100,f2(float,float); /*外部变量定义和外部函数说明 */
float f1(float a,float b);
{ return (a*b-x+y); }
void main(void)
{
printf(“f1=%f,f2=%f\n”,f1(x,y),f2(x,y));
}
/********源程序 2,test2.c **************/
extern float y; /*外部变量说明 */
extern float x; /*外部变量定义 */
float f2(float a,float b)
{
return (a/b+y);
}
外部变量 x的作用域外部变量 y的作用域外部静态变量 x的作用域
C项目的建立过程:
( 1)选择菜单,Project”的子菜单项,Project name”
输入项目名,test
( 2)编辑 (new)产生项目的文本文件,test.prj
test1.c
test2.c
注,对 test1和 test2可分别进行编译
( 3)连接、运行。
( 4)该 C程序调试完成后,选择菜单,Project”的子菜单项,Clear Project”
例 2:静态局部变量:
int sum(n)
{
static int s=0;
int i;
for(i=1;i<=n;i++)
s=s+i;
return s;
}
main()
{
int i;
for(i=1;i<=5;i++)
printf(“\nsum of 1 to %d=%d”,i,sum(i));
}
输出:
sum of 1 to 1=1
sum of 1 to 2=4
sum of 1 to 3=10
sum of 1 to 4=20
sum of 1 to 5=35
5.6 递归函数与递归调用
1.递归函数的概念。
间接递归调用:
int f1(…)
{ ………
f2(…)
………
}
void f2(…)
{ …..
x=f1(…);
……
}
直接递归调用:
long FiBo(int n)
{
long f1,f2;
if (n==1 ||n==2) return 1;
f1=FiBo(n-1);
f2=FiBo(n-2);
return f1+f2;
}
2。 递归算法思想:
在以一种方法求解问题时,将复杂的问题分解成相对简单的子问题,而在求解子问题时,使用同样的方法进行。
求解规模位 n的问题分解
1.特殊情况的求解:
(如,n=1,n=2等)
2.分解成子问题:
3.求解规模位 n的问题求解规模为
n-1的问题求解规模为
n-2的问题
3。 递归函数的定义:
例,计算 n的阶乘的算法,
1 n=0 特殊情况的求解
n!=
n*(n-1)! n>0
long fac(int n)
{
long f;
if (n==0) return 1; /*特殊情况的处理 */
f=fac(n-1); /*子问题的处理 */
return n*f; /*最后的求解 */
}
4。 递归函数的执行过程:
main() {
printf(“%ld”,fac(3));
}
递推过程,
fac(3)
变量存储分配,
n,3
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
变量存储分配,
n,2
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
变量存储分配,
n,1
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
变量存储分配,
n,0
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
各个 n,f 分配不同存储单元
fac(3)
变量存储分配,
n,3
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
变量存储分配,
n,2
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
变量存储分配,
n,1
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
变量存储分配,
n,0
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
fac(3)
变量存储分配,
n,3
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
变量存储分配,
n,2
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
变量存储分配,
n,1
f,1
if (n==0)
return 1;
f=fac(n-1);
return n*f;
回归过程:
1
1
fac(3)
变量存储分配,
n,3
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
变量存储分配,
n,2
f,1
if (n==0)
return 1;
f=fac(n-1);
return n*f;
回归过程:
2
fac(3)
变量存储分配,
n,3
f,2
if (n==0)
return 1;
f=fac(n-1);
return n*f;
6
5.7 编译预处理以 #开头、以换行符结尾的行称为 编译预处理指令。
#define PI 3.14159
#include,stdio.h”
编译预处理指令 不是 C语言的语法成分;
编译之前 要首先处理,编译程序自动调用编译预处理程序。
常用编译预处理包括:
( 1)宏替换;
( 2)文件嵌入;
( 3)条件编译;
5.7.1 宏替换
( 1) 简单宏替换
#define 标识符 单词串功能,在定义点以后的程序中,替换所有与该标识符相同的为指定符号串形式。不包括字符串常量中的符号。
#define PI 3.14159
printf(“PI=%d”,PI),?printf(“PI=%d”,3.14159),
( 2) 带参数的宏替换
#define 标识符(标识符,标识符,….,标识符) 单词串功能,在定义点以后的程序中,替换所有与该标识符结构相匹配的形式为指定符号串形式。不包括字符串常量中的符号。
#define SUM(a,b) a+b
#define MUL(a,b) a*b
int x=10,y=20;
printf(“SUM=%d”,SUM(x,y)),?printf(“SUM=%d”,x+y),
printf(“%f”,SUM(10.0,20.0)),?printf(“%f”,10.0+20.0),
printf(“%f”,MUL(1+2,3+4)),?printf(“%f”,1+2*3+4),
( 3)取消宏名定义
#undef 标识符例:
main()
{
int x=10,y;
#define x 20
y=4*x; printf(“y=%d”,y);
#undef x
y=4*x; printf(“y=%d”,y);
}
5.7.2 文件嵌入功能,将指定文件内容插入到该位置。
形式:
#include <文件名 >
#include,文件名”
#include 标识符文件名可以包括路径。按路径指示查找文件;
无路径时,<文件名 >按标准方式查找 ;,文件名”方式首先在该文件所在目录下查找,未找到时再按标准方式查找。
标准方式指由环境所设路径。
/*******文件 my.h***************/
#define PI 3.14159 /*常量定义 */
#define YES 1
#define NO 0
int x; /*全局变量的说明 */
#include,stdio.h” /*系统函数说明 */
#include,math.h”
int f1(int,int); /*外部函数说明 */
float f2(float,int);
……..
/*****p1.c**********/
#include,my.h”
int x=10; /*定义 */
int f1(int x,int y)
{…,}
main()
{…….
}
/*****p2.c**********/
#include,my.h” float
f2(float,int)
{printf(“%d”,x);
………}
p1.c
p2.c
p.prj
2002 年第五章 函数与程序结构
5.1 C程序的一般结构
1。结构化程序设计基本思想:将一个复杂的问题分解成若干较简单的子问题。
必要时,对子问题进一步分解,每一个子问题称为一个模块,
通过逐步求精,直到分解成一些容易实现的模块(最底层)为止,最终完成算法的功能设置。 (自顶向下的程序设计)
教务管理学生记录 查询统计录入 修改 删除 按学号 综合查询
2,C程序的一般结构
C程序源文件1 源文件 n(n>0)源文件2
函数1 函数2
…..
….,函数 m(m>=0)
说明:
(1) n个源文件中有且仅有一个 main函数,n个源文件组成一个 project,每个源文件可独立编译;
(2) 源程序中仅有说明时,不包括函数;
(3) 函数分系统函数和用户自定义函数。
p1.c p2.c pn.c
…..
5.2 函数定义存储类型区分符 类型区分符 函数名(参数表)
{
说明部分语句部分
}
函数是一段有名称的程序,根据参数表提供的输入数据,
借助于说明部分的变量,通过语句部分的语句执行,实现特定的功能。
说明:
( 1)存储类型区分符说明函数的使用范围:
extern(缺省 ),外部函数,所有 C程序文件中都可以使用 ;
static 静态函数,仅在本 C程序文件中使用 。
( 2) 函数名,除 main之外的标识符。外部函数间不能同名;
同一 C源程序文件中的静态函数也间不能同名。
( 3) 类型区分符,函数的返回值类型,缺省为 int;
void 表示无返回值。
( 4) 参数表,形式参数表(简称 形参表 )
形式,参数说明,参数说明,。。。,参数说明参数说明,类型区分符 形参名
( 5) 函数体和函数返回值,
函数体为一复合语句;
说明部分说明的变量使用范围(作用域)局部于本函数;
函数体为空的函数为哑函数;
函数返回值应与定义的返回类型一致。
例:定义一函数名求整数 xn,x,n均为整数。
分析,在 math.h中有函数说明 double pow(double x,double y)
计算 xy,当 x=0 且 y<=0 或者 x<0且 y不是一整数时,定义域错 。
xn =x*x*….x 结果为一较大的整数。
extern long power(int x,int n)
{
int i; long p=1;
for(i=1;i<=n;i++)
p*=x;
return p;
}
5.3 函数名调用与参数传递
5.3.1 函数调用函数调用表示为使用函数的功能而执行函数。
函数调用形式:
函数名(参数表)
参数表的形式:参数 1,参数 2,。。。,参数 n
各参数是表达式,表达式的值是函数执行时要处理的实际数据。实际参数( 实参 )
例:输入整数 m,计算 m1,m2,….m 10
long power(int x,int n)
{
int i; long p=1;
for(i=1;i<=n;i++)
p*=x;
return p;
}
main()
{
int m,i;
scanf(“%d”,&m);
for(i=1;i<=10;i++)
{ long w;
w=power(m,i);
printf(“power(%d,%d)”
“=%10ld”,m,i,w);
}
}
控制转移,x,n分配单元。 m?x,i?n
释放本次调用分配的所有单元,控制转移,返回 xn
每次执行,
i,p分配单元。
注意:
( 1)实参与形参应在数目上、次序上和类型上一致。
( 2)有返回值的函数,函数调用可作为表达式或语句出现。
getchar (); 作为语句出现,目的等待输入一个字符。
c=getchar (); 作为表达式出现。
power(10,4); 作为语句出现,返回的 104没起作用。
( 3)无返回值(返回类型为 void)的函数,函数调用只能作为语句出现。
( 4)无参数的函数调用形式:函数名()
()不能省却参数的求值次序:
标准 C中,函数调用时,实际参数表达式的求值次序没有规定。 绝大多数编译程序 按 从右至左 进行实际参数表达式的求值(如 TURBO C)。
main()
{
int x=0;
printf(“%d,%d”,x++,x++);
}
TURBO C下,输出结果,1,0
在某些 C编译环境下,输出会是结果,0,1
函数调用转换与参数类型的一致性执行函数调用时所发生的下述实参和形参的类型转换称为 函数调用转换:
( 1) 如无函数说明(或函数说明为传统 C的形式),则对实参进行可能的整数提升,以及 float转换成 double,称为 参数提升 。
main()
{ short a=10,b=20;
long sum(); /*函数说明的传统 C形式,也可省略 */
printf(“sum=%ld”,sum(a,b)); /*对 a,b提升为 int,实参和形参
}
long sum(long x,long y)
{ return x+y; }
类型不匹配,结果不正确。 */
( 2)如函数说明为标准 C的形式,则将实参自动转变成形式参数的类型(类似于赋值)
main()
{ short a=10,b=20;
long sum(long,long); /*函数说明的原型说明 */
printf(“sum=%ld”,sum(a,b)); /*对 a,b自动转换成 long*/
}
long sum(long x,long y)
{ return x+y;
}
( 3) 如果函数定义为传统 C,需要则对形参进行可能的整数提升,而标准 C不需要。
short sum( x,y) /*标准 C的定义形式 */
short x; /*经过整数提升后,形参为 int,int */
short y;
{ return x+y;
}
实参和形参的一致性实参与形参应在数目上、次序上和以及转换后类型上一致。
否则,调用效果不确定。
参数的传递函数调用时,进行实参与形参匹配,即将实参表达式的值传递给形参变量,不是传递地址;
函数中对形参变量的处理,仅仅是对实参的副本,对实参本身无任何影响;
若需要传递地址,必须用指针。
void swap(int x,int y);
{ int temp;
temp=x;x=y;y=temp;
}
main()
{ int x=10,y=20;
swap(x,y);
printf(“x=%d,y=%d”,x,y);
}
main函数
swap(x,y)
第一实参表达式的值,10
第二实参表达式的值,20
swap函数
x:
y:
temp
5.4 函数说明函数说明是对函数的返回值类型、参数的数目和类型的说明;
函数应先定义或先说明,后调用。
1。函数说明的一般形式:
存储类型区分符 类型区分符 函数名(参数类型表)
例,main()
{ long power(int x,int n);
printf(“%ld”,power(10,4)); }
long power(int x,int n)
{ int i; long p=1;
for(i=1;i<=n;i++)
p*=x;
return p; }
一般省略说明:
( 1) 一次定义,多次说明。
( 2)静态函数说明必须指定 static;
( 3)形参为空的函数,说明时参数表应指定 void;
2。函数说明的作用域
( 1)函数说明在函数体外时,从函数说明起到本 C程序文件结束的范围内都能有效调用该函数。
( 2)函数说明在函数体内时,有效调用该函数局限于该函数体。
int f1(int,int);
float f2(…) {… 可调用 f1..}
double f3(….) {… 可调用 f1.,}
int f1(int x,int y)
{………}
float f2(…)
{int f1(int,int);可调用 f1 ….}
double f3(….) { 不可调用 f1,}
int f1(int x,int y)
{………}
数据类型
C变量属性存储类型分配存储单元的多少值域的范围合法的操作分配存储单元的时机变量的生命期变量的初始化方式变量的作用域
5.5 变量的存储类型存储类型分类,
( 1) auto (自动存储类) ( 2) extern (外部存储类)
( 3) static( 静态存储类) ( 4) register(寄存器存储类)
自动变量定义形式:
auto int m,n;
float x,y;
定义位置,函数内或复合语句内。
变量生命期,当函数被调用,或进入复合语句时,产生变量,
分配存储单元,函数执行完或退出复合语句时,释放变量存储单元,变量消亡。
作用域,函数内或复合语句内。
缺省初始化方式,不定显式初始化方式,int m=10; 等价于 。
int m;
m=10;
外部(全局)变量定义、说明形式,float x,y;
extern int m,n;
编译将第一次遇到的理解为定义、以后遇到的理解为说明。
定义位置,函数外。
变量生命期,当 C程序开始执行时,分配存储单元,程序执行完后,释放变量存储单元,变量消亡。生命期同于 C程序的执行时间。
作用域,所有 C源程序文件。定义之后的源程序部分都可以使用该变量,其他位置可先说明,后使用。
缺省省初始化方式,0 或 0.0 或 ‘ \0?
注意,显式初始化方式为变量的定义。 int a=10;
静态变量
( 1)外部静态变量定义形式:
static int m,n;
定义位置,函数外。
变量生命期,当 C程序开始执行时,分配存储单元,程序执行完后,释放变量存储单元,变量消亡。生命期同于 C程序的执行时间。
作用域,当前 C源程序文件。定义之后的源程序部分都可以使用该变量,其他位置可先说明,后使用。
缺省初始化方式,0 或 0.0 或 ‘ \0?
显式初始化方式,stactic int m=10;。
静态变量
( 2)局部静态变量定义形式:
static int m,n;
定义位置,函数内或复合语句内。
变量生命期,当 C程序开始执行时,分配存储单元,程序执行完后,释放变量存储单元,变量消亡。生命期同于 C程序的执行时间。
作用域,函数内或复合语句内。
缺省初始化方式,0 或 0.0 或 ‘ \0?
显式初始化方式,stactic int m=10; 不等价于 。
stactic int m; m=10; 且仅赋值一次。
寄存器变量定义形式:
register int m,n;
定义位置,函数内或复合语句内。
变量生命期,当函数被调用,或进入复合语句时,产生变量,
当有空闲寄存器时,分配寄存器,无则分配存储内存单元,
函数执行完或退出复合语句时,释放变量存储分配,变量消亡。
作用域,函数内或复合语句内。
缺省初始化方式,不定例 1:变量的作用域。
#include,stdio.h”
int x=10,y=20; /*外部变量 */
main()
{ float x=12.3; /*自动变量 */
int i;
{
char x=?a?; /*自动变量 */
printf(“x=%c”,x);
}
printf(“x=%f”,x);
}
变量作用域重叠时,
内层屏蔽外层。
例 2:多源程序文件组成的 C程序。
/********源程序 1,test1.c **************/
#include,stdio.h”
static int x=500; /*外部静态变量,与 test2.c的 x同名,
静态变量定义与说明同一 */
float y=100,f2(float,float); /*外部变量定义和外部函数说明 */
float f1(float a,float b);
{ return (a*b-x+y); }
void main(void)
{
printf(“f1=%f,f2=%f\n”,f1(x,y),f2(x,y));
}
/********源程序 2,test2.c **************/
extern float y; /*外部变量说明 */
extern float x; /*外部变量定义 */
float f2(float a,float b)
{
return (a/b+y);
}
外部变量 x的作用域外部变量 y的作用域外部静态变量 x的作用域
C项目的建立过程:
( 1)选择菜单,Project”的子菜单项,Project name”
输入项目名,test
( 2)编辑 (new)产生项目的文本文件,test.prj
test1.c
test2.c
注,对 test1和 test2可分别进行编译
( 3)连接、运行。
( 4)该 C程序调试完成后,选择菜单,Project”的子菜单项,Clear Project”
例 2:静态局部变量:
int sum(n)
{
static int s=0;
int i;
for(i=1;i<=n;i++)
s=s+i;
return s;
}
main()
{
int i;
for(i=1;i<=5;i++)
printf(“\nsum of 1 to %d=%d”,i,sum(i));
}
输出:
sum of 1 to 1=1
sum of 1 to 2=4
sum of 1 to 3=10
sum of 1 to 4=20
sum of 1 to 5=35
5.6 递归函数与递归调用
1.递归函数的概念。
间接递归调用:
int f1(…)
{ ………
f2(…)
………
}
void f2(…)
{ …..
x=f1(…);
……
}
直接递归调用:
long FiBo(int n)
{
long f1,f2;
if (n==1 ||n==2) return 1;
f1=FiBo(n-1);
f2=FiBo(n-2);
return f1+f2;
}
2。 递归算法思想:
在以一种方法求解问题时,将复杂的问题分解成相对简单的子问题,而在求解子问题时,使用同样的方法进行。
求解规模位 n的问题分解
1.特殊情况的求解:
(如,n=1,n=2等)
2.分解成子问题:
3.求解规模位 n的问题求解规模为
n-1的问题求解规模为
n-2的问题
3。 递归函数的定义:
例,计算 n的阶乘的算法,
1 n=0 特殊情况的求解
n!=
n*(n-1)! n>0
long fac(int n)
{
long f;
if (n==0) return 1; /*特殊情况的处理 */
f=fac(n-1); /*子问题的处理 */
return n*f; /*最后的求解 */
}
4。 递归函数的执行过程:
main() {
printf(“%ld”,fac(3));
}
递推过程,
fac(3)
变量存储分配,
n,3
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
变量存储分配,
n,2
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
变量存储分配,
n,1
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
变量存储分配,
n,0
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
各个 n,f 分配不同存储单元
fac(3)
变量存储分配,
n,3
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
变量存储分配,
n,2
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
变量存储分配,
n,1
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
变量存储分配,
n,0
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
fac(3)
变量存储分配,
n,3
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
变量存储分配,
n,2
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
变量存储分配,
n,1
f,1
if (n==0)
return 1;
f=fac(n-1);
return n*f;
回归过程:
1
1
fac(3)
变量存储分配,
n,3
f,?
if (n==0)
return 1;
f=fac(n-1);
return n*f;
变量存储分配,
n,2
f,1
if (n==0)
return 1;
f=fac(n-1);
return n*f;
回归过程:
2
fac(3)
变量存储分配,
n,3
f,2
if (n==0)
return 1;
f=fac(n-1);
return n*f;
6
5.7 编译预处理以 #开头、以换行符结尾的行称为 编译预处理指令。
#define PI 3.14159
#include,stdio.h”
编译预处理指令 不是 C语言的语法成分;
编译之前 要首先处理,编译程序自动调用编译预处理程序。
常用编译预处理包括:
( 1)宏替换;
( 2)文件嵌入;
( 3)条件编译;
5.7.1 宏替换
( 1) 简单宏替换
#define 标识符 单词串功能,在定义点以后的程序中,替换所有与该标识符相同的为指定符号串形式。不包括字符串常量中的符号。
#define PI 3.14159
printf(“PI=%d”,PI),?printf(“PI=%d”,3.14159),
( 2) 带参数的宏替换
#define 标识符(标识符,标识符,….,标识符) 单词串功能,在定义点以后的程序中,替换所有与该标识符结构相匹配的形式为指定符号串形式。不包括字符串常量中的符号。
#define SUM(a,b) a+b
#define MUL(a,b) a*b
int x=10,y=20;
printf(“SUM=%d”,SUM(x,y)),?printf(“SUM=%d”,x+y),
printf(“%f”,SUM(10.0,20.0)),?printf(“%f”,10.0+20.0),
printf(“%f”,MUL(1+2,3+4)),?printf(“%f”,1+2*3+4),
( 3)取消宏名定义
#undef 标识符例:
main()
{
int x=10,y;
#define x 20
y=4*x; printf(“y=%d”,y);
#undef x
y=4*x; printf(“y=%d”,y);
}
5.7.2 文件嵌入功能,将指定文件内容插入到该位置。
形式:
#include <文件名 >
#include,文件名”
#include 标识符文件名可以包括路径。按路径指示查找文件;
无路径时,<文件名 >按标准方式查找 ;,文件名”方式首先在该文件所在目录下查找,未找到时再按标准方式查找。
标准方式指由环境所设路径。
/*******文件 my.h***************/
#define PI 3.14159 /*常量定义 */
#define YES 1
#define NO 0
int x; /*全局变量的说明 */
#include,stdio.h” /*系统函数说明 */
#include,math.h”
int f1(int,int); /*外部函数说明 */
float f2(float,int);
……..
/*****p1.c**********/
#include,my.h”
int x=10; /*定义 */
int f1(int x,int y)
{…,}
main()
{…….
}
/*****p2.c**********/
#include,my.h” float
f2(float,int)
{printf(“%d”,x);
………}
p1.c
p2.c
p.prj