1980在线娱乐登陆:《c语言程序设计》第五章函数

概述在第一章中已经先容过,C源法度榜样是由函数组成的。虽然在前面各章的法度榜样中都只有一个主函数main(),但实用法度榜样每每由多个函数组成。函数是C源法度榜样的基础模块,经由过程对函数模块的调用实现特定的功能。C说话中的函数相称于其它高档说话的




概述

在第一章中已经先容过,C源法度榜样是由函数组成的。 虽然在前面各章的法度榜样中都只有一个主函数main(), 但实用法度榜样每每由多个函数组成。函数是C源法度榜样的基础模块, 经由过程对函数模块的调用实现特定的功能。C说话中的函数相称于其它高档说话的子法度榜样。 C说话不仅供给了极为富厚的库函数(如Turbo C,MS C 都供给了三百多个库函数),还准许用户建立自己定义的函数。用户可把自己的算法编成一个个相对自力的函数模块,然后用调用的措施来应用函数。

可以说C法度榜样的整个事情都是由种种1980在线娱乐登陆各样的函数完成的, 以是也把C说话称为函数式说话。 因为采纳了函数模块式的布局, C说话易于实现布局化法度榜样设计。使法度榜样的层次布局清楚,便于法度榜样的编写、涉猎、调试。

在C说话中可从不合的角度对函数分类。

1. 从函数定义的角度看,函数可分为库函数和用户定义函数两种。

(1)库函数

由C系统供给,用户无须定义, 也不必在法度榜样中作类型阐明,只需在法度榜样前包孕有该函数原型的头文件即可在法度榜样中直接调用。在前面各章的例题中反复用到intf 、 scanf 、 getchar 、putchar、gets、puts、strcat等函数均属此类。

(2)用户定义函数

由用户按必要写的函数。对付用户自定义函数, 不仅要在法度榜样中定义函数本身, 而且在主调函数模块中还必须对该被调函数进行类型阐明,然后才能应用。

2. C说话的函数兼有其它说话中的函数和历程两种功能,从这个角度看,又可把函数分为有返回值函数和无返回值函数两种。

(1)有返回值函数

此类函数被调用履行完后将向调用者返回一个履行结果, 称为函数返回值。如数学函数即属于此类函数。 由用户定义的这种要返回函数值的函数,必须在函数定义和函数阐明中明确返回值的类型。

(2)无返回值函数

此类函数用于完成某项特定的处置惩罚义务, 履行完成后不向调用者返回函数值。这类函数类似于其它说话的历程。 因为函数无须返回值,用户在定义此类函数时可指定它的返回为“空类型”, 空类型的阐明符为“void”。

3. 从主调函数和被调函数之间数据传送的角度看又可分为无参函数和有参函数两种。

(1)无参函数

函数定义、函数阐明及函数调用中均不带参数。 主调函数和被调函数之间不进行参数传送。 此类函数平日用来完成一组指定的功能,可以返回或不返回函数值。

(2)有参函数

也称为带参函数。在函数定义及函数阐明时都有参数, 称为形式参数(简称为形参)。在函数调用时也必须给出参数, 称为实际参数(简称为实参)。 进行函数调用时,主调函数将把实参的值传送给形参,供被调函数应用。

4. C说话供给了极为富厚的库函数, 这些库函数又可从功能角度作以下分类。

(1)字符类型分类函数

用于对字符按ASCII码分类:字母,数字,节制字符,分隔符,大年夜小写字母等。

(2)转换函数

用于字符或字符串的转换;在字符量和种种数字量 (整型, 实型等)之间进行转换;在大年夜、小写之间进行转换。

(3)目录路径函数

用于文件目录和路径操作。

(4)诊断函数

用于内部差错检测。

(5)图形函数

用于屏幕管理和各类图形功能。

(6)输入输出函数

用于完成输入输出功能。

(7)接口函数

用于与DOS,BIOS和硬件的接口。

(8)字符串函数

用于字符串操作和处置惩罚。

(9)内存管理函数

用于内存管理。

(10)数学函数

用于数学函数谋略。

(11)日期和光阴函数

用于日期,光阴转换操作。

(12)进程节制函数

用于进程管理和节制。

(13)其它函数

用于其它各类功能。

