第6章-函数和模块设计课件_第1页
第6章-函数和模块设计课件_第2页
第6章-函数和模块设计课件_第3页
第6章-函数和模块设计课件_第4页
第6章-函数和模块设计课件_第5页
已阅读5页,还剩94页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第6章

函数和模块设计

7/27/20231程序设计基础(C语言)wh第6章函数和模块设计

6.1结构化程序设计

6.2函数的定义和调用6.3程序嵌套调用和递归调用

6.4作用域和存储类型

6.5内部函数和外部函数

6.6模块化程序设计

6.7应用举例

7/27/20232程序设计基础(C语言)wh对大千世界的许多描述大都可以在计算机中运用程序设计中的函数问题来解决,C语言程序设计也不例外。一个功能较大的系统,它一定包含有若干个相对独立的子功能,通过子程序模块来描述这些子功能,再通过对这些子程序的组织和调用,来实现整个程序的功能要求。而这些功能比较独立的子程序模块则称之为函数

。本章用于揭开函数的真面目!

7/27/20233程序设计基础(C语言)wh6.1结构化程序设计

<6.1.1结构化程序设计的基本概念结构化程序设计基本思想:将一个大的程序按功能分割成一些子模块,再通过对这些子模块的组织和调用,来实现整个程序的功能要求。7/27/20234程序设计基础(C语言)wh#include"stdio.h"

voidmain(){floata,b,c,v;scanf(”%f,%f,%f”,&a,&b,&c);v=volume(a,b,c);print_message();}

floatvolume(floata,floatb,floatc){floatv;v=a*b*c;return(v);}voidprint_message(){printf(”v=%f”,v);}输出体积组织和调用计算立方体示例:编程序计算一立方体的体积,并在屏幕上输出。7/27/20235程序设计基础(C语言)wh6.1结构化程序设计

6.1.1结构化程序设计的基本概念

结构化程序设计特点:各模块相对独立、功能单一、结构清晰;控制了程序设计的复杂性;提高元件的可靠性缩短开发周期;避免程序开发的重复劳动;易于维护和功能扩充;开发方法: 自上向下,逐步求精

,模块化,限制使用goto语句。

7/27/20236程序设计基础(C语言)wh6.1结构化程序设计

6.1.2结构化程序设计的基本特征

1.

程序的三种基本结构AB顺序结构图条件AB真假选择结构图条件A假真循环结构图7/27/20237程序设计基础(C语言)wh2.C语言是模块化程序设计语言C程序结构ABCDEFGHI7/27/20238程序设计基础(C语言)wh3.程序设计采用自顶向下逐步细化过程

工资计算程序工资计算信息输入工资额计算工资表打印应发部分扣除部分基本工资其他补贴水电、公积金……7/27/20239程序设计基础(C语言)wh6.2函数的定义和调用

函数是C语言程序的一种基本组成部分,

C语言程序的功能是通过函数之间的调用来实现,一个完整的C语言程序可由一个或多个函数组成。

<7/27/202310程序设计基础(C语言)wh示例:编一个程序,计算一立方体的体积,

并在屏幕上输出立方体的体积。#include"stdio.h"

voidmain(){floata,b,c,v;scanf(”%f,%f,%f”,&a,&b,&c);v=volume(a,b,c);print_message();}

floatvolume(floata,floatb,floatc){floatv;v=a*b*c;return(v);}voidprint_message(){printf(”v=%f”,v);}说明:

C是函数式语言,必须有且只

能有一个名为main的主函数,

执行总是从main函数开始,

在main中结束。一个C语言程序可由一个或

多个函数组成。

C语言中函数与函数之间都是互相独立的,不能嵌套定义。除main函数之外,其他函数是通过调用来执行的。自定义函数必须先定义后使用

volume函数中的return(v)

语句是返回语句7/27/202311程序设计基础(C语言)wh6.2函数的定义和调用

6.2.1函数的定义

一般格式函数类型函数名(形参类型说明表){ 说明部分 语句部分}传统格式函数类型函数名(形参表)形参类型说明{ 说明部分 语句部分}现代格式7/27/202312程序设计基础(C语言)wh例有参函数

longfacto(x) intx{longy;for(y=1;x>0;--x)y=y*x;return(y);}传统式例有参函数

longfacto(intx){longy;for(y=1;x>0;--x)y=y*x;return(y);}现代式函数类型函数名(形参类型说明表){ 说明部分 语句部分}现代格式函数返回值类型缺省

int型无返回值

void合法标识符可以为空也可以有多个参数函数体例无参函数

voidprint_message(){printf(”v=%f”,v);}例空函数myfile(){}函数体为空7/27/202313程序设计基础(C语言)wh6.2函数的定义和调用

6.2.2函数的调用

一.函数调用格式及执行过程

调用形式函数名([实参列表]);说明:实参与形参个数相等,类型一致,按顺序一一对应;实参列表求值顺序,因系统而定(TurboC自右向左);实参的量可以是常量、有值的变量或运算表达式.

7/27/202314程序设计基础(C语言)wh#include"stdio.h"

voidmain()

{inti=1,n;

n=f(i,++i);

printf(”\nn=%d\n”,n);}

