9299.net
大学生考试网 让学习变简单
赞助商链接
当前位置:首页 >> 其它课程 >>

C语言程序设计 用函数实现模块化程序设计

C语言程序设计 用函数实现模块化程序设计


1

C 语言程序设计
第七章 用函数实现模块化程序设计
北京航空航天大学 交通科学与工程学院 徐国艳

本章要点
函数的定义、说明与调用 ? 函数之间参数传递规则 ? 函数递归调用和嵌套调用 ? 变量的存储类型与特性
?

2/73

第七章 用函数实现模块化程序设计

3/73

7.1 概述
一、模块化程序结构
一个较大的应用程序应分为若干个程序模块,每一 个模块用来实现一个特定的功能。所有的高级语言

都有子程序概念,用子程序实现模块的功能。

主模块

模块1
模块11

模块2
模块21 模块22
4/73

在 C 语言中是利用函数来实现子程序的作用。

学生成绩 管理系统

成绩 录入

成绩 查询

成绩 统计

成绩单 打印
5/73

采用模块化程序设计的优越性:
?
? ? ? ?

控制程序设计的复杂性
提高软件的可靠性

提高软件开发的效率
提高软件的可维护性 提高程序的重用性

6/73

二、C程序的结构
?

函数

main ( )
?

F1 ( ) F11 ( ) F21 ( )

F2 ( )
?

F22 ( )
?

黑盒子

C程序是函数的集合体, 每个函数是一个独立 的程序模块; 有一个主函数,若干 个子函数; 所有子函数地位平等, 可相互调用、自我调 用; 函数可集中或分散存 放在一个或多个源程 序文件中。

7/73

三、C函数的分类
数学函数 (math.h) 字符和字符串函数 ( ctype.h,string.h) I/O函数 ( stdio.h) 动态存储分配函数(stdlib.h或malloc.h) 详见P384附录F

库函数

用户定义函数
形式

无参函数 有参函数 空函数

8/73

四、C程序的执行顺序
?

?

?

一个源程序文件,由一 个或多个函数以及其他 有关内容组成,是一个 编译单位,函数不是一 个编译单位。 C程序的执行总是从 main函数开始,调用其 它函数后回到main函数, 在main函数中结束整个 程序的运行; 所有的子函数都是平行 的,任何子函数都不属 于其他函数;

例7- 1 #include <stdio.h> void printstar() { printf(“*************\n”); } void printmessage() {printf(“ Hello,world.\n”); printstar(); } void main() { 这两个函数能单独执行吗? printstar(); printmessage(); }

不能

9/73

7.2 函数的定义
一、函数定义的一般形式
类型说明 函数名([形式参数说明]) { 函数体} 例7- 2 形式参数说明方法: #include <stdio.h> 类型说明 变量名1[,类型说明 变量名2 ] … int max(int x,int y) { int z; 1.无参函数的定义形式 z=x>y?x: void printstar() y; return( z ); { printf(“***************”); 类型说明 函数名() } { 函数体} } void main() { int a,b,c ; 2.空函数的定义形式 void function(int a, float y) scanf(“%d,%d”,&a,&b); 类型说明 函数名([形式参数说明]) { c=max(a,b); } printf(“The max is %d”, c); { } }

10/73

7.2 函数的定义
二、函数体组成

?一般情况下,函数体由

两部分组成: { [局部变量说明] 语句 } ? 局部变量: 函数体内定义的变量, 其有效范围仅在函数内部, 离开函数体无意义。

11/73

7.3 函数参数和函数的值
例7- 2 #include <stdio.h> int max(int x,int y) { int z; z = x > y ? x : y; return( z ); } 主调函数 被调用函数 void main() ┇ int max(int x,int y) { int a,b,c ; a, b scanf(“%d,%d”,&a,&b); c=max (a,b); { c=max(a,b); ┇ z ┇ printf(“The max is %d”, ); return( z ); } }
各函数的信息往来主要是由参数传递和返回语句实现的
12/73