以上种种函数不仅数量多,而且有的还必要硬件常识才会应用,是以要想整个把握则必要一个较长的进修历程。 应首先把握一些最基础、 最常用的函数,再慢慢深入。因为篇幅关系,本书只先容了很少一部分库函数, 另外部分读者可根据必要查阅有关手册。

还应该指出的是,在C说话中,所有的函数定义,包括主函数main在内,都是平行的。也便是说,在一个函数的函数体内, 不能再定义另一个函数, 即不能嵌套定义。然则函数之间准许互相调用,也准许嵌套调用。习气上把调用者称为主调函数。 函数还可以自己调用自己,称为递归调用。main 函数是主函数,它可以调用其它函数,而禁绝许被其它函数调用。 是以,C法度榜样的履行老是从main函数开始, 完成对其它函数的调用后再返回到main函数,着末由main函数停止全部法度榜样。一个C源法度榜样必须有,也只能有一个主函数main。

函数定义的一样平常形式

1.无参函数的一样平常形式

类型阐明符 函数名()

{

类型阐明

语句

}

此中类型阐明符和函数名称为函数头。 类型阐明符指清楚明了本函数的类型,函数的类型实际上是函数返回值的类型。 该1980在线娱乐登陆类型阐明符与第二章先容的各类阐明符相同。 函数名是由用户定义的标识符,函数名后有一个空括号,此中无参数,但括号弗成少。{} 中的内容称为函数体。在函数体中也有类型阐明, 这是对函数体内部所用到的变量的类型阐明。在很多环境下都不要求无参函数有返回值, 此时函数类型符可以写为void。

我们可以改为一个函数定义:

void Hello()