f(inta,intb)

{intc;if(a>=b)c=1;elsec=0;return(c);}自右向左顺序#include"stdio.h"

voidmain()

{inti=1,n;

n=f(i,++i);

printf(”\nn=%d\n”,n);}

f(inta,intb)

{intc;if(a>=b)c=1;elsec=0;return(c);}自左向右顺序【例6_3】

实参求值顺序举例。

运行结果:n=0

运行结果:n=1

i(1),++i(2)a(1),b(2)c=0;i(2),++i(2)a(2),b(2)c=1;7/27/202315程序设计基础(C语言)wh函数调用语句的执行过程:

①首先计算每个实参表达式的值,并把此值存入所对应的形参单元中,②执行流程转入函数体,执行函数体中的各语句。③函数体执行完之后,return(c)返回到调用该函数的函数中的调用处的下一条语/*计算面积*/

#include"stdio.h"

voidmain()

{intx=5,y=4,s=0;

s=f(x,y);

printf(”\ns=%d\n”,s);}

f(int

a,intb)

{c=a*b;return(c);}x=5y=4a=5b=4c=5*4=20s=20运行结果:s=207/27/202316程序设计基础(C语言)wh二.函数的调用方式

3.以函数调用中的一个实际参数形式调用

例如

①k=hust(hust(m,n),j);

②printf(”%d”,power(a,b));

2.以函数表达式的一个运算对象形式调用

例如

k=hust(m,n)*hust(i,j);

1.以函数调用语句形式调用

例如

hust();

7/27/202317程序设计基础(C语言)wh三.对被调用函数的使用说明

在程序中调用另一个函数时,要满足以下三个条件:

①被调用函数可以是已存在的用户自定义函数或库函数。

#include"stdio.h"

voidmain()

{intx=5,y=4,s=0;

s=f(x,y);

printf(”\ns=%d\n”,s);}

f(inta,intb)

{c=a*b;return(c);}用户自定义函数库函数

②若是库函数,应用#include命令将有关库函数所需的信息包含到本文件中

#include"stdio.h"

voidmain()

{

printf(“********”);}③若是用户自定义的函数,且该函数与调用它的函数(即调用函数)在同一个源 文件中,则在调用函数中应对被调用函数返回值的类型加以说明。

7/27/202318程序设计基础(C语言)wh#include"stdio.h"

voidmain()

{floatvolume(floata,floatb,floatc)

floatx,y,z,v;

scanf(”%f%f%f”,&x,&y,&z);

v=volume(x,y,z);

printf(”v=%f\n”,v);

}

floatvolume(float

a,floatb,float

c)

{floatd;

d=a*b*c;

return(d);

}【例6_4】

求长方形体积的程序。

对自定义函数volume说明

调用自定义函数volume

7/27/202319程序设计基础(C语言)wh6.2函数的定义和调用

6.2.3函数的返回值

返回语句形式return(表达式);说明:系统默认的返回值类型为int型当函数有返回值时,凡是允许表达式出现的地方,都可以调用该函数当函数没有返回值时,函数的返回值类型可以说明为void型(空类型)若无return语句,遇

}

时,自动返回调用函数函数中可有多个return语句或return表达式;或return;功能:利用return语句,将计算结果(或不带结果)返回给调用程序,同时,也使程序的执行流程转到调用语句的下一语句去执行。7/27/202320程序设计基础(C语言)wh

floatcount(int

n)