一个C程序由若干个函数组成, 各函数调用时经常要传递一些 数据,调用函数把数据传递给 被调用函数,经被调用函数使 用后,一般会返回一个确定结 果,在返回调用函数时,把这 些结果带回调用函数。

7.3 函数参数和函数的值
一、形式参数和实际参数
函数参数用于函数间数据的传递 形式参数:定义函数时使用的参数 实际参数:调用函数时使用的参数 函数max有两个形式参数x和y 形参x和y只在max函数中使用 a和b是主函数中定义的变量 main函数调用max函数 a和b是max函数的实参 例7- 2 #include <stdio.h> int max(int x,int y) { int z; z = x > y ? x : y; return( z ); } void main() { int a,b,c ; scanf(“%d,%d”,&a,&b); c=max(a,b); printf(“The max is %d”, c); } 23,56 The max is 56
13/73

7.3 函数参数和函数的值
一、形式参数和实际参数
说明: 1.定义函数时,必须说明形参类 型,形参只能是变量和数组; 2.函数被调用前,形参不占内存 ,函数调用结束后,内存也被释 放; 3.实参可以是常量、变量和表达 式; 4.实参和形参的类型必须一致, 字符型和整型可以相互匹配; 5.C语言中实参对形参的数据传 递是“值传递”,即单向传递 ,仅由参数的对应位置决定,与 名字无关。 例7例8- 2 #include <stdio.h> int max(int x,int y) b,int a) { int z; c; c x b a b: y; z = x > y ? x : a; return( z ); c x } void main() { int a,b,c ; scanf(“%d,%d”,&a,&b); c=max(a,b); printf(“The max is %d”, c); } 23,56 The max is 56
14/73

7.3 函数参数和函数的值
一、形式参数和实际参数
例7-3 读程序,写程序结果 #include <stdio.h> int sum(int a,int b) { int c; a=a+b; b=a+b; c=a+b; printf(“sum:%d+%d = %d\n”, a,b,c); return a; } void main() { int a=1,b=3,c ; c=sum(a,b); printf(“main:%d+%d = %d\n”, a,b,c); }
15/73

7.3 函数参数和函数的值
二、函数的返回值
例7例8- 2 1.返回函数值的方法 #include <stdio.h> (1)函数的返回值也就是函数的 int max(int x,int y) y) int max(int x,int 值,如果一个函数有返回值, { int z; { if(x>y) return y; ; z = x > y ? x :>(x) ? x : y ); 就必须用return语句; return(x y return return((zz); ); } (2)一个函数中可以有多个 } void main() return语句,无论执行到哪 void main() { int a,b,c ; 个return语句,都将结束函 { int a,b,c ; scanf(“%d,%d”,&a,&b); 数调用,返回主调函数。 scanf(“%d,%d”,&a,&b); c=max(a,b); c=max(a,b); (3) return语句中的括号可以 printf(“The max is %d”, c); printf(“The max is %d”, c); } 省略,return后面可以是一 } 个表达式,返回的是表达式 的值。
16/73

7.3 函数参数和函数的值
2. 函数值的类型
(1)函数的类型也就是函数值 的类型,函数max是int型 的,函数max的值也是int 型的; (2)省略了类型说明的函数是 int型; (3)return语句中的表达式一 般应与函数类型一致。如 果不一致,需要进行类型 转换,只有数值型数据可 以进行自动类型转换,以 函数类型为准。 例7- 2 #include <stdio.h> int max(int x,int y) { int z; z = x > y ? x : y; return( z ); } void main() { int a,b,c ; scanf(“%d,%d”,&a,&b); c=max(a,b); printf(“The max is %d”, c); }
17/73

7.3 函数参数和函数的值
3.不需要返回值的函数
(1)如果函数中没有使用 return语句,函数返回的 是一个不确定的值; (2)如果一个函数不需要返回 值,可以用void做类型说 明; (3)如果一个函数被声明为 void型的,就不允许再引 用他的返回值,只能用函 数语句形式调用;
例7- 1 #include <stdio.h> void printstar() { printf(“***************”); } void printmessage() { printf(“ Hello,world.\n”); printstar(); } void main() { printstar(); printmessage(); }

18/73