{

printf ("Hello,world

");

}

这里,只把main改为Hello作为函数名,另外不变。Hello 函数是一个无参函数,当被其它函数调用时,输出Hello world字符串。

2.有参函数的一样平常形式

类型阐明符 函数名(形式参数表)

型式参数类型阐明

{

类型阐明

语句

}

有参函数比无参函数多了两个内容,其一是形式参数表, 其二是形式参数类型阐明。在形参表中给出的参数称为形式参数, 它们可所以各类类型的变量, 各参数之间用逗号距离。在进行函数调用时,主调函数将付与这些形式参数实际的值。 形参既然是变量,当然必须给以类型阐明。例如,定义一个函数, 用于求两个数中的大年夜数,可写为:

int max(a,b)

int a,b;

{

if (a>b) return a;

else return b;

}

第一行阐明max函数是一个整型函数,其返回的函数值是一个整数。形参为a,b。第二行阐明a,b均为整型量。 a,b 的详细值是由主调函数在调用时传送过来的。在{}中的函数体内, 除形参外没有应用其它变量,是以只有语句而没有变量类型阐明。 上边这种定义措施称为“传统款式”。 这种款式不易于编译系统反省,从而会引起一些异常细微而且难于跟踪的差错。ANSI C 的新标准中把对形参的类型阐明合并到形参表中,称为“今世款式”。

例如max函数用今世款式可定义为:

int max(int a,int b)

{

if(a>b) return a;

else return b;

}

今世款式在函数定义和函数阐明(后面将要先容)时, 给出了形式参数及其类型,在编译时易于对它们进行查错, 从而包管了函数阐明和定义的同等性。例1.3即采纳了这种今世款式。 在max函数体中的return语句是把a(或b)的值作为函数的值返回给主调函数。有返回值函数中至少应有一个return语句。 在C法度榜样中,一个函数的定义可以放在随意率性位置, 既可放在主函数main之前,也可放在main之后。例如例1.3中定义了一个max 函数,其位置在main之后, 也可以把它放在main之前。

改动后的法度榜样如下所示。

int max(int a,int b)

{

if(a>b)return a;

else return b;

}

void main()

{

int max(int a,int b);

int x,y,z;

printf("input two numbers:

");

scanf("%d%d",&x,&y);

z=max(x,y);

printf("maxmum=%d",z);

}

现在我们可以从函数定义、 函数阐明及函数调用的角度来阐发全部法度榜样,从中进一步懂得函数的各类特征。法度榜样的第1行至第5行径max函数定义。进入主函数后,由于预备调用max函数,故先对max函数进行阐明(法度榜样第8行)。函数定义和函数阐明并不是一回事,在后面还要专门评论争论。 可以看出函数阐明与函数定义中的函数头部分相同,然则末端要加分号。法度榜样第12 行径调用max函数,并把x,y中的值传送给max的形参a,b。max函数履行的

结果 (a或b)将返回给变量z。着末由主函数输出z的值。

函数调用的一样平常形式前面已经说过,在法度榜样中是经由过程对函数的调用来履行函数体的,其历程与其它说话的子法度榜样调用相似。C说话中, 函数调用的一样平常形式为:

函数名(实际参数表) 对无参函数调用时则无实际参数表。 实际参数表中的参数可所以常数,变量或其它构造类型数据及表达式。 各实参之间用逗号分隔。'Next of Page在C说话中,可以用以下几种要领调用函数:

1.函数表达式

函数作表达式中的一项呈现在表达式中,以函数返回值介入表达式的运算。这种要领要求函数是有返回值的。例如: z=max(x,y)是一个赋值表达式,把max的返回值付与变量z。'Next of Page

2.函数语句

函数调用的一样平常形式加上分号即构成函数语句。例如: printf ("%D",a);scanf ("%d",&b);都因此函数语句的要领调用函数。

3.函数实参

函数作为另一个函数调用的实际参数呈现。 这种环境是把该函数的返回值作为实参进行传送,是以要求该函数必须是有返回值的。例如: printf("%d",max(x,y)); 等于把max调用的返回值又作为printf函数的实参来应用的。在函数调用中还应该重视的一个问题是求值顺序的问题。 所谓求值顺序是指对实参表中各量是自左至右应用呢,照样自右至左应用。 对此, 各系统的规定不必然相同。在3.1.3节先容printf 函数时已提

到过,这里从函数调用的角度再强调一下。 看例5.2法度榜样。

void main()

{

int i=8;

printf("%d

%d

%d

%d

",++i,--i,i++,i--);

}

如按照从右至左的顺序求值。例5.2的运行结果应为:

8

7

7

8

如对printf语句中的++i,--i,i++,i--从左至右求值,结果应为:

9

8

8

9

应不凡重视的是,无论是从左至右求值, 照样自右至左求值,其输出顺序都是不变的, 即输出顺序老是和实参表中实参的顺序相同。因为Turbo C现定是自右至左求值,以是结果为8,7,7,8。上述问题如还不理解,上机一试就明白了。函数的参数和函数的值

一、函数的参数

前面已经先容过,函数的参数分为形参和实参两种。 在本小节中,进一步先容形参、实参的特征和两者的关系。 形参呈现在函数定义中,在全部函数体内都可以应用, 脱离该函数则不能应用。实参呈现在主调函数中,进入被调函数后,实参变量也不能应用。 形参和实参的功能是作数据传送。发生函数调用时, 主调函数把实参的值传送给被调函数的形参从而实现主调函数向被调函数1980在线娱乐登陆的数据传送。

函数的形参和实参具有以下特征:

1.形参变量只有在被调用时才分配内存单元,在调用停止时, 即刻开释所分配的内存单元。是以,形参只有在函数内部有效。 函数调用停止返回主调函数后则不能再应用该形参变量。

2.实参可所以常量、变量、表达式、函数等, 无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值, 以便把这些值传送给形参。 是以应预先用赋值,输入等法子使实参得到确定值。

3.实参和形参在数量上,类型上,顺序上应严格同等, 否则会发生“类型不匹配”的差错。

4.函数调用中发生的数据传送是单向的。 即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。 是以在函数调用历程中,形参的值发生改变,而实参中的值不会变更。例5.3可以阐明这个问题。

void main()

{

int n;

printf("input number

");

scanf("%d",&n);

s(n);

printf("n=%d

",n);

}

int s(int n)

{

int i;

for(i=n-1;i>=1;i--)

n=n+i;

printf("n=%d

",n);

}

本法度榜样中定义了一个函数s,该函数的功能是求∑ni=1i 的值。在主函数中输入n值,并作为实参,在调用时传送给s 函数的形参量n( 重视,本例的形参变量和实参变量的标识符都为n, 但这是两个不合的量,各自的感化域不合)。 在主函数顶用printf 语句输出一次n值,这个n值是实参n的值。在函数s中也用printf 语句输出了一次n值,这个n值是形参着末取得的n值0。从运行环境看,输入n值为100。即实参n的值为100。把此值传给函数s时,形参 n 的初值也为100,在履行函数历程中,形参n的值变为5050。 返回主函数之后,输出实参n的值仍为100。可见实参的值不随形参的变更而变更。

二、函数的值

函数的值是指函数被调用之后, 履行函数体中的法度榜样段所取得的并返回给主调函数的值。如调用正弦函数取得正弦值,调用例5.1的max函数取得的最大年夜数等。对函数的值(或称函数返回值)有以下一些阐明:

1. 函数的值只能经由过程return语句返回主调函数。return 语句的一样平常形式为:

return 表达式;

或者为:

return (表达式);

该语句的功能是谋略表达式的值,并返回给主调函数。 在函数中准许有多个return语句,但每次调用只能有一个return 语句被履行, 是以只能返回一个函数值。

2. 函数值的类型和函数定义中函数的类型应维持同等。 要是两者不同等,则以函数类型为准,自动进行类型转换。

3. 如函数值为整型,在函数定义时可以省去类型阐明。

4. 不返回函数值的函数,可以明确定义为“空类型”, 类型阐明符为“void”。如例5.3中函数s并不向主函数返函数值,是以可定义为:

void s(int n)

{ ……

}

一旦函数被定义为空类型后, 1980在线娱乐登陆就不能在主调函数中应用被调函数的函数值了。例如,在定义s为空类型后,在主函数中写下述语句 sum=s(n); 便是差错的。为了使法度榜样有优越的可读性并削减掉足, 凡不要求返回值的函数都应定义为空类型。函数阐明在主调函数中调用某函数之前应对该被调函数进行阐明, 这与应用变量之前要先辈行变量阐明是一样的。 在主调函数中对被调函数作阐明的目的是使编译系统知道被调函数返回值的类型, 以便在主调函数中按此种类型对返回值作响应的处置惩罚。 对被调函数的阐明也有两种款式,一种为传统款式,其一样平常款式为: 类型阐明符 被调函数名(); 这种款式只给出函数返回值的类型,被调函数名及一个空括号。

这种款式因为在括号中没有任何参数信息, 是以不便于编译系统进行差错反省,易于发生差错。另一种为今世款式,其一样平常形式为:

类型阐明符 被调函数名(类型 形参,类型 形参…);

或为:

类型阐明符 被调函数名(类型,类型…);

今世款式的括号内给出了形参的类型和形参名, 或只给出形参类型。这便于编译系统进行检错,以防止可能呈现的差错。例5.1 main函数中对max函数的阐明若

用传统款式可写为:

int max();

用今世款式可写为:

int max(int a,int b);

或写为:

int max(int,int);

C说话中又规定在以下几种环境时可以省去主调函数中对被调函数的函数阐明。

1. 要是被调函数的返回值是整型或字符型时, 可以纰谬被调函数作阐明,而直接调用。这时系统将自动对被调函数返回值按整型处置惩罚。例5.3的主函数中未对函数s作阐明而直接调用即属此种情形。

2. 当被调函数的函数定义呈现在主调函数之前时, 在主调函数中也可以纰谬被调函数再作阐明而直接调用。例如例5.1中, 函数max的定义放在main 函数之前,是以可在main函数中省去对 max函数的函数阐明int max(int a,int b)。

3. 如在所有函数定义之前, 在函数外预先阐清楚明了各个函数的类型,则在今后的各主调函数中,可不再对被调函数作阐明。例如:

char str(int a);

float f(float b);

main()

char str(int a)

float f(float b)

此中第一,二行对str函数和f函数预先作了阐明。 是以在今后各函数中无须对str和f函数再作阐明就可直接调用。

4. 对库函数的调用不必要再作阐明, 但必须把该函数的头文件用include敕令包孕在源文件前部。数组作为函数参数数组可以作为函数的参数应用,进行数据传送。 数组用作函数参数有两种形式,一种是把数组元素(下标变量)作为实参应用; 另一种是把数组名作为函数的形参和实参应用。一、数组元素作函数实参数组元素便是下标变量,它与通俗变量并无差别。 是以它作为函数实参应用与通俗变量是完全相同的,在发生函数调用时, 把作为实参的数组元素的值传送给形参,实现单向的值传送。例5.4阐清楚明了这种环境。[例5.4]判别一个整数数组中各元素的值,若大年夜于0 则输出该值,若小于即是0则输出0值。编程如下:

void nzp(int v)

{

if(v>0)

printf("%d ",v);

else

printf("%d ",0);

}

main()

{

int a[5],i;

printf("input 5 numbers

");

for(i=0;i1)

按公式可编程如下:

long ff(int n)

{

long f;

if(n%c

",x,z);

else

{

move(n-1,x,z,y);

printf("%c-->%c

",x,z);

move(n-1,y,x,z);

}

}

main()

{

int h;

printf("

input number:

");

scanf("%d",&h);

printf("the step to moving %2d diskes:

",h);

move(h,'a','b','c');

}

move(int n,int x,int y,int z)

{

if(n==1)

printf("%-->%c

",x,z);

else

{

move(n-1,x,z,y);

printf("%c-->%c

",x,z);

move(n-1,y,x,z);

}

}

main()

{ ……

move(h,'a','b','c');

}

从法度榜样中可以看出,move函数是一个递归函数,它有四个形参n,x,y,z。n表示圆盘数,x,y,z分腕表示三根针。move 函数的功能是把x上的n个圆盘移动到z 上。当n==1时,直接把x上的圆盘移至z上,输出x→z。如n!=1则分为三步:递归调用move函数,把n-1个圆盘从x移到y;输出x→z;递归调用move函数,把n-1个圆盘从y移到z。在递归调用历程中n=n-1,故n的值逐次递减,着末n=1时,终止递归,逐层返回。当n=4 时法度榜样运行的结果为

input number:

4

the step to moving 4 diskes:

a→b

a→c

b→c

a→b

c→a

c→b

a→b

a→c

b→c

b→a

c→a

b→c

a→b

a→c

b→c

变量的感化域

在评论争论函数的形参变量时曾经提到, 形参变量只在被调用时代才分配内存单元,调用停止急速开释。 这一点注解形参变量只有在函数内才是有效的, 脱离该函数就不能再应用了。这种变量有效性的范围称变量的感化域。不仅对付形参变量, C说话中所有的量都有自己的感化域。变量阐明的要领不合,其感化域也不合。 C说话中的变量,按感化域范围可分为两种, 即局部变量和全局变量。

一、局部变量

局部变量也称为内部变量。局部变量是在函数内作定义阐明的。其感化域仅限于函数内, 脱离该函数后再应用这种变量是不法的。

例如:

int f1(int a) /*函数f1*/

{

int b,c;

……

}a,b,c感化域

int f2(int x) /*函数f2*/

{

int y,z;

}x,y,z感化域

main()

{

int m,n;

}

m,n感化域 在函数f1内定义了三个变量,a为形参,b,c为一样平常变量。在 f1的范围内a,b,c有效,或者说a,b,c变量的感化域限于f1内。同理,x,y,z的感化域限于f2内。 m,n的感化域限于main函数内。关于局部变量的感化域还要阐明以下几点:

1. 主函数中定义的变量也只能在主函数中应用,不能在其它函数中应用。同时,主函数中也不能应用其它函数中定义的变量。由于主函数也是一个函数,它与其它函数是平行关系。这一点是与其它说话不合的,应予以重视。

2. 形参变量是属于被调函数的局部变量,实参变量是属于主调函数的局部变量。

3. 准许在不合的函数中应用相同的变量名,它们代表不合的工具,分配不合的单元,互不滋扰,也不会发生肴杂。如在例5.3 中,形参和实参的变量名都为n,是完全准许的。4. 在复合语句中也可定义变量,其感化域只在复合语句范围内。例如:

main()

{

int s,a;

……

{

int b;

s=a+b;

……b感化域

}

……s,a感化域

}[例5.11]main()

{

int i=2,j=3,k;

k=i+j;

{

int k=8;

if(i==3) printf("%d

",k);

}

printf("%d

%d

",i,k);

}

main()

{

int i=2,j=3,k;

k=i+j;

{

int k=8;

if(i=3) printf("%d

",k);

}

printf("%d

%d

",i,k);

}

本法度榜样在main中定义了i,j,k三个变量,此中k未赋初值。 而在复合语句内又定义了一个变量k,并赋初值为8。应该重视这两个k不是同一个变量。在复合语句外由main定义的k起感化,而在复合语句内则由在复合语句内定义的k起感化。是以法度榜样第4行的k为main所定义,其值应为5。第7行输出k值,该行在复合语句内,由复合语句内定义的k起感化,其初值为8,故输出值为8,第9行输出i,k值。i是在全部法度榜样中有效的,第7行对i赋值为3,故以输出也为3。而第9行已在复合语句之外,输出的k应为main所定义的k,此k值由第4 行已得到为5,故输出也为5。

二、全局变量

全局变量也称为外部变量,它是在函数外部定义的变量。 它不属于哪一个函数,它属于一个源法度榜样文件。其感化域是全部源法度榜样。在函数中应用全局变量,一样平常应作全局变量阐明。 只有在函数内颠末阐明的全局变量才能应用。全局变量的阐明符为extern。 但在一个函数之前定义的全局变量,在该函数内应用可不再加以阐明。 例如:

int a,b; /*外部变量*/

void f1() /*函数f1*/

float x,y; /*外部变量*/

int fz() /*函数fz*/

main() /*主函数*/

/*全局变量x,y感化域 全局变量a,b感化域*/

从上例可以看出a、b、x、y 都是在函数外部定义的外部变量,都是全局变量。但x,y 定义在函数f1之后,而在f1内又无对x,y的阐明,以是它们在f1内无效。 a,b定义在源法度榜样最前面,是以在f1,f2及main内不加阐明也可应用。

[例5.12]输入正方体的长宽高l,w,h。求体积及三个面x*y,x*z,y*z的面积。

int s1,s2,s3;

int vs( int a,int b,int c)

{

int v;

v=a*b*c;

s1=a*b;

s2=b*c;

s3=a*c;

return v;

}

main()

{

int v,l,w,h;

printf("

input length,width and height

");

scanf("%d%d%d",&l,&w,&h);

v=vs(l,w,h);

printf("v=%d s1=%d s2=%d s3=%d

",v,s1,s2,s3);

}

本法度榜样中定义了三个外部变量s1,s2,s3, 用来寄放三个面积,其感化域为全部法度榜样。函数vs用来求正方体体积和三个面积, 函数的返回值为体积v。由主函数完生长宽高的输入及结果输出。因为C说话规定函数返回值只有一个, 当必要增添函数的返回数据时,用外部变量是一种很好的要领。本例中,如不应用外部变量, 在主函数中就弗成能取得v,s1,s2,s3四个值。而采纳了外部变量, 在函数vs中求得的s1,s2,s3值在main 中仍旧有效。是以外部变量是实现函数之间数据通讯的有效手段。对付全局变量还有以下几点阐明:

1. 对付局部变量的定义和阐明,可以不加区分。而对付外部变量则不然,外部变量的定义和外部变量的阐明并不是一回事。外部变量定义必须在所有的函数之外,且只能定义一次。其一样平常形式为: [extern] 类型阐明符 变量名,变量名… 此中方括号内的extern可以省去不写。

例如: int a,b;

等效于:

extern int a,b;

而外部变量阐明呈现在要应用该外部变量的各个函数内, 在全部法度榜样内,可能呈现多次,外部变量阐明的一样平常形式为: extern 类型阐明符 变量名,变量名,…; 外部变量在定义时就已分配了内存单元, 外部变量定义可作初始赋值,外部变量阐明不能再赋初始值, 只是注解在函数内要应用某外部变量。

2. 外部变量可加强函数模块之间的数据联系, 然则又使函数要寄托这些变量,因而使得函数的自力性低落。从模块化法度榜样设计的不雅点来看这是晦气的, 是以在不需要时只管即便不要应用全局变量。

3. 在同一源文件中,准许全局变量和局部变量同名。在局部变量的感化域内,全局变量不起感化。

[例5.13]int vs(int l,int w)

{

extern int h;

int v;

v=l*w*h;

return v;

}

main()

{

extern int w,h;

int l=5;

printf("v=%d",vs(l,w));

}

int l=3,w=4,h=5;

本例法度榜样中,外部变量在着末定义, 是以在前面函数中对要用的外部变量必须进行阐明。外部变量l,w和vs函数的形参l,w同名。外部变量都作了初始赋值,mian函数中也对l作了初始化赋值。履行法度榜样时,在printf语句中调用vs函数,实参l的值应为main中定义的l值,即是5,外部变量l在main内不起感化;实参w的值为外部变量w的值为4,进入vs后这两个值传送给形参l,wvs函数中应用的h 为外部变量,其值为5,是以v的谋略结果为100,返回主函数后输出。变量的存储类型各类变量的感化域不合, 就其本色来说是因变量的存储类型相同。所谓存储类型是指变量占用内存空间的要领, 也称为存储要领。

变量的存储要领可分为“静态存储”和“动态存储”两种。

静态存储变量平日是在变量定义时就分定存储单元并不停维持不变, 直至全部法度榜样停止。5.5.1节中先容的全局变量即属于此类存储要领。动态存储变量是在法度榜样履行历程中,应用它时才分配存储单元, 应用完毕急速开释。 范例的例子是函数的形式参数,在函数定义时并不给形参分配存储单元,只是在函数被调用时,才予以分配, 调用函数完毕急速开释。要是一个函数被多次调用,则反复地分配、 开释形参变量的存储单元。从以上阐发可知, 静态存储变量是不停存在的, 而动态存储变量则时而存在时而消掉。我们又把这种因为变量存储要领不合而孕育发生的特点称变量的生计期。 生计期表示了变量存在的光阴。 生计期和感化域是从光阴和空间这两个不合的角度来描述变量的特点,这两者既有联系,又有差别。 一个变量究竟属于哪一种存储要领, 并不能仅从其感化域来鉴定,还应有明确的存储类型阐明。

在C说话中,对变量的存储类型阐明有以下四种:

auto     自动变量

register   寄存器变量

extern    外部变量

static    静态变量

自动变量和寄存器变量属于动态存储要领, 外部变量和静1980在线娱乐登陆态变量属于静态存储要领。在先容了变量的存储类型之后, 可以知道对一个变量的阐明不仅应阐明其数据类型,还应阐明其存储类型。 是以变量阐明的完备形式应为: 存储类型阐明符 数据类型阐明符 变量名,变量名…; 例如:

static int a,b;           阐明a,b为静态类型变量

auto char c1,c2;          阐明c1,c2为自动字符变量

static int a[5]=;    阐明a为静整型数组

extern int x,y;           阐明x,y为外部整型变量

下面分手先容以上四种存储类型:

一、自动变量的类型阐明符为auto。

这种存储类型是C说话法度榜样中应用最广泛的一种类型。C说话规定, 函数内凡未加存储类型阐明的变量均视为自动变量, 也便是说自动变量可省去阐明符auto。 在前面各章的法度榜样中所定义的变量凡未加存储类型阐明符的都是自动变量。例如:

{ int i,j,k;

char c;

……

}等价于: { auto int i,j,k;

auto char c;

……

}

自动变量具有以下特征:

1. 自动变量的感化域仅限于定义该变量的个体内。在函数中定义的自动变量,只在该函数内有效。在复合语句中定义的自动变量只在该复合语句中有效。 例如:

int kv(int a)

{

auto int x,y;

{ auto char c;

} /*c的感化域*/

……

} /*a,x,y的感化域*/

2. 自动变量属于动态存储要领,只有在应用它,即定义该变量的函数被调用时才给它分配存储单元,开始它的生计期。函数调用停止,开释存储单元,停止生计期。是以函数调用停止之后,自动变量的值不能保留。在复合语句中定义的自动变量,在退出复合语句后也不能再应用,否则将引起差错。例如以下法度榜样:

main()

{ auto int a,s,p;

printf("

input a number:

");

scanf("%d",&a);

if(a>0)

printf("s=%d p=%d

",s,p);

}

{ auto int a;

printf("

input a number:

");

scanf("%d",&a);

if(a>0){

auto int s,p;

s=a+a;

p=a*a;

}

printf("s=%d p=%d

",s,p);

}

s,p是在复合语句内定义的自动变量,只能在该复合语句内有效。而法度榜样的第9行却是退出复合语句之后用printf语句输出s,p的值,这显然会引起差错。

3. 因为自动变量的感化域和生计期都局限于定义它的个体内( 函数或复合语句内), 是以不合的个体中准许应用同名的变量而不会肴杂。 纵然在函数内定义的自动变量也可与该函数内部的复合语句中定义的自动变量同名。例5.14注解了这种环境。

[例5.14]

main()

{

auto int a,s=100,p=100;

printf("

input a number:

");

scanf("%d",&a);

if(a>0)

{

auto int s,p;

s=a+a;

p=a*a;

printf("s=%d p=%d

",s,p);

}

printf("s=%d p=%d

",s,p);

}

本法度榜样在main函数中和复合语句内两次定义了变量s,p为自动变量。按照C说话的规定,在复合语句内,应由复合语句中定义的s,p起感化,故s的值应为a+ a,p的值为a*a。退出复合语句后的s,p 应为main所定义的s,p,其值在初始化时给定,均为100。从输出结果可以阐发出两个s和两个p虽变量名相同, 但却是两个不合的变量。

4. 对构造类型的自动变量如数组等,弗成作初始化赋值。

二、外部变量外部变量的类型阐明符为extern。

在前面先容全局变量时已先容过外部变量。这里再弥补阐明外部变量的几个特征:

1. 外部变量和全局变量是对同一类变量的两种不合角度的提法。全局变是是从它的感化域提出的,外部变量从它的存储要领提出的,表示了它的生计期。

2. 当一个源法度榜样由多少个源文件组成时, 在一个源文件中定义的外部变量在其它的源文件中也有效。例如有一个源法度榜样由源文件F1.C和F2.C组成: F1.C

int a,b; /*外部变量定义*/

char c; /*外部变量定义*/

main()

{

……

}

F2.C

extern int a,b; /*外部变量阐明*/

extern char c; /*外部变量阐明*/

func (int x,y)

在F1.C和F2.C两个文件中都要应用a,b,c三个变量。在F1.C文件中把a,b,c都定义为外部变量。在F2.C文件顶用extern把三个变量阐明为外部变量,表示这些变量已在其它文件中定义,并把这些变量的类型和变量名,编译系统不再为它们分配内存空间。 对构造类型的外部变量, 如数组等可以在阐明时作初始化赋值,若不赋初值,则系统自动定义它们的初值为0。

三、静态变量

静态变量的类型阐明符是static。 静态变量当然是属于静态存储要领,然则属于静态存储要领的量不必然便是静态变量, 例如外部变量虽属于静态存储要领,但不必然是静态变量,必须由 static加以定义后才能成为静态外部变量,或称静态全局变量。 对付自动变量,前面已经先容它属于动态存储要领。 然则也可以用static定义它为静态自动变量,或称静态局部变量,从而成为静态存储要领。

由此看来, 一个变量可由static进行再阐明,并改变其原有的存储要领。

1. 静态局部变量

在局部变量的阐明前再加上static阐明符就构成静态局部变量。

例如:

static int a,b;

static float array[5]=;

静态局部变量属于静态存储要领,它具有以下特征:

(1)静态局部变量在函数内定义,但不象自动变量那样,当调用时就存在,退出函数时就消掉。静态局部变量始终存在着,也便是说它的生计期为全部源法度榜样。

(2)静态局部变量的生计期虽然为全部源法度榜样,然则其感化域仍与自动变量相同,即只能在定义该变量的函数内应用该变量。退出该函数后, 只管该变量还继承存在,但不能应用它。

(3)准许对构造类静态局部量赋初值。在数组一章中,先容数组初始化时已作过阐明。若未赋以初值,则由系统自动赋以0值。

(4)对基础类型的静态局部变量若在阐明时未赋以初值,则系统自动付与0值。而对自动变量不赋初值,则其值是不定的。 根据静态局部变量的特征, 可以看出它是一种生计期为全部源法度榜样的量。虽然脱离定义它的函数后不能应用,但如再次调用定义它的函数时,它又可继承应用, 而且保存了前次被调用后留下的值。 是以,当多次调用一个函数且要求在调用之间保留某些变量的值时,可斟酌采纳静态局部变量。虽然用全局变量也可以达到上述目的,但全局变量无意偶尔会造成意外的副感化,是以仍以采纳局部静态变量为宜。

[例5.15]main()

{

int i;

void f(); /*函数阐明*/

for(i=1;i

发表评论
加载中...

相关文章