{inti;floats;if(n<=0);{printf(”The%disinvalid”,n);

return(0);

}else{s=0;for(i=1;i<=n;i++) s+=1/(float)i;

return(s);

}【例6_5】编一函数,求1+1/2+1/3+…+1/n的值。

强制转换成实型

7/27/202321程序设计基础(C语言)wh

voidspc(int

n)

{inti;for(i=0;i<n;i++)

printf(”%c”,’’);

return(0);

}【例6_6】

打印n个空格的函数。

voidspc(int

n)

{inti;for(i=0;i<n;i++)

printf(”%c”,’’);

}返回调用函数

或7/27/202322程序设计基础(C语言)whvoidline(int

n)

line(intn)

{inti;for(i=1;i<=n;i++)

printf(”%c”,’-’);

return;

}调用该函数:

printf(”%d”,line(30));…当无返回值的函数将void省掉时,

函数将返回一个不确定的值。例如:

输出一段虚线的同时,还输出line函数的返回值,它是一个不确定的值。引起编译错误

7/27/202323程序设计基础(C语言)wh

doublepower(float

x,intn)

{inti;doublepw;

pw=l;for(i=1;i<=n;i++)

pw*=x;

returnpw;

}

【例6_7】编一函数,求x的n次方的值,其中n是整数。

x、n

做为函数参数

结果通过return语句返回调用程序

7/27/202324程序设计基础(C语言)wh

to_str(int

n)

{charstr[10];

inti;

if(n<0)

{putchar(’-’);

n=-n;}

i=0;

do{str[i++]=n%10+’0’;

n/=10;

}while(n>0);

while(--i>=0)

putchar(str[i]);}【例6_8】将一个给定的整数转换成相应的字符串后显示出来。

将数值型的数据转换成数值字符的内码

7/27/202325程序设计基础(C语言)wh正确的形参定义

inthust(a,b)

inta,b;

inthust(int

a,intb)或错误的形参定义

inthust(int

a,b)

intb;

inthust(inta,b)或6.2函数的定义和调用

6.2.4函数参数及函数间的数据传递

形式参数:定义函数时函数名后面括号中的变量名。实际参数:调用函数时函数名后面括号中的表达式。例如形参与实参实参的定义

s=hust(x,y);

…7/27/202326程序设计基础(C语言)wh/*计算面积*/

#include"stdio.h"

voidmain()

{intx=5,y=4,s=0;

s=f(x,y);

printf(”\ns=%d\n”,s);}

f(inta,intb)

{c=a*b;return(c);}实参

形参

s=f(x,y);(main函数)(f函数)f(inta,intb){c=a*b;

return(c);}

7/27/202327程序设计基础(C语言)wh6.2函数的定义和调用

6.2.4函数参数及函数间的数据传递

形式参数:定义函数时函数名后面括号中的变量名。实际参数:调用函数时函数名后面括号中的表达式。形参与实参说明:实参可以是常量、已赋值的变量或表达式。实参在次序、类型和个数上应与相应形参表中的形参保持一致。通常,当需要从调用函数中传值(或传地址)到被调用函数中的形参时应设置实参。7/27/202328程序设计基础(C语言)wh6.2函数的定义和调用

6.2.4函数参数及函数间的数据传递

值的传递

:调用函数将实参(常数、变量、数组元素或可计算的表达式)的值传递到被调用函数形参设置的临时变量存储单元中,被调用函数形参值的改变对调用函数的实参没有影响。调用结束后,形参存储单元被释放,实参仍保持原值不变。

传递形参值的两种方法

特点

:形参与实参占用不同的内存单元.单向传递7/27/202329程序设计基础(C语言)wh#include"stdio.h"

voidmain(){inti=25;printf(”Thevalueofiinmain()beforecallingsqr(x)is%d\n”,i);printf(”Callingsqr(x):sqr(%d)=%d\n”,i,sqr(i));

printf(”Thevalueofiinmain()aftercallingsqr(x)is%d\n”,i);}

sqr(intx){x=x*x;return(x);}【例6_9】值的传递程序举例

实参值复制给形参25i:调用前:调用:25x:25i:运行结果:

Thevalueofiinmain()beforecallingsqr(x)is25Callingsqr(x):sqr(25)=625Thevalueofiinmain()aftercallingsqr(x)is25sqr:25i:62525×25x:25i:调用结束:

结论:在值的传递调用中,只是实参的复制值被传递,被调用函数中的操作不会影响实参的值。7/27/202330程序设计基础(C语言)wh6.2函数的定义和调用

6.2.4函数参数及函数间的数据传递

地址的传递

:调用函数将实参(数组名或指针型变量)的地址作为参数传递给形参。若实参是数组名,则调用函数将实参数组的起始地址传递给形参的临时变量单元;若实参是指针变量或地址表达式,则调用函数将实参指针变量所指向单元的地址或实参的地址传递给形参的临时变量存储单元。

传递形参值的两种方法

特点

:形参与实参占用相同的内存单元.双向传递实参和形参必须是地址常量或变量7/27/202331程序设计基础(C语言)whvoidf(intb[]){intmax,max_i,i;max=b[0],max_i=0;for(i=0;i<10;i++)if(max<b[i]){max=b[i];max_i=i;}max=b[0];b[0]=b[max_i];b[max_i]=max;return;}#include"stdio.h"

voidmain()

{voidf(intb[]);inta[10],i;for(i=0;i<10;i++)scanf(”%d”,&a[i]);

f(a);

for(i=0;i<10;i++)printf(”\n%4d”,a[i]);}【例6_11】将数组中的最大元素值与第一个元素值交换

运行结果:

01234567899123456780

调用前0…a9b调用0…a9交换b9…a0返回9…a0

结论:

在地址的传递调用中,数组b与数组a共用同一存储空间。所以被传递的数据在被调用函数中对存储空间的值做出某种变动后,必然会影响到使用该空间的调用函数中变量的值。实参数组的起始地址传递给形参7/27/202332程序设计基础(C语言)wh6.2函数的定义和调用

6.2.4函数参数及函数间的数据传递

一、非数组名作为函数参数

参数传递的两种形式

当非数组名作为函数参数,在函数调用时,C语言编译系统根据形参的类型为每个形参分配存储单元,并将实参的值复制到对应的形参单元之中,形参和实参分别占用不同的存储单元,且形参值的改变不影响与其对应的实参,即按“值的传递”方法操作。

7/27/202333程序设计基础(C语言)wh

f(int

a,int

b){a=a+2;

b=b+4;printf(”a=%d,b=%d\n”,a,b);return(a);}#include"stdio.h"

voidmain()

{intf(int

a,int

b);

intx=1,y=2,z;staticinta[]={0,1,2,3,4};z=f(x,y);printf(”z=%d,x=%d,y=%d\n”,z,x,y);z=f(a[3],a[4]);

printf(”z=%d,a[3]=%d,a[4]=%d\n”,z,a[3],a[4]);

z=f(x,y+1);printf(”z=%d,x=%d,y=%d\n”,z,x,y);}【例6_12】非数组名作为参数的值的传递程序举例

运行结果:

a=3,b=6z=3,x=1,y=2①②③④a=5,b=8z=5,a[3]=3,a[4]=4⑥⑤a=3,b=7

z=3,x=1,y=27/27/202334程序设计基础(C语言)wh6.2函数的定义和调用

6.2.4函数参数及函数间的数据传递

二、数组名作为函数参数

参数传递的两种形式

单个数组元素可以作为函数参数,这同非数组名作为函数参数的情形完全一样,即遵守”值传递”方式。

7/27/202335程序设计基础(C语言)wh1、数组名作为函数参数的表示方法

当数组名作为函数参数时,需要对其类型进行相应的说明

例如

int

test(int

array[10])

... }若数组说明时不指定数组的长度