7.4 函数的调用
一. 函数调用的一般形式
函数名(实参表列)

说明:
1.如果调用无参函数,实 参表列部分没有,但括号 不能省略; 2.实参的个数和形参个数 一般相等; 3.实参和形参的类型一一 对应,必要时使用类型转 换; 4.实参变量定义在调用函 数之前完成。

例7- 2 #include <stdio.h> int max(int x,int y) { int z; z = x > y ? x : y; return( z ); } void main() { int a,b,c ; scanf(“%d,%d”,&a,&b); c=max(a,b); printf(“The max is %d”, c); }

19/73

7.4 函数的调用
二. 函数调用的方式
1.函数语句 形式为:函数名(实参表列); 例如: printmessage(); printf(“%d”,a); 2.函数表达式

说明:这种方式不要求 函数带返回值,函数仅 完成一定的操作。

函数的值参与运算 例如: m=max(a,b); m=3*max(a,b); printf(“The max is %d”, max(a,b));
说明:这种方式不能 用于void类型。
20/73

7.4 函数的调用
三. 函数调用的执行过程 1.按从右到左的顺序 ,计算实参各表达式 的值; 2.按照位置,将实参 的值一一传给形参; 3.执行被调用函数; 4.当遇到return(表达 式)语句时,计算表达 式的值,并返回主调 函数。
21/73

7.4 函数的调用
四. 函数的声明
在程序中调用函数要 满足以下条件:
1.被调函数必须存在, 且遵循先定义,后使 用的原则; 2.如果函数在主调函 数之后定义,则应在 主调函数中或主调函 数之前对被调函数进 行声明。

#include <stdio.h> #include <stdio.h> void main( ) x ) int sum ( int {int sum ( int x ); { int i,t=0; intfor (i=1; i<=x; i++) s; s=sum (100); t+=i; printf("%d\n", s); return (t); } } int main( ) voidsum ( int x ) { int i,t=0; { int s; s=sum (100); i++) for (i=1; i<=x; printf("%d\n", s); t+=i; } return (t);}
22/73

函数声明的一般形式

int max(int x,int y); int max(int ,int);

函数声明与函数定义的格式区别:
?函数声明语句的( )后必须有分号,而函数定义( )后 没有分号。 ?函数声明只有一条语句,没有函数体,而函数定义 有多条语句,有函数体。
23/73

?

例7-5 已知汽车以速度ua等速行驶的阻 力功率为P,燃油消耗率为b,求汽车以 速度ua等速行驶百公里燃油消耗量。 百公里燃油消耗量计算公式为:

Pb Qs ? 1.02ua ?g

24/73

例7- 5 Pb #include <stdio.h> Qs ? #define g 9.8 1.02ua ?g void main() { float qsf(float,float, float,float); //百公里燃油消耗量函数声明 float qresult,p, b, ua, rou; //实参变量定义 printf("p, b, ua, rou =\n"); scanf("%f,%f, %f,%f,%f",&p,&b, &ua, &rou); //实参变量赋值 qresult =qsf(p, b, ua, rou); //百公里燃油消耗量函数调用 printf(“qresult=%d\n",qresult);} }
/*百公里燃油消耗量函数定义*/

