版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第5章
函数函数
6C语言程序的开发环境5.1模块化程序设计与函数5.2函数定义5.3函数调用5.4函数递归调用5.5变量的作用域与储存期5.6编译预处理5.1模块化程序设计与函数
在设计较复杂的程序时,一般采用自顶向下的方法,将问题划分为几个部分,各个部分再进行细化,直到分解为很容易求解的小问题为止。求解小问题的程序算法叫做“功能模块”,把复杂的问题分解为单独的模块后,称为模块化设计。因此C语言程序设计是模块化程序设计。5.1.1模块与函数C语言中程序是由基本语句和函数组成,每个函数负责完成独立的小任务。c语言程序设计是模块化程序设计。任务、模块和函数的关系是:解决整个特定问题的大任务被分解成若干个小问题即功能模块,功能模块由一个或者多个函数来具体实现。解决整个特定问题的程序就通过这些函数的调用来完成。总结来说,模块化程序设计就是由设计函数和调用函数来实现。5.1.1模块与函数编程输出以下图形。
*********团结就是力量!*********方法一:(不用函数实现的程序源代码)#include<bits/stdc++.h>intmain(){ printf("*********\n"); printf("团结就是力量!\n"); printf("*********\n"); }【例5.1】5.1.1模块与函数方法二:(用函数实现的程序源代码)#include<bits/stdc++.h>intmain(){ voidprintstar();/*对printstar函数进行声明*/ voidprintunity();/*对printhelloworld函数进行声明*/ printstar();/*调用printstar函数*/ printunity();/*调用printhelloworld函数*/ printstar();/*调用printstar函数*/}voidprintstar(){/*定义printstar函数*/ printf("*********\n");}voidprintunity(){/*定义printhelloworld函数*/ printf("团结就是力量!\n");}5.1.2模块化设计的基本原则
1.模块独立模块完成独立的功能,和其他模块间的关系简单,各模块可以单独调试。修改某一模块,不会造成整个程序的混乱。
模块的独立性原则是指模块完成独立的功能,可单独进行调试。各个模块之间的联系简单,修改一个模块不会对整个程序产生大的影响。这要求我们在模块设计中注意几个问题:首先,因为模块具有相对独立性,所以在分解任务时要注意对问题的综合。其次,各个模块之间的联系简单,尽量只包含简单的数据传递这种联系,不要涉及到控制联系。最后要注意模块的私有数据的使用。5.1.2模块设计原则
2.模块规模适当
模块的规模不能太大或者太小。功能太强的模块,一般可读性就会很差,功能太小的模块,会出现很多接口。初学者只需记住此原则,在以后的实践中需经常总结经验。
3.分解模块要注意层次
在对任务进行多层次分解时,要尤其注意对问题进行抽象化。开始只需考虑大的模块,不要过分注意细节。在中期,大模块的设计中,再逐步细化求精,分解成较小的模块进行设计。5.2函数定义
在C语言中,函数(Function)是一个处理过程,把一段程序的工作放在函数中进行,函数结束时可以携带或不带处理结果。C语言中的程序处理过程全部都是以函数形式出现,最简单的程序至少也包含一个main()函数。函数必须先定义和声明后才能调用。5.2函数定义用户使用的函数通常有两种:标准库函数和自定义函数。标准库函数:是系统提供给用户,c语言的强大功能依赖于它丰富的库函数。需要注意的是,如果用户想调用这些函数,则必须先用编译预处理命令将相应的头文件包含到程序中。在前面各章的例题中反复用到printf、scanf、getchar、putchar、gets、puts、strcat等函数均属此类。自定义函数:用户自己编写。不仅要在程序中定义函数本身,而且在主调函数模块中还必须对该被调函数进行类型说明,然后才能使用。5.2.1函数定义的一般形式函数的定义就是把子任务的程序写到一个函数里。函数包含函数的说明部分和函数体两大部分。一般形式:类型名函数名(参数类型说明及列表)
{局部变量说明语句序列
}例如:输入两个整数,以下函数minpear输出两个数中较小者:intminpear(inta,intb)/*函数定义和形式参数类型说明*/{intt;/*局部变量说明*/if(a<b)t=a;/*执行语句*/elset=b;returnt;/*返回语句*/}
1.函数的说明部分函数的说明部分包括函数的类型、函数名、参数表和参数类型的说明。例如上例中第一行为函数的说明部分。(1)函数的类型。即函数的返回值类型。表示给调用者提供什么类型的返回值。函数可以有或者没有返回值。
如果函数没有返回值,则定义函数类型为空,用标识符void表示空类型。例如:voiddata(inta)
如果函数有返回值,例如上例中min函数的类型为int,即函数的返回值类型是int。(2)函数名。也叫函数标识符。它遵循C语句标识符的命名规范。(3)参数表。函数名后面的括号“()”里的内容是参数表,由变量标识符和类型标识符构成。参数表中的变量也叫作形式参数,即形参。5.2.1函数定义的一般形式
1.函数的说明部分
根据参数表中是否有参数可将函数分为无参函数和有参函数。无参函数:函数可以没有形参,叫作无参函数,注意无参函数的括号“()”不能省略。有参函数:如果有形参,在定义形参时,必须指定形参的类型。例如:intmin(inta,intb)5.2.1函数定义的一般形式
2.函数体
在函数定义中,函数体是用花括号括起来的部分,函数的具体功能在函数体中完成。函数体内的开头部分是定义和说明部分,后面是语句部分。函数声明和函数体构成了函数定义。
函数的返回值,是指函数被调用之后,执行函数体中的程序段后得到的结果,并返回给主调函数。关于函数的返回值有下面几点说明:
(1)有返回值的函数体:需要有return返回语句。格式如下:return(表达式);该语句的执行顺序是先计算表达式的值,然后把结果返回给主调函数。
(2)return语句表达式的类型要和函数定义中函数的类型保持一致。如果不一致,则以函数的类型为准,自动进行类型转换。
(3)若函数类型为整型,则函数定义时可以省略函数类型。
例如,上面提到的自定义函数min(a,b),根据传入的a和b两个值的大小返回一个t值,也就是两个数中的较小者。5.2.1函数定义的一般形式
函数调用时,应该遵循先定义后使用的原则。如果函数调用出现在函数定义之前,则要对函数先进行声明,也就是让系统先知道要用哪个函数以及函数类型等信息。5.3函数调用
函数声明与函数定义时的第一行是基本一致的,包括函数类型、函数名、形参个数、类型、次序。不同的是,函数声明是函数定义时的第一行在结尾时加上“;”,并且参数列表中可以省略参数名。
格式如下:
类型名函数名(参数类型说明列表);5.3.1函数的声明5.3.1函数的声明编程实现孔融让梨,输出较小的梨。步骤分析:输入两个整数,表示梨的重量;调用函数minpear()进行较小值的比较运算;输出运算结果;Intmain(){ intminpear(inta,intb);/*对minpear函数的声明*/ intx,y,z; printf("inputtwonumbers:\n"); scanf("%d%d",&x,&y); z=minpear(x,y);/*调用minpear函数*/ printf("minmum=%d",z);#include<bits/stdc++.h>intminpear(inta,intb){/*函数定义和形式参数类型说明*/ intt;/*局部变量说明*/ if(a<b)t=a;/*执行语句*/ elset=b; returnt;/*返回语句*/}【例5.2】5.3.1函数的声明
本例中,把x,y中的值传送给minpear的形参a,b。minpear函数执行的结果(a或b)将返回给变量z。最后由主函数输出z的值。
注意:孔融让梨程序运行结果如图:
根据函数有参数或者无参数两种情况,函数调用可分为:有参函数调用和无参函数调用。1、有参函数调用的形式:函数名(实参表达式)
例如:min(inta,intb);2、无参函数调用的形式:函数名()
例如:func();5.3.2函数的调用
根据调用方式不同,函数调用可分为:语句调用和表达式调用1、语句调用的形式:
例如:scanf(“%d”,&x);2、表达式调用的形式:
例如:a+min(x,y);5.3.3函数的嵌套调用
在C语言中不允许“嵌套定义函数”,即不能在一个函数的定义中作另一个函数的定义。例如下面的例子,在main函数的定义中作printdata函数的定义,这种写法是错误的:intmain(intargc,char*argv[]){//定义func函数voidprintdata(inta){printf("inprintdata,a=%d\n",a);}printdata(8);return0;}
这样的代码,在VC编译器,或者VisualStudio编译器中,属于非法定义的代码。虽然在func函数的调用之前,定义了func函数。但是,不能够在main函数中定义func函数,就是不能够嵌套定义函数。
注意:5.3.3函数的嵌套调用
但是C语言允许在一个函数的定义中出现对另一个函数的调用。这叫作函数的嵌套调用。也就是在被调函数中又调用其它函数。这与其它语言的子程序嵌套的情形是类似的。例如:intb()/*定义函数b*/{…….}inta()/*定义函数a*/{…….b();/*a中调用函数b*/}voidmain(){……a();/*主函数中调用函数a*/}调用a()f2()调用b()main()b()5.3.3函数的嵌套调用
图中表示了两层嵌套的情况。其执行过程是:在执行main函数时遇到了调用a函数的语句,即转到a函数去执行,在执行a函数时遇到了调用b函数的语句,则转到b函数去执行,当b函数执行完毕后返回a函数的断点继续执行,a函数执行完毕后返回main函数的断点继续执行。5.3.3函数的嵌套调用
学校为鼓励学生和辅导老师以赛促教、以赛促学、以赛促改,进一步推进学校创新创业教育迈上新台阶,要求统计计算机专业两个班的大学生计算机应用能力竞赛获奖人数,学校把任务分配给了辅导员,辅导员把任务分配给了班长。试编程实现。代码设计如下:#include<bits/stdc++.h>intmain(){ intcounselor(); printf("%d",counselor());}intcounselor(){ intmonitor(); return(monitor());}intmonitor(){ inta,b; scanf("%d,%d",&a,&b); returna+b;}【例5.3】5.3.3函数的嵌套调用大学生计算机应用能力竞赛获奖人数程序运行结果如图:main函数相当于学校,在输出函数中调用counselor函数。counselor函数中,在return语句中调用了monitor函数,monitor函数来求两个班的人数,并且通过return语句返回人数之和,层层返回。5.3.3函数的嵌套调用【例5.4】计算s=12!+22!+32!#include<bits/stdc++.h>longf1(intd){ /*定义求立方值的函数f1*/ intcube; longr; longf2(int); /*嵌套调用阶乘函数f2*/ cube=d*d; r=f2(cube); returnr;}
解题思路:本题可通过编写两个函数来实现,第一个函数f1用来实现计算平方值,第二个函数f2用来实现计算阶乘值。代码设计如下:5.3.3函数的嵌套调用longf2(intq){ /*定义求阶乘值的函数f2*/ longc=1; inti; for(i=1;i<=q;i++) c=c*i; returnc;}main(){ inti; longs=0; for(i=1;i<=3;i++) s=s+f1(i); /*调用求立方值的函数f1*/ printf("\ns=%ld\n",s);}5.3.4参数传递
形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用。实参出现在主调函数中,进入被调函数后,实参变量也不能使用。形参和实参的功能是作数据传送。发生函数调用时,主调函数把实参的值传送给被调函数的形参从而实现主调函数向被调函数的数据传送。
5.3.4参数传递
函数的形参和实参具有以下特点:1、形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变量。2、实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使实参获得确定值。3、实参和形参在数量上,类型上,顺序上应严格一致,否则会发生类型不匹配”的错误。4、函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。5.3.4参数传递【例5.5】参数传递算法实例。#include<bits/stdc++.h>intmain(){ intn; printf("inputnumber\n"); scanf("%d",&n); ints(intn); s(n); printf("n=%d\n",n);}ints(intn){ inti; for(i=n-1;i>=1;i--) n=n+i; printf("n=%d\n",n);}5.3.4参数传递
本程序中定义了一个函数s,该函数的功能是求n+(n-1)+….+1的值。在主函数中输入n值,并作为实参,在调用时传送给s函数的形参量n(注意,本例的形参变量和实参变量的标识符都为n,但这是两个不同的量,各自的作用域不同)。
在主函数中用printf语句输出一次n值,这个n值是实参n的值。在函数s中也用printf语句输出了一次n值,这个n值是形参最后取得的n值0。从运行情况看,输入n值为10。即实参n的值为10。把此值传给函数s时,形参n的初值也为10,在执行函数过程中,形参n的值变为55。返回主函数之后,输出实参n的值仍为10。可见实参的值不随形参的变化而变化。5.4函数递归调用直接递归形式如下:voidfunc(){......func();/*函数func中调用函数func,直接递归*/......}
在函数内部调用自己,叫作函数的递归调用。递归调用分为直接递归和间接递归。
某一函数在函数体内部直接调用自身函数叫作函数的直接递归。即函数的嵌套调用的是函数本身。嵌套调用自身函数在我们的学习生活中就好像是榜样的示范!修身立德,才能言传身教,彰显榜样力量!
某一函数在函数体内部调用其他函数,其他函数再调用本函数,叫作函数的间接递归。5.4函数递归调用(2)间接递归形式如下:voidfunc1(){......func2();/*函数func1中调用函数func2*/......}voidfunc2(){......func1();/*函数func2中调用函数func1,间接递归*/
递归思想是一个非常有用的解决问题的思路。它不仅可以解决本身是递归定义的问题,还可以把看起来很复杂不容易描述出来的过程变得简单明了。下面针对这两方面分别举例说明递归思想。5.4函数递归调用【例5.6】用递归算法计算n!由于n!=n*(n-1)!是递归定义,所以求n!
(n-1)!
(n-1)!
(n-2)!
(n–2)!
(n-3)!
……
0!的问题,
根据公式有0!=1,
再反过来依次求出1!,2!……直到最后求出n!。5.4函数递归调用#include<stdio.h>longfac(intn){longf;if(n<0)printf("n<0,inputerror");elseif(n==0||n==1)f=1;elsef=fac(n-1)*n;return(f);}intmain(){intn;longy;printf("\ninputainteagernumber:\n");scanf("%d",&n);y=fac(n);printf("%d!=%ld",n,y);}直到最后的fac(n)都做完了,f的值被返回到了它的调用点:主函数中,这样就是一个递归运算。
程序中给出的函数fac是一个递归函数。主函数调用fac后即执行函数fac,如果n<0,n==0或n=1时都将结束函数的执行,否则就递归调用fac函数自身。注意每次递归调用的实参为n-1,即把n-1的值赋予形参n,最后当n-1的值为1时再作递归调用,形参n的值也为1,将使递归终止。然后可逐层退回。5.4函数递归调用
运行上述程序,若输入为5,则求5!。在主函数中调用语句y=fac(5),进入fac函数执行,判断n=5,不满足n等于0或1,故应该执行f=fac(n-1)*n,即f=fac(5-1)*5。此语句为递归调用。转为求fac(4)。进行四次递归调用后,fac函数的形参变为1,满足elseif(n==0||n==1),将结束函数的执行,故不再进行递归调用,而开始逐层返回主调函数。fac(1)的函数返回值为1,fac(2)的返回值为1*2=2,fac(3)的返回值为2*3=6,fac(4)的返回值为6*4=24,最后返回值fac(5)为24*5=120。递归算法程序运行结果如图所示:5.4函数递归调用
【例5.7】汉诺塔游戏是理论指导实践,锻炼学生们动手操作的经典游戏,请编程实现。汉诺塔是一个很繁杂的游戏,但可以用递归的方法异常简单的完成。规则:(1)一次只能移动一个金片。
(2)大的不能放在小的上面。
(3)只能在三个位置中移动。总体思想:1.将i-1个盘子先放到B座位上。2.将A座上地剩下的一个盘移动到C盘上。3.将i-1个盘从B座移动到C座上。5.4函数的递归调用递归法解汉诺塔#include<bits/stdc++.h>voidhanoi(intn,inta,intb,intc)
{
if(n==1)
printf(“%d->%d”,a,c);
else
{hanoi(n-1,a,c,b);
printf(“%d->%d”,a,c);
hanoi(n-1,b,a,c);
}
}voidmain()
{intn;
printf(“inputn:”);
scanf(“%d”,&n);
hanoi(n,1,2,3);
}再将n-1个盘子从b经过a移动到cn=1时,直接将金片从a移动到cn-1个金片从a经过c移动到b5.4函数的递归调用voidhanoi(intn,inta,intb,intc)
{
if(n==1)
printf(“%d->%d”,a,c);
else
{hanoi(n-1,a,c,b);
printf(“%d->%d”,a,c);
hanoi(n-1,b,a,c);
}
}voidmain()
{intn;
printf(“inputn:”);
scanf(“%d”,&n);
hanoi(n,1,2,3);
}递归解汉诺塔步骤输入3,则n=35.4函数的递归调用voidhanoi(intn,inta,intb,intc)
{
if(n==1)
printf(“%d->%d”,a,c);
else
{hanoi(n-1,a,c,b);
printf(“%d->%d”,a,c);
hanoi(n-1,b,a,c);
}
}voidmain()
{intn;
printf(“inputn:”);
scanf(“%d”,&n);
hanoi(n,1,2,3);
}递归解汉诺塔步骤n=3
主函数调用hanoi(n,1,2,3);第一次调用。第一次调用hanoi(n,a,b,c)(第一层)即要把三个金片移到c5.4函数的递归调用递归解汉诺塔步骤voidhanoi(intn,inta,intb,intc)
{
if(n==1)
printf(“%d->%d”,a,c);
else
{hanoi(n-1,a,c,b);
printf(“%d->%d”,a,c);
hanoi(n-1,b,a,c);
}
}voidmain()
{intn;
printf(“inputn:”);
scanf(“%d”,&n);
hanoi(n,1,2,3);
}由于n>1则执行hanoi(n-1,a,c,b)
(第二次调用)n=35.4函数的递归调用递归解汉诺塔步骤voidhanoi(intn,inta,intb,intc)
{
if(n==1)
printf(“%d->%d”,a,c);
else
{hanoi(n-1,a,c,b);
printf(“%d->%d”,a,c);
hanoi(n-1,b,a,c);
}
}voidmain()
{intn;
printf(“inputn:”);
scanf(“%d”,&n);
hanoi(n,1,2,3);
}由于仍然n>1则执行hanoi(n-1,a,c,b)
(第三次调用)5.4函数的递归调用递归解汉诺塔步骤voidhanoi(intn,inta,intb,intc)
{
if(n==1)
printf(“%d->%d”,a,c);
else
{hanoi(n-1,a,c,b);
printf(“%d->%d”,a,c);
hanoi(n-1,b,a,c);
}
}voidmain()
{intn;
printf(“inputn:”);
scanf(“%d”,&n);
hanoi(n,1,2,3);
}n=2第三层执行完毕,返回到第二层,即下去执行printf(“%d->%d”,a,c);把第二个金片摆到第二根针上5.4函数的递归调用递归解汉诺塔步骤voidhanoi(intn,inta,intb,intc)
{
if(n==1)
printf(“%d->%d”,a,c);
else
{hanoi(n-1,a,c,b);
printf(“%d->%d”,a,c);
hanoi(n-1,b,a,c);
}
}voidmain()
{intn;
printf(“inputn:”);
scanf(“%d”,&n);
hanoi(n,1,2,3);
}n=2执行下一条语句,又调用第三层hanoi(1,3,1,2)5.4函数的递归调用递归解汉诺塔步骤voidhanoi(intn,inta,intb,intc)
{
if(n==1)
printf(“%d->%d”,a,c);
else
{hanoi(n-1,a,c,b);
printf(“%d->%d”,a,c);
hanoi(n-1,b,a,c);
}
}voidmain()
{intn;
printf(“inputn:”);
scanf(“%d”,&n);
hanoi(n,1,2,3);
}n=1n=1,执行结果为3
25.4函数的递归调用递归解汉诺塔步骤voidhanoi(intn,inta,intb,intc)
{
if(n==1)
printf(“%d->%d”,a,c);
else
{hanoi(n-1,a,c,b);
printf(“%d->%d”,a,c);
hanoi(n-1,b,a,c);
}
}voidmain()
{intn;
printf(“inputn:”);
scanf(“%d”,&n);
hanoi(n,1,2,3);
}n=3第二层也执行完了,返回第一层,执行接下来的语句,结果为1
3。5.4函数的递归调用递归解汉诺塔步骤voidhanoi(intn,inta,intb,intc)
{
if(n==1)
printf(“%d->%d”,a,c);
else
{hanoi(n-1,a,c,b);
printf(“%d->%d”,a,c);
hanoi(n-1,b,a,c);
}
}voidmain()
{intn;
printf(“inputn:”);
scanf(“%d”,&n);
hanoi(n,1,2,3);
}n=3执行接下来的语句,再次调用
第二层hanoi(2,2,1,3)5.4函数的递归调用递归解汉诺塔步骤voidhanoi(intn,inta,intb,intc)
{
if(n==1)
printf(“%d->%d”,a,c);
else
{hanoi(n-1,a,c,b);
printf(“%d->%d”,a,c);
hanoi(n-1,b,a,c);
}
}voidmain()
{intn;
printf(“inputn:”);
scanf(“%d”,&n);
hanoi(n,1,2,3);
}5.5变量的作用域与储存期
变量的作用域,即变量有效性的范围。例如函数中的形参变量,只在函数调用时才给形参分配内存单元,函数调用结束后该内存单元就会被释放。这说明形参有效性的范围即作用域是函数内。形参在函数以外的范围是不起作用的。C语言中的变量,根据作用域可划分为两类,即局部变量和全局变量。5.5.1变量根据作用域进行划分变量
局部变量也叫内部变量。局部变量的作用域是函数内,即它是在函数内作定义说明的。函数以外的地方使用这种变量是不合法的。例如:voidfunc(){inta=3;c1+=32 c2+=32; c3+=32; c4+=32;}
在函数func中使用main函数中定义的局部变量c1,c2,c3和c4是非法的。c1,c2,c3和c4在main函数中定义说明,只能在main函数中使用,即c1,c2,c3和c4的作用域仅限main函数。故在func函数中使用c1,c2,c3和c4是非法的。
1.局部变量voidmain(){charc1,c2,c3,c4; printf("Enterc1,c2,c3,c4:"); scanf("%c%c%c%c",&c1,&c2,&c3,&c4); func(); printf(“%c%c%c%c\n”,c1,c2,c3,c4);}5.5.1变量根据作用域进行划分变量正确的使用如下:【例5.8】#include<bits/stdc++.h>voidfunc(){ charc1,c2,c3,c4; /*定义函数func中的局部变量c1,c2,c3和c4*/ c1='A',c2='B',c3='C',c4='D’; c1+=32; c2+=32; c3+=32; c4+=32; printf("%c%c%c%c\n",c1,c2,c3,c4);/*输出函数func中的c1,c2,c3和c4*/}intmain(){ charc1,c2,c3,c4; printf("Enterc1,c2,c3,c4:"); scanf("%c%c%c%c",&c1,&c2,&c3,&c4); func();/*调用函数func()*/ printf("%c%c%c%c\n",c1,c2,c3,c4);/*输出main函数中的c1,c2,c3和c4*/}5.5.1变量根据作用域进行划分变量
全局变量也叫外部变量,它是在函数外部定义,其作用域是从定义开始,到文件结束为止。对任何函数来说,它都不是局部的变量。全局变量具有全局作用域,即定义后,可以用在文件的所有函数中。如果要在函数中使用全局变量,应先对全局变量进行说明。遵循先说明后使用的原则。全局变量的说明符为extern,可以省略。但是,如果全局变量的定义在前,函数内使用全局变量在后,这种情况可不再加以说明。
2.全局变量5.5.1变量根据作用域进行划分变量
2.全局变量【例5.9】全局变量在main函数中赋值并改变的实例。#include<bits/stdc++.h>charc1,c2,c3,c4; /*定义全局变量c1,c2,c3和c4*/voidfunc(){ c1+=32; /*使用全局变量在main函数中赋的值,并改变m和n的值*/ c2+=32; c3+=32; c4+=32; printf("%c%c%c%c\n",c1,c2,c3,c4);/*输出已改变的c1,c2,c3和c4的值*/}intmain(){ c1='T',c2='E',c3='A',c4='M’; /*对全局变量c1,c2,c3和c4赋值*/ func(); /*调用函数func()*/ printf("%c%c%c%c\n",c1,c2,c3,c4);/*输出c1,c2,c3和c4*/}5.5.2变量根据存储方式进行划分
静态存储类型的变量的生存期为程序执行的整个过程,在该过程中占有固定的存储空间,通常称它们为永久存储。变量按存储方式划分:—静态存储—动态存储说明
动态存储类型变量只生存在某一段时间内。例如,函数的形参和函数体或分程序中定义的变量,只是在程序进入该函数或分程序时才分配存储空间,当该函数或分程序执行完后,变量对应的存储空间又被撤销。5.5.2变量根据存储方式进行划分1、静态存储类别(1)全局变量
全局变量全部存放在静态存储区,在程序开始执行时给全局变量分配存储区,程序执行完毕就释放内存。全局变量占据固定的存储单元,而不动态地进行分配和释放;(2)静态局部变量
静态局部变量是用static声明的局部变量,它属于静态存储方式。局部变量的值在函数调用结束后释放。有时希望保留函数中局部变量的原值,这种情况需要指定局部变量为“静态局部变量”,用关键字static进行声明。例如:Staticintm,n;
注意:静态局部变量在函数结束后仍保留原值,不随函数的结束而消失,生存期为整个程序。静态局部变量在编译时赋初值,即只赋初值一次,若未赋初值,系统自动赋值0.5.5.2变量根据存储方式进行划分【例5.10】静态局部变量实例。
#include<bits/stdc++.h>intfunc(){ staticintn=3; n*=2; return(n);}intmain(){ inti; for(i=0;i<3;i++) printf("%d\n",func());}5.5.2变量根据存储方式进行划分2、动态存储类别动态存储方式:是在程序运行期间根据需要给变量动态的分配存储空间。动态存储区存放函数的形式参数和auto自动变量。auto自动变量,是未加static声明的局部变量。函数中的局部变量如果不加static存储类别,都属于动态地分配存储空间,数据存储在动态存储区中。
函数中的形参和在函数中定义的变量都属于自动变量,在调用该函数时系统会给它们分配存储空间,在函数调用结束时就自动释放这些存储空间。自动变量用关键字auto作存储类别的声明。形式如下:intf(inta)/*定义f函数,a为参数*/{autointb,c=3;/*定义b,c自动变量*/……}a是形参,b,c是自动变量,对c赋初值3。执行完f函数后,自动释放a,b,c所占的存储单元。关键字auto可以省略,auto不写则隐含定为“自动存储类别”,属于动态存储方式。5.6编译预处理
“编译预处理”是C语言编译系统的一个组成部分。是在编译前由编译系统中的预处理程序对源程序的预处理命令进行加工。
与源程序中的语句不同,源程序中的预处理命令以“#”开头,结束没有分号,它们可以放在程序中的任何位置,作用域是自出现点到源程序的末尾。
预处理命令包括执行宏定义(宏替换)、文件包含和条件编译。5.6.1宏定义无参宏的宏名后不带参数。无参宏定义的一般形式为:#define标识符字符串:其中,“#”表示该行为预处理命令,“define”为宏定义命令,“标识符”为定义的宏名,这里为“M”,“字符串”可以是常数、表达式、格式串等。例如
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 汽车销售代销合同书
- 工业设备维修风险管理服务合同
- 商铺租赁解除合同策略
- 企业自来水设施安装协议
- 养殖场合伙合同
- 私人借款合同的关键内容
- 猎头招聘服务合同权益争议解决方式
- 温州居民房屋买卖合同
- 木材材料采购合同格式
- 标准型钢铁购销协议
- 医院事业单位招录100题真题真解(结构化面试)
- 培训机构学校:教师管理手册
- 39 《出师表》对比阅读-2024-2025中考语文文言文阅读专项训练(含答案)
- 糖尿病的预防及治疗幻灯片
- 综合能力测试(一)附有答案
- YB-T+4190-2018工程用机编钢丝网及组合体
- 简述光纤温度传感器的原理及应用
- 执行信息屏蔽申请书
- 小区消防移交物业协议书
- 第四节任务4 船舶纵倾讲解
- 【视神经脊髓炎谱系疾病的探究进展文献综述3800字】
评论
0/150
提交评论