,可用另一个参数来表示数组的长度

例如

int

test(intarray[],intn

)

... }用形参n来表示array数组的实际长度,更灵活7/27/202336程序设计基础(C语言)whintsolve(inta[],intn){intsum,i;sum=0;for(i=0;i<n;i++)if(a[i]!=0)sum++;return(sum);}【例6_13】编一函数,用来统计一个一维数组中非0元素的个数用形参n来表示a数组的实际长度。7/27/202337程序设计基础(C语言)wh1、数组名作为函数参数的表示方法

当多维数组名作为函数参数时,除第一维可以不指定长度外,其余各维都必须指定长度。

例如

check(floata[][10],float

n)

... }

下面的参数说明都是不正确的:

例如

floata[][];或

floata[10][];

{ { ... ... } }

7/27/202338程序设计基础(C语言)wh说明:

①用数组名作为函数参数时,应该在调用函数和被调用函数中分别定义数组。

②实参数组和形参数组类型应一致,否则出错。

③形参数组的大小应大于等于实参数组的大小,否则得不到实参数组的全部值。

④特别注意的是,数组名作为函数参数时,是将实参数组的首地址传给形参数组,两数组的对应元素占用同一内存单元。传递时按数组在内存中排列的顺序进行。7/27/202339程序设计基础(C语言)wh2、数组名作为函数参数的传递方式

数组名作为函数参数时,不是采用“值传递”方式,而是采用“地址传递”方式。这意味着形参数组中某一元素的改变,将直接影响到与其对应的实参数组中的元素。7/27/202340程序设计基础(C语言)whvoidsort(intarray[10])

{inti,j,k,t;for(i=0;i<9;i++){k=i;for(j=i+1;j<10;j++)if(array[j]<array[k])k=j;t=array[k];array[k]=array[i];array[i]=t;}}#include"stdio.h"

voidmain()

{intx[10],i;voidsort(intarray[10]);for(i=0;i<10;i++)scanf(”%d,”,&x[i]);

sort(x);printf(”Thesortedarray:\n”);for(i=0;i<10;i++)printf(”%d,”,x[i]);printf(”\n”);}【例6_14】将一个10个元素的一维数组用函数调用实现选择排序。

9,8,7,6,5,4,3,2,1,0Thesortedarray:0,1,2,3,4,5,6,7,8,9调用前9…x00…9

调用9…x00…9array

交换0…x90…9array

返回0…x90…9scanf(”%d,”,&x[i]);寻找排序7/27/202341程序设计基础(C语言)wh6.3嵌套调用和递归调用

C语言中的函数定义是互相独立的,函数和函数之间没有从属关系,即一个函数内不允许包含另一个函数的定义。一个函数既可以被其他函数调用,同时,它也可以调用别的函数,这就是函数的嵌套调用。函数的嵌套调用为自顶向下、逐步求精及模块化的结构化程序设计技术提供了最基本的支持。<7/27/202342程序设计基础(C语言)wh6.3嵌套调用和递归调用

6.3.1函数的嵌套调用

嵌套调用一个函数既可以被其他函数调用,同时,它也可以调用别的函数,这就是函数的嵌套调用。嵌套调用执行过程main()调用函数a结束a函数b函数调用函数bmain()调用函数aa函数调用函数bb函数结束7/27/202343程序设计基础(C语言)wh6.3嵌套调用和递归调用

6.3.2函数的递归调用

递归调用在调用一个函数过程中又出现直接或间接地调用该函数本身,前者称之为直接递归调用,后者称之为间接递归调用。

7/27/202344程序设计基础(C语言)whfunc()调func调func2调func1func1()func2()floatfunc(intn)

{intm;floatf;……f=func(m);…….}

funcl(intn)

{intm;……

func2(m);

…….}func2(intx)

{inty;……

funcl(y);…….}直接递归调用

间接递归调用

7/27/202345程序设计基础(C语言)whlongintfact(int

n)

{longintf;if(n==0)f=1;else

f=n*fact(n-1);

return(f);}#include"stdio.h"

voidmain()

{intn;longintresult;longintfact(intn);while(1){printf(”Inputanumber:”);

scanf(”%d”,&n);if(n>=0)break;}

result=fact(n);

printf(”Result=%ld”,result);}【例6_16】