float qsf(float p,float b, float ua,float rou ) { float qs; qs=p*b/(1.02*ua*rou*g); return qs; //函数返回值 }

25/73

例7-6 设计一个程序完成下面表达式的计算,其中 m,n为正整数且m>n.

m!n! (m - n)!

例8- 6 #include <stdio.h> int factor(int k ) //求阶乘函数定义 { int i, kfactor=1; for(i=k;i>1;i--) kfactor*=i; return kfactor; //阶乘函数返回值 } void main() { //三次调用阶乘函数 int m,n,result; printf("m,n= \n"); scanf("%d,%d",&m,&n); result =factor(m)*factor(n)/factor(m-n) ; 26/73 printf("result=%d\n",result);}

7.5 函数的嵌套调用和递归调用
一、函数的嵌套调用
main函数 { …… …… 函数 A { …… …… 调用函数 B; 函数 B { ……

……
…… }

调用函数 A;
……

……
}
27/73

}

void main( ) { int n=3; printf (“%d\n”, sub1(n)); }

sub1(int n) { int i,a=0; for (i=n; i>0; i--) a+=sub2(i); return a;
}

程序输出结果: 9

函数调用可以嵌套

函数定义不可嵌套

sub2(int n) { return n+1; }
28/73

7.5.2 函数的递归调用
1.递归的基本概念
递归调用:一个函数直接或间接地调用了它本身 ,就称为函数的递归调用。 递归函数:在函数体内调用该函数本身。 例如: int sub(int x) { int y,z; …… if( …… ) z=sub(y); 直接调用sub else { …… } return ; 函数本身 }
29/73

2.递归函数的执行过程
【例7.16】编一递归函数求n!。
思路:以求4的阶乘为例: 4!=4*3!,3!=3*2!,2!=2*1!,1!=1,0!=1。 递归结束条件:当n=1或n=0时,n!=1。 递归公式:

n! =

1 (n=0, 1) n×(n-1)! (n>1)

30/73

?

用递归函数求n! – n! = 1 当n=1时 – n! = n * (n-1)! 当 n > 1 时

#include <stdio.h> void main ( ) { int n, p; printf ("n=?");scanf ("%d", &n); p = fact (n); printf ("%d!=%d\n", n, p); } int fact ( int n ) { int r; if ( n == 1 ) r = 1; else r=n*fact(n-1); /* 递归调用 */ return (r);}

31/73

递归调用执行过程
递 推 void main( ) fact( 4 ) { { … … fact( 3 ) { … fact(2 ) { … fact(1 ) { …

p=fact(4);

r=4*fact(3); r=3*fact(2); r=2*fact(1); r=1;


}

… return 24 }

… return 6 }
回 推

… return 2 }

… return 1 }

32/73

3.编制递归函数的方法
⑴ 数值型问题递归函数的编程方法
对于数值型问题,首先要找出解题的数学公式, 这个公式必须是递归定义的,且所处理的对象要 有规律地递增或递减,然后确定递归结束条件。 【例8.17】编一递归函数求xn 。 思路:首先把xn转化成递归定义的公式

x =
n

1 (n=0) x × xn - 1 (n>0)

再找出递归结束条件:当n=0时,xn=1。
33/73

程序如下:
#include <stdio.h> long xn(int x,int n) { long f=0; if (n<0) printf("n<0,data error!\n"); else if (n==0) f=1; else f=x*xn(x,n-1); return (f); 程序运行情况如下: } 2,10? void main( ) 1024 { int n,x; long y; scanf("%d,%d",&x,&n); y=xn(x,n); printf("%ld\n",y); }
34/73

(2) 非数值型问题递归函数的编程方法

Hanoi(汉诺塔问题)

A

B

C

35/73

36/73

37/73

38/73

#include <stdio.h> void move(char getone, char putone) { printf("移动%c针最上面一个盘到%c针\n",getone,putone); } void hanoi(int n,char one,char two,char three) { //借助two针,把one针上n个盘子移到three针上 if(n==1) move(one,three); else { hanoi(n-1,one,three,two); //借助three针把one上n-1个盘子移到two move(one,three); //把A上1个盘子移到C hanoi(n-1,two,one,three); //借助one针把two上n-1个盘子移到three } }
39/73

#include<stdio.h> void main() { int m;

printf("Input the number of disks:");
scanf("%d",&m); printf("The steps to moving %3d disks:\n",m); hanoi(m,'A','B','C'); }
40/73

7.6 数组作函数参数
7.6.1 一维数组元素作函数参数(值传递) 例 两个数组大小比较
a和b为有6个元素的整型数组; 比较两数组对应元素; 变量n,m,k记录a[i]>b[i], a[i]==b[i], a[i]<b[i]的个数; 最后 若n>k,认为数组a>b; 若n<k,认为数组a<b; 若n==k,认为数组a==b。
41/73

a 0 1 2

b
i i i i i i i=1 n=0 m=1 k=1

12
23 56 10 76

43 23
21

0 1 2

n:a[i]>b[i]元素个数 m:a[i]==b[i]元素个数 k:a[i]<b[i]元素个数

3
4 5

98 66
54 i=2 n=1 m=1 k=1

3
4 5 i=3 n=1 m=1 k=2 i=4 n=2 m=1 k=2 i=5 n=3 m=1 k=2
42/73

88
i=0 n=0 m=0 k=1

i=0 n=0 m=0 k=0

#include <stdio.h> void main() { int a[10],b[10],i,n=0,m=0,k=0; printf("Enter array a:\n"); for(i=0;i<10;i++) scanf("%d",&a[i]); printf("Enter array b:\n"); for(i=0;i<10;i++) scanf("%d",&b[i]); for(i=0;i<10;i++) { if(large(a[i],b[i])==1) n=n+1; else if(large(a[i],b[i])==0) m=m+1; else k=k+1; } /* Output */ }

int large(int x,int y) { int flag; if(x>y) flag=1; else if(x<y) flag=-1; else flag=0; return(flag); }

43/73

7.6 数组作函数参数
7.6.2 一维数组名作函数参数
? 数组名表示数组在内存中的起始地址。

例如:数组a在内存中从2000地址开始存放,则a的 值为2000。2000是地址值。
?

如实参是数组名,形参应定义为数组形式,形参 数组的长度可以省略,但[ ]不能省,否则就不是 数组形式了。 【例8.12】用冒泡法将10个存放在一维数组中的 整数排序。
44/73

void sort(int b[ ],int n); void printarr(int b[ ]); void main( ) { int a[10] = {11,22,63,97,58,80,45, 32,73,36}; printf("Before sort:\n"); printarr(a); sort(a,10); printf("After sort:\n"); printarr(a); }

void printarr(int b[10]) { int i; for (i=0; i<10; i++) printf("%5d",b[i]); printf("\n");} void sort(int b[ ], int n) { int i,j,t; for (i=1; i<n; i++) for (j=0; j<n-i; j++ ) if (b[j]>b[j+1]) { t=b[j];b[j]=b[j+1];b[j+1]=t; } }
45/73

实参赋给形参

a:2000 b

2000

形参 b 实际是一个 可以存放地址的变量

a[0] a[1] a[2] a[3] a[4 ] a[5] a[6] a[7] a[8] a[9]

11 22 63 97 58 80 45 32 73 36
b[0] b[1] b[2] b[3] b[4] b[5] b[6] b[7] b[8] b[9]

首地址: 2000

(a) 排序前
a[0] a[1] a[2] a[3] a[4 ] a[5] a[6] a[7] a[8] a[9]

11 22 32 36 45 58 63 73 80 97
b[0] b[1] b[2] b[3] b[4] b[5] b[6] b[7] b[8] b[9]

(b) 排序后

图8.3 调用sort函数

46/73

#include "stdio.h" void scat(char str1[ ], char str2[ ]) void main( ) { int i=0,k=0; { while (str1[i]!='\0') i++; void scat(char str1[ ],char str2[ ]); while (str2[k]!=?\0') char s1[50],s2[50]; { int i,k; str1[i]=str2[k]; printf("Input s1:"); i++; k++; gets(s1); } printf("Input s2:"); str1[i]='\0'; gets(s2); } scat(s1,s2); printf("Output s1:%s\n",s1); printf("Output s2:%s\n",s2); }
47/73

8.6.2 多维数组作函数参数
以二维数组为例。 ? 二维数组名作实参时,对应的形参也应该定义为一个二 维数组形式。 ? 对形参数组定义时可以指定每一维的大小,也可以省略 第一维的大小说明。

【例8.14】编程序,将矩阵转置。设转置前为a矩阵 ,转置后为b矩阵,如下所示: 1 5 9 1 2 3 4 2 6 10 a= b= 5 6 7 8 3 7 11 9 10 11 12 4 8 12
思路:将a[0][0]?b[0][0],a[0][1]? b[1][0],a[0][2]?b[2][0], a[1][0]?b[0][1],…,a[i][j]?b[j][i],…。
48/73