从键盘输入一非负整数n,并求出n!的值。n!=n*(n-1)!结果分析:n=4 f(4)=4*fac(4-1)=3 f(3)=3*fac(3-1)=2f(2)=2*fac(2-1)=1f(1)=1*fact(1-1)=0f(0)=1回推递推运行情况:Inputanumber:4Result

= 24递归调用嵌套调用if(n==0)/*递归终止条件*/f=1;递归过程的两个阶段:⑴fact(4)是主函数调用的。在一次调用fact函数时并不是立即得到fact(4)的值,而是一次又一次地进行递归调用(回推),直到fact(1)时才有确定的值。⑵之后,再递推出fact(2)、fact(3)、fact(4)的值。7/27/202346程序设计基础(C语言)whdoublexpower(floatx,intn)

{if(n<=0)return(1);else

return(x*xpower(x,n-1));}#include"stdio.h"

voidmain(){doublexpower(floatx,intn);floatx;intn;doubler

scanf(”%f%d”,&x,&n);r=xpower(x,n);printf(”Result=%f”,r);}【例6_17】编一程序,利用函数的递归调用求x的n次方的值,

其中n为正整数。

运行情况:2,3Result

= 8

小结:任何有意义的递归调用总是由两部分组成: 即递归方式与递归终止条件。

if(n<=0)

/*递归终止条件*/

return(1);7/27/202347程序设计基础(C语言)wh6.4作用域和存储类型

变量是对程序中数据的存储空间的抽象变量的属性数据类型:变量所持有的数据的性质(操作属性)存储属性存储器类型:寄存器、静态存储区、动态存储区生存期:变量在某一时刻存在——静态变量与动态变量作用域:变量在某区域内有效

——局部变量与全局变量变量的存储类型

auto———自动型

register

———寄存器型

static

———静态型

extern

———外部型变量定义格式:[存储类型定义符]数据类型变量名表;如:intsub;

auto

intx,y,z;

registerintn;

static

floata,b;<7/27/202348程序设计基础(C语言)wh6.4作用域和存储类型

6.4.1局部变量及其存储类型

定义在函数或复合语句内部定义的变量称为局部变量。

说明主函数main中定义的变量也只在主函数中有效,其它函数不能引用;不同函数中可以使用相同名字的变量,它们代表不同的对象,占用不同的内存单元,互相独立;形式参数也是局部变量;可以在复合语句中定义变量,其作用域只是本复合语句。7/27/202349程序设计基础(C语言)wh

floathust1(int

a)

{intx,y;……}举例局部变量a、x、y的作用范围floathust2(intb,intc){chars;

……}局部变量b、c、s的作用范围void

main(){intm,n;……}局部变量m、n的作用范围7/27/202350程序设计基础(C语言)wh举例#include”stdio.h”

voidmain(){intp,q;……

{intx;x=p+q;……}

……}x的有效范围p、q的有效范围7/27/202351程序设计基础(C语言)wh6.4作用域和存储类型

6.4.1局部变量及其存储类型

1.自动存储变量auto自动存储变量在函数或复合语句中定义和说明的变量,通常称为自动变量。自动变量前可以冠以“auto”,若变量前不加任何存储类别说明,则按缺省规则都为自动存储类别的变量。作用域:

自动变量通常是局部变量,它的作用域仅限于定义它的那个函数或复合语句。它的可见性与生存期和作用域相同。

autofloata;

floata;或7/27/202352程序设计基础(C语言)wh【例6_18】

不同函数中的同名变量#include"stdio.h"voidmain(){inta;a=0;

data(

);a=a+100;printf(”main:a=%d\n”,a);}data(){inta;a=-199;

printf(”data:a=%d\n”,a);}运行结果:data:a=-199main:a=100不指定为auto型不指定为auto型#include"stdio.h"voidmain(){inta;

a=1;

data(

);