#include <stdio.h> void turn(int arra[ ][4],int arrb[ ][3]) ; void main( ) { int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; int i,j,b[4][3]; … turn(a,b); printf("array b:\n"); for (i=0; i<4;i++) { for (j=0; j<3;j++) printf("%5d",b[i][j]); printf("\n"); /* 矩阵转置函数*/ } void turn(int arra[ ][4],int arrb[ ][3]) } { int r, c; for (r=0; r<3;r++) for (c=0; c<4;c++) arrb[c][r]==arra[r][c]; 49/73 }

7.7 局部变量和全局变量
1. 变量的作用域
变量的作用域:变量在程序中可以被使用的范围。 根据变量的作用域可以将变量分为局部变量和全局 变量。

2. 局部变量及其作用域
局部变量(内部变量):在函数内或复合语句内定 义的变量以及函数的形参。

作用域:函数内或复合语句内
【例7.19】分析下面程序的运行结果及变量的作用域。
50/73

#include<stdio.h> void sub(int a,int b) { int c; sub函数局部变量 a=a+b; b=b+a; c=b-a; printf("sub:\ta=%d b= %d c= %d\n",a,b,c); } void main( ) main函数局部变量 { int a=1,b=1,c=1; printf("main:\ta=%d b= %d c= %d\n",a,b,c); sub(a,b); printf("main:\ta=%d b= %d c= %d\n",a,b,c); { 复合语句局部变量 int a=2,b=2; 程序输出结果: printf("comp:\ta=%d b= %d c= %d\n",a,b,c); main: a=1 b= 1 c= 1 } sub: a=2 b= 3 c= 1 printf("main:\ta=%d b= %d c= %d\n",a,b,c); main: a=1 b= 1 c= 1 } comp: a=2 b= 2 c= 1 51/73 main: a=1 b= 1 c= 1

3 全局变量及其作用域 全局变量(外部变量):在函数外部定义的 变量。 作用域:从定义变量的位置开始到本源文件 结束。如在其作用域内的函数或分程序中定 义了同名局部变量,则在局部变量的作用域 内,同名全局变量暂时不起作用。 【例7.20】全局变量和局部变量的作用域。

52/73

#include<stdio.h> 全局变量 void main( ) { int b=6,c=7; int a= 5; main函数局部变量 f(b,c); void f(int x, int y) printf("%d %d %d\n",a,b,c); { int b,c; { int a=9,b=8; 复合语句局部变量 b=a+x; f函数局部变量 printf("%d %d %d\n",a,b,c); c=a-y; { c=10; printf("%d %d %d\n",a,b,c); printf("%d %d %d\n", a,b,c); } } printf("%d %d %d\n",a,b,c); 程序输出结果: } 5 11 -2 printf("%d %d %d\n",a,b,c); 5 6 7 } 9 8 7 9 8 10 9 8 10 5 6 10
53/73

7.8 变量的存储类别
局部变量和全局变量是从变量的作用域(空间)来划分的。

从变量存在的时间(即生存期)来分,又可以分为 静态存储方式和动态存储方式。 ?静态存储方式:程序运行期间分配固定存储空 间; ?动态存储方式:程序运行期间根据需要动态分 配存储空间。

54/73

变 量 的 属 性

数据类型: 决定为变量分配内存单元的长度, 数据的存放形式,数的范围。 存储类别: 决定了变量的生存期, 给它分配在哪个存储区。

变量定义语句的完整形式:
存储类别 数据类型 变量名1, … , 变量名n ;
auto(自动的) register(寄存器的) static(静态的) extern(外部的)

55/73

? 内存用户区
程序区 静态存储区 动态存储区 全局变量、局部静态变量
形参变量 局部动态变量(auto register) 函数调用返回地址等

56/73

1.自动变量(auto类别) 局部变量可以定义为自动变量。

可省

main() {int x,y; … }

等价
自动变量

main() {auto int x,y; … }

57/73