a=a+100;printf(”main:a=%d\n”,a);}data(){inta;printf(“da=%d\n",a);

a=-199;

printf(”data:a=%d\n”,a);}运行结果:da=1

data:a=-199

main:a=1017/27/202353程序设计基础(C语言)wh【例6_18】

不同函数中的同名变量#include"stdio.h"voidmain(){inta;

a=10;

printf(“ma=%d,%x\n",a,&a);

data(

);

a=a+100;

printf(”main:a=%d\n”,a

,&a);}data(){inta;

printf(“da=%d\n",a

,&a);

a+=1;

printf(“daa=%d,%x\n",a,&a);

a=-199;

printf(”data:a=%d\n”,a

,&a);}运行结果:ma=10,ffdcda=404,ffd6daa=405,ffd6data:a

=-199,ffd6main:a=110,ffdc7/27/202354程序设计基础(C语言)wh6.4作用域和存储类型

6.4.1局部变量及其存储类型

2.静态局部变量

static如果希望在函数调用结束后仍然保留函数中定义的局部变量的值,则可以将该局部变量定义为静态局部变量。静态局部变量前可以冠以“static”

例如static

intt,s;

说明:①静态局部变量的作用域在定义它的函数内部,它的值在函数调用结束后并不消失,但其他函数仍然不能访问它。②静态局部变量赋初值是在编译过程中进行的,且只赋一次初值。而且连续保留上一次函数调用时的结果。③静态局部变量的默认初值数值型为0,字符型为Null7/27/202355程序设计基础(C语言)wh【例6_19】编一程序,观察静态局部变量在调用过程中的情况。

#include"stdio.h"

voidtest()

{staticinta=0;printf(”a=%d\n”,a);++a;}

voidmain()

{inti;for(i=0;i<4;i++)

test();}运行结果:

a=0

a=1a=2a=37/27/202356程序设计基础(C语言)wh#include<stdio.h>

intfunc(inta,int

b){staticintm=0,i=0;i+=m+1;m=i+a+b;return(m);}

main(){intk=3,m=2,p;p=func(k,m);

printf(“p1=%d\n”,p);p=func(k,m);

printf(“p2=%d\n”,p);}运行结果:p1=

课堂练习:看程序写结果\*i=i+(m+1)=0+(0+1)=1*\\*m=1+3+2=6*\\*i=i+(m+1)=1+(6+1)=8*\\*m=8+3+2=13*\6p2=137/27/202357程序设计基础(C语言)wh6.4作用域和存储类型

6.4.1局部变量及其存储类型

3.寄存器变量

register为提高程序的运行速度,可将使用十分频繁的局部变量说明为寄存器变量,即在局部变量前冠以register,告知编译系统将其存储在CPU的寄存器中

voidtest_r(register

intn){registercharc;...}说明:①变量的存储类型为寄存器变量时,auto说明符可省,冠以register说明符即可②寄存器变量的使用与机器的硬件特性有关,有一些限制:如寄存器变量的个数;它只适用于自动变量和函数的形参;它的类型只能是char、shortint、unsignedint、int和指针型;不允许对寄存器变量取地址等。

③TurboC中寄存器变量只能用于整型和字符型,且限制最多只允许定义两个

寄存器变量。一旦超过,系统就自动地将其余的作为非寄存器变量来处理。

7/27/202358程序设计基础(C语言)whi的作用范围【例6_20】

输出1到5的阶乘的值。

#include"stdio.h"

voidmain()

{intfac(intn);inti;for(i=1;i<=5;i++)printf(”%d!=%d\n”,i,fac(i));

}

intfac(int

n)

{

register

inti,f=1;

for(i=1;i<=n;i++)f=f*i;return(f);}运行结果:

1!=1

2!=23!=64!=24i、f的作用范围5!=1207/27/202359程序设计基础(C语言)wh【例6_21】编一程序,输入10名学生的成绩,并求出平均成绩

#include"stdio.h"

floatascore(float

a[],int

n)

{register

inti;floatsum;sum=0;for(i=0;i<n;i++)

sum+=a[i];return(sum/n);}

voidmain(){floatarray[10];

register

inti;for(i=0;i<10;i++)scanf(”%f”,&array[i]);printf(”Averagescore=%f”,;

ascore(array,10));}i的作用范围i的作用范围7/27/202360程序设计基础(C语言)wh6.4作用域和存储类型

6.4.2全局变量及其存储类型

定义一个源程序文件可以包含一个或若干个函数。在函数之外定义的变量称为全局变量或全程变量(又称外部变量)。

全局变量与局部变量的区别:全局变量在函数之外定义,局部变量在函数之内定义;局部变量在本函数之内有效,全局变量从定义变量的位置开始到本源文件结束均有效。编译时全局变量分配在静态存储区,而局部变量则不一定。7/27/202361程序设计基础(C语言)wh【例6_22】编一程序,打印九九表

#include"stdio.h"

voidrow();

inta=1;

/*外部变量*/

voidmain()

{intk;for(k=1;k<=9;++k,++a)

row();

}

voidrow()

{intb;for(b=1;b<=a;++b)

printf(”%4d”,a*b);printf(”\n”);}k的有效范围b的有效范围作用域a7/27/202362程序设计基础(C语言)wh6.4作用域和存储类型

6.4.2全局变量及其存储类型

1.外部变量

extern

外部变量没有说明为static的全局变量,其存储类型都是外部的,统称为外部变量。外部变量说明

extern

数据类型变量表;注意:⑴凡在函数外定义的全局变量,按缺省规则可以不写说明extern,但在函数体内说明其后所定义的全局变量时,要冠以extern。⑵若一个文件要引用另一个文件中的全局变量,应该在需要引用该变量的文件中,用

extern说明该变量为外部的全局变量。7/27/202363程序设计基础(C语言)wh【例6_23】编一程序,打印九九表

#include"stdio.h"voidrow();voidmain()

{intk;

for(k=1;k<=9;++k,++a)

row();}inta=1;

/*定义外部变量*/voidrow

()

{intb;for(b=1;b<=a;++b)

printf(”%4d”,a*b);printf(”\n”);}作用域a作用域a扩展externinta;/*说明外部变量*/extern只能用来说明变量,而不能用来定义变量。

7/27/202364程序设计基础(C语言)wh例如 在不同的文件中引用外部变量

文件f1.c的内容:#include“f2.c”intx;/*外部变量定义*/main()

{intsum,y;scanf(“%d”,&y);store();sum=x+y;printf(“sum=%d”,sum);}文件f2.c的内容:externintx;/*外部变量引用说明*/voidstore()

{x=10;}7/27/202365程序设计基础(C语言)wh6.4作用域和存储类型

6.4.2全局变量及其存储类型

2.静态外部变量

static

静态全局变量一定是在本文件中定义的全局变量,其存储类型说明符是static。

静态全局变量的作用域是其定义点开始到该文件的结束,在本文件外不能访问。这种全局变量起到一个屏蔽作用。也可以对函数定义成静态的,来限制函数的作用域。

静态外部变量与外部变量的相同与区别:两者都是在静态存储区中分配单元;外部变量不仅在本函数之内使用,还可以用于其他函数,但静态外部变量则不能用于其他函数;7/27/202366程序设计基础(C语言)wh例如 下面对静态全局变量的引用是错误的:

file1.cstaticint

a;

/*静态外部变量定义*/main(){

a=1;

printf(”%d\n”,f(a));}file2.c

externinta;/*静态外部变量引用说明*/intf(int

x)

{x=a+x;

printf(”%d\n”,x);return(x);}即使使用了extern说明,也无法使用该变量。

7/27/202367程序设计基础(C语言)wh6.5内部函数和外部函数

C语言程序系统由若干个函数组成,这些函数既可在同一文件中,也可分散在多个不同的文件中,根据函数能否被其它源文件调用,可将它们分为内部函数和外部函数。<7/27/202368程序设计基础(C语言)wh6.5内部函数和外部函数

6.5.1内部函数(静态函数

)

如果一个函数只能被本文件中其它函数所调用,称为内部函数(或静态函数)。定义时在函数类型前加static:static类型标识符函数名<形参表>

staticfloathust(int

a,intb)

{……}函数hust的作用范围仅局限于定义本文件,而在其它文件中不能调用此函数。

7/27/202369程序设计基础(C语言)wh6.5内部函数和外部函数

6.5.2外部函数外部函数在函数定义的前面冠以extern说明符的函数,称为外部函数。定义外部函数

extern类型标识符函数名<形参表>说明:

①在定义函数时省去了extern说明符时,则隐含为外部函数。②在需要调用外部函数的文件中,应该用extern说明所用的函数是外部函数。7/27/202370程序设计基础(C语言)wh【例6_24】输入一个字符,将已知字符串中的该字符删除,

要求用外部函数实现。

/*file1.c*/#include"stdio.h“voidmain(){externenter_string(charstr[80]);externdelete_string(charstr[],charch);externprint_string(charstr[]);charc;

staticcharstr[80];

enter_string(str);scanf(”%c”,&c);

delete_string(str,c);

print_string(str);}/*file2.c*/#include“stdio.h“/*输入字符串*/

extern

enter_string(char

str[80]){gets(str);}/*file3.c*/#include"stdio.h“/*删除给定的字符

*/extern

delete_string(char

str[],char

ch){inti,j;for(i=j=0;str[i]!=’\0’;i++)if(str[i]!=ch)str[j++]=str[i];str[j]=’\0’;}/*file4.c*//*打印操作结果

*/extern

print_string(char

str[

]){printf(”%s”,str);}运行结果:abcdefgc

cabcdefg7/27/202371程序设计基础(C语言)wh上机操作过程:方法一:(1)在file1.c文件开头加入如下内容 #include”file2.c” #include”file3.c” #include”file4.c”(2)对file1.c文件进行编译、连接、运行。方法二:

分别对4个文件进行编译得到四个目标文件(.obj文件)。用link功能将四个目标文件连接起来:在MSC系统上用命令: linkfile1+file2+file3+file4执行结果生成一个可执行文件(.exe文件)7/27/202372程序设计基础(C语言)wh6.6模块化程序设计

在程序设计时,如果待解决的问题比较简单,所编制的程序又不大,可将整个程序放在一个模块中。但对大而复杂的设计任务,不可能由1个人用1个程序来实现。<7/27/202373程序设计基础(C语言)wh6.6模块化程序设计

6.6.1模块化程序设计方法的指导思想基本思想:将一个大的程序按功能分割成一些小模块。开发方法:自顶向下,逐步求精。特点:各模块相对独立、功能单一、结构清晰、接口简单。控制了程序设计的复杂性。提高元件的可靠性。缩短开发周期。避免程序开发的重复劳动。易于维护和功能扩充。7/27/202374程序设计基础(C语言)whC语言是模块化程序设计语言C程序结构ABCDEFGHIC是函数式语言必须有且只能有一个名为main的主函数C程序的执行总是从main函数开始,在main中结束函数不能嵌套定义,可以嵌套调用7/27/202375程序设计基础(C语言)wh程序设计采用自顶向下逐步细化过程

工资计算程序工资计算信息输入工资额计算工资表打印应发部分扣除部分基本工资其他补贴水电、公积金……7/27/202376程序设计基础(C语言)wh6.6模块化程序设计

6.6.2模块分解的原则

模块分解用“自顶向下”的方法进行系统设计,即先整体后局部。复杂系统化大为小,化繁为简。按功能划分法把模块组成树状结构,层次清楚,提高系统设计效率(多人并行开发),便于维护。模块的大小要适中,语句行数不大于100行。各模块间的接口要简单。尽可能使每个模块只有一个入口,一个出口。7/27/202377程序设计基础(C语言)wh模块的划分和设计可参考如下规则:

(1)如果一个程序段被很多模块所共用,则它应是一个独立的模块。(2)如果若干个程序段处理的数据是共用的,则这些程序段应放在一个模块中。

(3)若两个程序段的利用率差别很大,则应分属于两个模块。(4)一个模块既不能过大,也不能过小。过大则模块的通用性较差,过小则会造成时间和空间上的浪费。

(5)力求使模块具有通用性,通用性越强的模块利用性越高。

(6)各模块间应在功能上,逻辑上相互独立,尽量截然分开,特别应避免用转移语句的模块间转来转去。

(7)各模块间的接口应该简单,要尽量减少公共符号的个数,尽量不用共用数据存储单元,在结构或编排上有联系的数据应放在一个模块中,以免相互影响,造成查错困难。(8)每个模块的结构应尽量设计成单入口,单出口的形式。这样的程序便于调试,阅读和理解且可靠性高。7/27/202378程序设计基础(C语言)wh6.7应用举例

<7/27/202379程序设计基础(C语言)wh【例6_25】编一程序,从键盘为一个10×10维整型数组输入数据,并对该数组进行转置操作,即行、列互换。

#include"stdio.h"voidrotate(inta[10][10]){inti,j,temp;

for(i=0;i<10;i++)for(j=i+1;j<10;j++){temp=a[i][j];a[i][j]=a[j][i];a[j][i]=temp;}}voidmain(){inta[10][10],i,j;for(i=0;i<10;i++)for(j=0;j<10;j++)scanf(”%d”,&a[i][j]);putchar(’\n’);

rotate(a);

for(i=0;i<10;i++)for(j=0;j<10;j++)printf(”%d”,a[i][j]);}说明:由于rotate函数的参数a是数组,因此,它采用的是“地址传递”方式,即rotate函数中形参a数组的改变,直接影响到在main函数中调用rotate函数时的实参数组a。7/27/202380程序设计基础(C语言)wh分析:题意要求计算字符串长度。可以用字符数组来存储字符串。主函数main用来输入字符串和输出字符串长度值,函数strlen()用来计算字符串长度。其递归结束条件是元素值为’\0’,此时,应返回字符串长度,否则应判断下一个字符。【例6_26】编写一个计算字符串长度的递归函数。