自动变量
⑴ 内存分配 int a=5; 调用函数或执行分程序时在 例8- 2 void main( ) 动态存储区为其分配存储单 #include <stdio.h> { b=6,c=7; 元,函数或分程序执行结束, int int max(int x,int y) printf("%d %d %d\n",a,b,c); 所占内存空间即刻释放。 { int z; { int z = x > y ? x : y; a=9,b=8; ⑵ 变量的初值 printf("%dz%d %d\n",a,b,c); return( ); 定义变量时若没赋初值,变 } { c=10; 量的初值不确定;如果赋初 void main() printf("%d %d %d\n", a,b,c); 值则每次函数被调用时执行 } { int a,b,c ; 一次赋值操作。 scanf(“%d,%d”,&a,&b); printf("%d %d %d\n",a,b,c); ⑶ 生存期 c=max(a,b); } 在函数或分程序执行期间。 printf(“The max is %d”, c); printf("%d %d %d\n",a,b,c); } ⑷ 作用域 } 自动变量所在的函数内或分 程序内。
58/73

2.静态变量(static类别)
除形参外,局部变量和全局变量都可以定义为静 态变量。 静态局部变量(或称静态内部变量) 静态变量 静态全局变量(或称静态外部变量) static int a; void main( ) { float x,y; …} f( ) { static int b=1; …… } 静态全局变量 自动变量

不 能 省

静态局部变量
59/73

静态变量
⑴ 内存分配 static int a; 编译时,将其分配在内存的静态存 int f( ) 储区中,程序运行结束释放该单元。 { static int b=1; ⑵ 静态变量的初值 …… 若定义时未赋初值,在编译时,系 统自动赋初值为0;若定义时赋初值,} 则仅在编译时赋初值一次,程序运行 void main( ) 后不再给变量赋初值。 { float x,y; ⑶ 生存期 static int b=1; 整个程序的执行期间。 … { static c=10; ⑷ 作用域 … 静态局部变量的作用域是它所在的 函数或分程序。静态全局变量的作用 } 域是从定义处开始到本源文件结束。 } 60/73

3.外部变量(extern类别)
在函数外定义的变量若没有用 static说明,则是 外部变量。外部变量只能隐式定义。
int c; static int a; void main( ) { float x,y; …} char s; f( ) { static int b=1; …… }

静态外部变量 自动变量

外部变量

局部静态变量
61/73

外部变量
⑴ 内存分配 int c; 编译时,将其分配在静态存储区, static int a; 程序运行结束释放该单元。 void main( ) ⑵ 变量的初值 { float x,y; 若定义变量时未赋初值,在编译 …} 时,系统自动赋初值为0。 char s; f( ) ⑶ 生存期 { static int b=1; 整个程序的执行期间。 …… ⑷ 作用域 } 从定义处开始到本源文件结束。
62/73

外部变量的声明
#include"stdio.h" int p=1,q=5; 定义外部变量 int f1(int a) 用extern进行声明 {extern char c1,c2; 声明外部变量 ,以使其作用域扩 c1=a; c2=2*a; 大 return a*a; } char c1,c2; 定义外部变量 void main() 思考:在f1函数中声 { 明c1,c2的作用是什 int a; 么?如何修改使所有 a=f1(10); 函数可以使用外部变 printf("a,c1,c2=% 量而不需要声明。 d,%d,%d\n",a,c1,c2); 63/73 }

外部变量声明的一般格式
extern 数据类型 变量名1,…,变量名n; #include"stdio.h" 或 int p=1,q=5; extern 变量名1,…,变量名n; int f1(int a)

{extern char c1,c2; 注意: c1=a; c2=2*a; ①外部变量声明用关键字extern, return a*a; 而外部变量的定义不能用 } char c1,c2; extern,只能隐式定义。 void main() ②定义外部变量时,系统要给变 { 量分配存储空间,而外部变量 int a; 声明时,系统不分配存储空间, a=f1(10); 只是让编译系统知道该变量是 … 一个有定义的外部变量,与函 }

数声明的作用类似。

64/73

// file1.cpp文件程序如下: #include<stdio.h> int i; 定义外部变量 void main() { void f1(),f2(),f3(); i=1; f1(); printf("\tmain:i=%d",i); f2(); printf("\tmain:i=%d",i); f3(); printf("\tmain:i=%d\n",i); } void f1() { i++; printf("\nf1:i=%d",i); }