#include"stdio.h"inti=0;voidmain(){intstr_len(chars[]);charstr[100];printf(”Inputstring:\n”);gets(str);printf(”Outputstring:\n”);puts(str);i=str_len(str);printf(”Thestringlength=%d\n”,i);}intstr_len(char

s[])

{if(s[i]==’\0’)return(i);else{i++;

str_len(s);

}}说明:程序的递归函数中,若不满足条件(s[i]==’\0’)时,一方面长度I要加1,另一方面将数组中下一个元素的地址作为实参进行递归调用。这是因为s是数组的第一个元素的地址,则s+1是第二个元素的地址,……s+I是第i+1个元素的地址。7/27/202381程序设计基础(C语言)wh【例6_27】变量存储类型及作用域应用举例

/*文件file1.c内容*/

#include"stdio.h“inti=1;next(){return(i++);}voidmain(){inti,j;i=reset();for(j=1;j<=3;j++){printf(”i=%d\tj=%d\t”,i,j);printf(”next()=%d\t”,next(

));printf(”last()=%d\t”,last(

));printf(”new(i+j)=%d\t”,new(i+j));printf(”\n”);}}/*文件file2.c*/staticinti=10;

last(){return(i-=1);}new(int

i){staticintj=5;return(i=j+=++i);}/*文件file3.c*/externinti;reset(){return(i);}运行结果:i=1j=1next()=1last()=9new(i+j)=8i=1j=2next()=2last()=8new(i+j)=12i=1j=3next()=3last()=7new(i+j)=17

7/27/202382程序设计基础(C语言)wh

这是一个由三个文件组成的程序,分别是file1.c、file2.c、file3.c。在file1.c的头部对i变量进行了外部说明,照例它是全局变量,其作用域是整个文件。然而,主函数main()内又对i变量重新作了说明,这个i是自动变量,它与外部那个全局的i无关。在函数next()中,i在使用前已经作了外部说明,所以可直接引用,不需用extern作外部说明。在文件file2.c中,把i说明成外部静态变量,照例它的作用域是文件file2.c内。但是在new()函数中,i为形参,和自动变量一样,它与外部静态变量i无关,而且它也与文件file1.c中的外部变量i无关。在文件file3.c中,开头就对i变量作了外部说明,因此,它与file1.c中的外部变量i是同一个变量。在不同的系统中,将多个源文件合成为一个程序的方法是不同的。TurboC中,是通过用户定义的project文件将多个源文件合并成一个程序的。

7/27/202383程序设计基础(C语言)wh

就本例而言,可以建立project文件file.prj。先在编辑器中编辑file.prj文件,文件内容为:file1.cfile2.c

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论