//file2.cpp 文件程序如下: #include<stdio.h> extern int i; 声明外部变量 void f2() { int i=3; printf("\nf2:i=%d",i); } void f3() { i=3; printf("\nf3:i=%d",i); }

65/73

4.寄存器变量(register类别)
只有函数内定义的变量或形参可以定义为寄存器 变量。寄存器变量的值保存在CPU的寄存器中。 受寄存器长度的限制,寄存器变量只能是char、 int和指针类型的变量。 【例8.26】寄存器变量的使用。 void main( ) { long int sum=0; register int i; for (i=1; i<=1000; i++) sum+=i; printf("sum=%ld\n",sum); }

程序输出结果: sum=500500

66/73



变量存储类型
局部变量 外部变量 局部static 外部static 静态 静态存储区 外部

存储类别 存储方式

auto

register 动态

寄存器 存储区 动态区 生存期 函数调用开始至结束

程序整个运行期间

作用域 定义变量的函数或复合语句内 本文件 其它文件 赋初值 每次函数调用时 编译时赋初值,只赋一次 未赋初值 不确定 自动赋初值0或空字符 ?局部变量默认为auto型 ?register型变量个数受限,且不能为long, double, float型 ?局部static变量具有全局寿命和局部可见性 extern不是变量定义,可扩展外部变量作用域
67/73

7.7 函数的存储分类
内部函数: static int func( ) { …… }
外部函数: extern int fan(char a,char b) { …… }
extern可以省略

外部函数和静态函数区别: 外部函数允许本程序其他文件中的函数调用 (与外部变量类似)。 内部函数禁止本程序其他文件中的函数调用 (与静态外部变量类似)。
68/73

外部函数调用例子
从键盘输入一行字符放在str数组中,然后 从键盘输入一个字符c,从str 中把字符c 删除,然后输出str字符。 ? 要求
?
– – –



1.在file1文件中定义主函数 2.在file2文件中定义字符串输入函数 3.在file3文件中定义删除字符函数 4.在file4文件中定义字符串输出函数

69/73

//file1.cpp: #include<stdio.h> void main() { extern void enter_string(char str[80]); extern void delete_string(char str[],char ch); extern void print_string(char str[]); char c; char str[80]; printf("请输入字符串:\n"); enter_string(str); printf("请输入需要删除的字符:\n"); scanf("%c",&c); delete_string(str,c);

//file2.cpp: #include<stdio.h>
void enter_string(char str[80]) { gets(str);} //file3.cpp: void delete_string(char str[],char ch) { int i,j; for(i=j=0;str[i]!='\0';i++) if(str[i]!=ch)

str[j++]=str[i];
str[j]='\0';} //file4.cpp: #include<stdio.h> void print_string(char str[]) { printf("%s",str);}
70/73

print_string(str);
printf("\n");}

在VC6.0中实现外部函数调用方法
一.由系统自动建立项目工作区(workspace)
(用户只建立项目文件)

1. File->New->Files->C++ Source File, 编辑完后保存文件,如file1.cpp; ? 3.点击菜单栏Project->Add to Project>New ->Files->C++ Source File,在右侧 file中输入file2,可在项目中新生成 file2.cpp;(如果file2.cpp已经存在,选 择Project->Add to Project->File2 -> file2.cpp) ? 4. 依照第3步,可以把file3.cpp,file4.cpp 加入项目中。 71/73
?

二. 用户建立项目工作区和项目文件
1. 建工作区(Workspace) ? 2.建项目文件(Project) ? 3.在项目文件中建新文件或加入现有文 件; ? 4.编译和链接项目文件 ? 5.执行。 ? 详见C程序设计(第四版)学习辅导 P233页。
?

72/73

作业
?

P218 –2 –5 –9 – 13 – 14

73/73


赞助商链接
推荐相关:
网站首页 | 网站地图
All rights reserved Powered by 大学生考试网 9299.net
文档资料库内容来自网络,如有侵犯请联系客服。zhit325@qq.com