函数及变量的存储_第1页
函数及变量的存储_第2页
函数及变量的存储_第3页
函数及变量的存储_第4页
函数及变量的存储_第5页
已阅读5页,还剩69页未读 继续免费阅读

下载本文档

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

文档简介

函数及变量的存储第1页,共74页,2023年,2月20日,星期三目标描述C语言中的函数掌握C语言中常见的内置函数理解函数原型和函数的返回值熟练掌握自定义函数的定义和调用理解变量的作用域、生命期理解变量的存储类型正确理解函数在C语言程序设计中的作用和地位;理解函数、形参、实参、作用域、生存期的概念;掌握各种函数的定义、原型声明和调用的方法;理解全局变量、局部变量、静态变量、静态函数的作用域和生存期;掌握递归函数的编写规则;掌握利用工程管理程序的方法;

第2页,共74页,2023年,2月20日,星期三6.1.1什么是模块化

模块化程序设计方法:人们在求解某个复杂问题时,通常采用逐步分解、分而治之的方法,也就是将一个大问题分解成若干个比较容易求解的小问题,然后分别求解。程序员在设计一个复杂的应用程序时,往往也是把整个程序划分成若干个功能较为单一的程序模块,然后分别予以实现,最后再把所有的程序模块象搭积木一样装配起来,这种在程序设计中分而治之的策略,被称为模块化程序设计方法。6.1概述第3页,共74页,2023年,2月20日,星期三maincabdefghijkl图6-1C程序的模块化C程序的模块化第4页,共74页,2023年,2月20日,星期三6.1.2什么是函数?在C语言中,模块就是一组逻辑相关(这也体现了软件工程中的“内聚性”)的语句的集合或说是用于完成特定任务的程序代码的单元。根据规模的大小,C语言中的模块有三种形式:语句块(即复合语句)函数文件。函数是C语言中最为常用的模块单元。因此通常说C程序是由函数组成的;函数是C语言程序的基本组成部分。第5页,共74页,2023年,2月20日,星期三voidmain(){::::::x=x*x*x;y=y*y*y;z=z*z*z;ans1=x+y+z;

a=a*a*a;b=b*b*b;c=c*c*c;ans2=a+b+c;:::::}重复多次的同一计算类型voidmain(){::::::ans1=cube(x,y,z);ans2=cube(a,b,c);:::::}intcube(inta,b,c){intans;ans=(a*a*a)+(b*b*b)+(c*c*c);returnans;}函数主程序ans函数可以把相对独立的某个功能抽象出来,使之成为程序中的一个独立实体。可以在同一个程序或其他程序中多次重复使用为什么使用函数?第6页,共74页,2023年,2月20日,星期三使程序变得更简短而清晰有利于程序维护可以提高程序开发的效率提高了代码的重用性函数机制的优点第7页,共74页,2023年,2月20日,星期三6.2.1

函数的分类内置函数(库函数):由C语言系统提供;用户无须定义,也不必在程序中作类型说明;只需在程序前包含有该函数定义的头文件;自定义函数:用户在程序中根据需要而编写的函数;从用户角度6.2函数的定义与使用第8页,共74页,2023年,2月20日,星期三内置函数头文件用途doublesqrt(doublex)math.h计算x的平方根doublepow(doublex,doubley)计算x的y次幂doubleceil(doublex)求不小于x的最小整数,并以double形式显示doublefloor(doublex)求不大于x的最大整数,并以double形式显示inttoupper(intx)ctype.h如果x为小写字母,则返回对应的大写字母inttolower(intx)如果x为大写字母,则返回对应的小写字母intrand(void)stdlib.h产生一个随机数voidexit(intretval)终止程序常用库函数使用库函数的一般方法:1、函数功能2、函数参数的数目和顺序,及各参数意义和类型3、函数返回值意义和类型4、需要使用的包含文件第9页,共74页,2023年,2月20日,星期三函数定义格式函数体合法标识符函数返回值类型函数类型函数名(形参类型说明表){

说明部分

语句部分

return语句}以下红色的为函数的6个元素函数头部第10页,共74页,2023年,2月20日,星期三参数:一般用于一个函数把数据传递给另一个函数(调用者和被调用者之间),实现函数之间的通信。定义函数的时候,函数的参数是形式参数,是对一件具体事件可能需要数据的假设。返回值:即函数带回来的值。而返回值的类型是在定义函数的时指定的,即用“返回值类型”指定函数的类型。1、如果类型标识符为void则表示不需要带回函数值;2、如果没有类型标识,则TC2.0默认返回值类型是int(在vc++6.0中则认为默认为void,视编译器的不同而不同)。函数体:一对花括号里面的内容(包括声明部分和语句部分)又被称为函数体,当函数体为空的时候,该函数也被叫做空函数,就是说它什么也不做。第11页,共74页,2023年,2月20日,星期三例6-1计算两个整数的平均数的函数。/*

函数功能:就算平均数函数入口参数:整型x,存储第一个运算数整型y,存储第二个运算数函数返回值:平均数*/intAverage(intx,inty){intresult;result=(x+y)/2;returnresult;}第12页,共74页,2023年,2月20日,星期三

大多数情况下,调用者(主调函数)和被调用者(被调用函数)之间有数据传递关系,也就是说该函数有参数(可以称为有参函数,否则叫做无参函数)。在定义函数时函数名后面括号中的参数称为“形式参数”(简称“形参”),在主调函数中调用一个函数时,函数名后面括号中的参数(可以是一个“表达式”)称为“实际参数”(简称“实参”)。参数和参数传递的方式6.2.3函数的参数和返回值第13页,共74页,2023年,2月20日,星期三例6-2调用函数时的数据(参数)传递。#include<stdio.h>voidmain(){intmax(intx,inty);inta,b,c;scanf("%d,%d",&a,&b);c=max(a,b);printf("maxis%d",c);}intmax(int

x,inty)/*定义有参函数max*/{intz;z=x>y?x:y;return(z);}运行情况如下:7,8↙Maxis8第14页,共74页,2023年,2月20日,星期三关于形参和实参的说明:在定义函数中指定的形参,在函数尚未被调用时,它们并不占用内存中的存储单元。只有在发生函数调用时,函数max中的形参才被分配内存单元。在调用结束后,形参所占的内存单元也被释放。实参可以是常量、变量或表达式,例如:max(3,a+b);但要求它们有确定的值。在调用时将实参的值赋给形参。参数和参数传递的方式第15页,共74页,2023年,2月20日,星期三关于形参和实参的说明:在被定义的函数中,必须指定形参的类型。实参与形参的类型应相同或赋值兼容。在C语言中,实参向形参的数据传递是“值传递”,单向传递,只由实参传给形参,而不能由形参传回来给实参。在内存中,实参单元与形参单元是不同的单元。参数和参数传递的方式第16页,共74页,2023年,2月20日,星期三2222abxy图6-3参数值传递221015abxy图6-4实参值不变参数和参数传递的方式第17页,共74页,2023年,2月20日,星期三int

Check(intnum){if(num%5==0)return1;elsereturn0;}通常,希望通过函数调用使主调函数能得到一个确定的值,这就是函数的返回值,也称函数值。C语言中的return语句用于向调用函数返回值,语法如下:return(<表达式>);函数的返回值第18页,共74页,2023年,2月20日,星期三voidswap(intx,inty){intz;z=x;x=y;y=z; printf("\nx=%d,y=%d",x,y);}main(){inta=10,b=20;swap(a,b);printf("\na=%d,b=%d\n",a,b);}程序输出结果:x=20,y=10a=10,b=20形式参数(形参)实际参数(实参)【例】编一程序,将主函数中的两个变量的值传递给swap函数中的两个形参,交换两个形参的值。单向值传递第19页,共74页,2023年,2月20日,星期三c=max(a,b);(调用main函数)(max函数)intmax(intx,inty){intz;z=x>y?x:y;return(z);}图6-2函数调用函数的返回值第20页,共74页,2023年,2月20日,星期三voidmain(){::::::ans1=cube(2,5,7);ans2=cube(2,3,4);:::::}intcube(inta,intb,intc){intans;ans=(a*a*a)+(b*b*b)+(c*c*c);returnans;}函数主程序ans参数(实参)参数(形参)返回值第21页,共74页,2023年,2月20日,星期三(1)函数的返回值是通过函数中的return语句获得的。说明return语句将被调用函数中的一个确定值带回主调函数中去。如果需要从被调用函数带回一个数值,则被调用函数中必须包含reutrn语句。如果不需要则可以不要return语句。一个函数中可以有一个以上的return语句,执行到哪一个return语句,则哪个语句起作用。return语句后面的括号也可以不要,如“returnz;”和“return(z);”等价。return后面的值可以是一个表达式。例如,例6.2中的函数max可以改写如下:max(intx,inty){return(x>y?x:y);}第22页,共74页,2023年,2月20日,星期三(2)函数的类型。既然函数有返回值,这个值当然应属于某一个确定的类型,应当在定义函数时指定函数值的类型。例如下面是3个函数的首行:

intmax(floatx,floaty) /*函数值为整型*/

charletter(charc1,charc2))/*函数值为字符型*/

doublemin(intx,inty)) /*函数值为双精度型*/在C语言中,凡不加类型说明的函数,自动按整型处理。第23页,共74页,2023年,2月20日,星期三(3)在定义函数时指定的函数类型一般应该和return语句中的表达式类型一致。例6.2中指定max函数值为整型,而变量z也被指定为整型,通过return语句把z的值作为max的函数值,由max带回主调函数。z的类型与max函数的类型是一致的,是正确的。如果函数值的类型和return语句中表达式的值不一致,则以函数类型为准。对数值型数据,可以自动进行类型转换。即函数类型决定返回值的类型。(4)对于不带返回值的函数,应当用“void”定义函数为“无类型”(或称“空类型”)。

这样,系统就保证不使函数带回任何值,即禁止在调用函数中使用被调用函数的返回值。此时在函数体中不得出现return语句。第24页,共74页,2023年,2月20日,星期三例6-3返回值类型与函数类型不同。#include<stdio.h>voidmain(){intmax(intx,inty);floata,bintc;scanf("%f,%f",&a,&b);c=max(a,b);printf("maxis%d",c);}intmax(floatx,floaty){floatz; /*z为实型变量*/z=x>y?x:y;return(z);}运行情况如下:1.5,2.5Maxis2第25页,共74页,2023年,2月20日,星期三6.3.1函数调用的一般形式函数调用的一般形式为

函数名(实参表列);注意事项:(1)如果是调用无参函数,则“实参表列”可以没有,但是括号不能省略。(2)如果实参表列包含多个实参,则各个参数间用逗号隔开。实参可以是常量、变量、表达式、函数等6.3函数调用

第26页,共74页,2023年,2月20日,星期三注意事项:

(3)赋值对应关系:

实参1->形参1

实参2->形参2

……

实参n->形参n(4)实参表求值顺序(即实参赋值给形参的顺序)因系统而定。TC、BC、VC均是自右向左,也就是说最右边的实参最先赋值给最右边的形参,最左边的实参最后赋值给最左边的形参。但VC与TC、BC在具体赋值时稍有不同,注意它们之间的区别。第27页,共74页,2023年,2月20日,星期三例6-4实参求值的顺序。#include<stdio.h>voidmain(){intf(inta,intb);/*函数声明*/inti=2,p;p=f(i,++i);/*函数调用*/printf("%d\n",p);}intf(inta,intb)/*函数定义*/{intc;if(a>b)c=1;elseif(a==b)c=0;elsec=-1;return(c);}问:在TurboC2.0和TurboC++3.0系统上运行的结果?原型声明

i为实参

a、b为形参

第28页,共74页,2023年,2月20日,星期三若按自左至右顺序求实参的值,则函数调用相当于f(2,3),程序运行应得结果为“-1”。若按自右至左顺序求实参的值,则它相当于f(3,3),程序运行结果为“0”。分析:

如果本意是按自左而右顺序求实参的值,即f(2,3)调用,可改写成:

j=i;k=++i;p=f(j,k);

如果本意是自右而左求实参的值,即f(3,3)调用,可改写成:

j=++i;p=f(j,j);是否有办法让参数确定?第29页,共74页,2023年,2月20日,星期三1.函数语句把函数调用作为一个语句。这时不要求函数带来返回值,只要求函数完成一定的操作。例如:

printstar();printf(“Hello,World!\n”);2.函数表达式函数出现在一个表达式中,这种表达式称为函数表达式。这是要求函数带回一个确定的值以确定参加表达式的运算。例如:

C=2*max(a,b);

函数max是表达式的一部分,它的值乘2再赋给c。6.3.2函数调用的方式按函数在程序中出现的位置分,可有3种函数调用的方式:第30页,共74页,2023年,2月20日,星期三3.函数参数函数调用作为一个函数的实参。例如:

M=max(a,max(b,c));

其中max(b,c)是一次函数调用,它的值作为max另一次调用的实参。M的值是a、b、c三者中的最大者。例如:

printf(“%d”,max(a,b));

也是把max(a,b)作为printf函数的一个函数。函数调用作为函数的参数,实质上也是函数表达式形式调用的一种,因为函数的参数本来就要求是表达式形式。第31页,共74页,2023年,2月20日,星期三6.3.3对被调用函数的声明和函数原型#include<stdio.h>floatcount(int,int);voidmain(){......}floatcount(intx,inty){...}函数原型说明在形式上与函数头部类似,最后加一个分号。原型说明中参数表里的参数名可以不写(只写参数类型)。第32页,共74页,2023年,2月20日,星期三问题描述:根据用户的选择求不同形状的面积。函数调用示例#include<stdio.h>voidAreaOfRect();voidAreaOfTriangle();voidAreaOfRound();voidmain(){intselect;do{ printf("0、退出\n1、长方形\n2、三角形\n3、圆形\n"); printf("请选择功能:"); scanf("%d",&select); if(select==0)break; switch(select){ case1:AreaOfRect();break;//长方形

case2:AreaOfTriangle();break;//三角形

case3:AreaOfRound();break;//圆形

default:printf("输入有误,请在0~4之间选择。\n"); }}while(1);}voidAreaOfRect(){intx,y;printf("请输入长方形的长:");scanf("%d",&x);printf("请输入长方形的宽:");scanf("%d",&y);printf("面积为:%d\n",(x*y));}voidAreaOfTriangle(){intx,y;printf("请输入三角形的底:");scanf("%d",&x);printf("请输入三角形的高:");scanf("%d",&y);printf("面积为:%d\n",(x*y)/2);}voidAreaOfRound(){intr;printf("请输入圆形的半径:");scanf("%d",&r);printf("面积为:%d\n",3.14*r*r);}函数原型第33页,共74页,2023年,2月20日,星期三在一个函数中调用另一个函数(即被调用函数)需要具备的条件如下:首先被调用的函数必须是已经存在的函数(库函数或自定义函数)。如果使用库函数,还应该在文本开头用#include命令将调用有关库函数时所需用到的信息(这些信息是一些常量和函数原型)“包含”到本文件中来,否则函数将不能正常地得到调用。例如,前面经常用到过:#include<stdio.h>3.如果使用用户自定义的函数,则如果该函数被定义的位置在调用它的函数(即主调函数)的后面(在同一文件中),应该在主调函数中对被调函数作声明。如果被调用函数的定义出现在主调函数之前,可以不必加以声明。第34页,共74页,2023年,2月20日,星期三对于函数的位置:对于非int函数,调用单位的位置要在被调用单位在下面,否则编译产生错误。解决方法是:在调用单位加上被调用函数的声(说)明。voidf(){…}main(){…f();

…}voidf(){…}main(){…f();

…}voidf(){…}main(){voidf();…f();…}第35页,共74页,2023年,2月20日,星期三例6-5编制子函数实现求两个单精度实数的和,main函数调用该函数的时候要先声明。/*6_5.c*/#include<stdio.h>voidmain(){floatadd(floatx,floaty);/*对被调用函数add的声明*/floata,b,c;scanf("%f,%f",&a,&b);

c=add(a,b);printf("sumis%f\n",c);}floatadd(floatx,floaty)/*函数首部*/{floatz;/*函数体*/z=x+y;return(z);}运行情况如下:3.6,6.5↙sumis10.100000floatadd(float,float);第36页,共74页,2023年,2月20日,星期三综上所述,函数原型的一般形式有两种:(1)函数类型函数名(参数类型1,参数类型2,…,参数类型n);(2)函数类型函数名(参数类型1参数名1,参数类型2参数名2,…参数类型n参数名n);第37页,共74页,2023年,2月20日,星期三应该注意到函数的原型与函数的定义是不一样的。函数的定义是指对函数功能的确立,包括指定函数名、函数值类型、形参及其类型、函数体等,它是一个完整的、独立的函数单位。函数的声明的作用则是把函数的名字、函数类型以及形参的类型、个数和顺序通知编译系统,以便在调用该函数时系统按此进行对照检查(例如,函数名是否正确,实参与形参的类型和个数是否一致等)。第38页,共74页,2023年,2月20日,星期三6.3.4嵌套调用在C语言中,函数的定义是平行的,不允许进行函数的嵌套定义,即在一个函数体中不允许定义另一个函数。而函数之间的调用可以是任意的,即允许在一个函数体内再调用其他函数,在函数体中再调用其它函数称为函数的嵌套调用。第39页,共74页,2023年,2月20日,星期三voidreverse(){::::::::::::::::::::}#include<stdio.h>voidmain(){ :::::::::

palindrome(); :::::::: ::::::::}voidpalindrome(){

::::::::reverse();::::::::}从一个函数调用另一个函数称为函数的嵌套调用

例如:C规定:函数定义不可嵌套,但可以嵌套调用函数第40页,共74页,2023年,2月20日,星期三例6-6函数的嵌套调用。main(){

aia();}aia(){ber();}ber(){cal();}cal(){…..}图6-5函数的嵌套调用89246135710

函数main调用了aia,aia调用了ber,ber又调用了cal。其调用过程和返回过程如图所示。voidaia(),ber(),cal();main(){printf("I'minmain.\n");

aia();}voidaia(){printf("NowI'minaia.\n");

ber();}voidber(){printf("NowI'minber.\n");

cal();}voidcal(){printf("NowI'mincal.");}第41页,共74页,2023年,2月20日,星期三一个函数直接或间接地调用函数本身,这种调用称为递归调用,前者称为直接递归,后者称为间接递归。递归调用的函数称为递归函数。由于递归非常符合人们的思维习惯,而且许多数学函数及许多算法或数据结构都是递归定义的,因此,递归调用颇具实用价值。6.3.4函数递归调用第42页,共74页,2023年,2月20日,星期三/*此函数用于计算n的阶乘*/intfactorial(intn)

{inta;if(n==1)return1;else{a=n*factorial(n-1);returna;}}在一个函数体内调用自身称为函数的递归调用

第43页,共74页,2023年,2月20日,星期三例6-7利用函数的递归调用来求n的阶乘。#include<stdio.h>longfact();/*声明被调用函数返回值为长整型*/main()/*主函数*/{inth,i;printf("请输入任一正整数:\n");scanf("%d",&h);for(i=0;i<=h;++i)printf("%d!=%ld\n",i,fact(i));}longfact(intn)/*求阶乘函数*/{longintres;if(n==0)res=1;elseres=n*fact(n-1);/*递归调用*/return(res);}请输入任一正整数:6↙0!等于11!等于12!等于23!等于64!等于245!等于1206!等于720程序执行后显示:第44页,共74页,2023年,2月20日,星期三6.3.6程序设计举例(使用函数编写程序)例6-8

输出5之内的数字金字塔。例6-9输入精度e,使用格里高利公式求π的近似值,精确到最后一项的绝对值小于e。要求定义和调用函数funpi(e)求π的近似值。例6-10采用递归方式实现二分查找。二分查找算法是对有序数列进行查找操作的一种有效操作。实际上,这种查找方法是一个递归的过程。第45页,共74页,2023年,2月20日,星期三结构体变量作为函数参数140页例5-3将键盘输入的有关学生的档案信息用函数list实现。#include<stdio.h>structSTUD{charname[20];longnum;intage;charsex;floatscore;};voidlist(structSTUDstud){printf("%-20s%-10ld%-4d%-4c%-6.2f\n",,stud.num,stud.age, stud.sex,stud.score);}voidmain(){structSTUDstud[3];inti;for(i=0;i<3;i++){printf("InputallinformationabouttheNo.%dstudent:\n",i+1);getchar();gets(stud[i].name);scanf("%ld,%d,%c,%f",&stud[i].num,&stud[i].age,&stud[i].sex,&stud[i].score);}printf("\n%-20s%-10s%-4s%-4s%-6s\n","Name","Num","Age","Sex","Scores");for(i=0;i<3;i++)list(stud[i]);}第46页,共74页,2023年,2月20日,星期三返回结构体类型值的函数例5-4第47页,共74页,2023年,2月20日,星期三总结函数是程序中的一个相对独立的单元或模块,程序在需要时可以任意多次地调用函数来完成特定功能使用函数带来的好处:程序更清晰、易维护、分模块方便设计与开发、提高代码的重用性C语言提供了极为丰富的内置函数,这些内置函数分门别类地放在不同的头文件中,要使用这些内置函数,只要在程序前包含相应的头文件即可第48页,共74页,2023年,2月20日,星期三总结自定义函数是用户在程序中根据需要而编写的函数函数的结构包括:返回值类型、函数名、参数列表、函数体函数原型说明以便向编译器指出该函数使用什么样的格式和语法函数调用时程序控制流将转向被调函数,被调函数执行结束时,控制流返回主调函数return语句用于向调用函数返回值第49页,共74页,2023年,2月20日,星期三6.5变量的性质在C程序世界里,程序由一个个函数组成,这些函数是相对独立的模块,为了使得各个函数能彼此协作以完成一个程序任务,各个函数之间需要通信和协作,而函数之间通信所采用的媒介就是函数中的数据,也就是变量。于是对于变量来说就有两个值得考虑的问题了:变量是否可以被访问,也就是变量在什么范围中有效(可见性,作用域)。变量占据的内存单元什么时候开辟,什么时候被释放(存在性,生命期)。第50页,共74页,2023年,2月20日,星期三6.6变量的作用域与生命期限于陆地限于海洋限于空中第51页,共74页,2023年,2月20日,星期三作用域和生存期的基本概念变量的作用域即变量的作用范围(或有效范围)。表现为有的变量可以在整个程序或其它程序中进行引用,有的则只能在局部范围内引用。其作用域范围可分为两种:即局部变量和全局变量

变量的生存期变量从被生成到被撤消的这段时间。实际上就是变量占用内存的时间。

按其生存期可分为两种:即动态变量和静态变量

变量只能在其生存期内被引用。作用域和生存期是从空间和时间的角度来体现变量的特性。

第52页,共74页,2023年,2月20日,星期三6.6.2局部变量作用域和生存期定义在函数内作定义说明的变量,也称为内部变量

作用域仅限于函数内,离开函数后不可再引用。

生存期从函数被调用的时刻到函数返回调用处的时刻(静态局部变量除外)。intf1(intx,inty){intz;z=x>y?x:y;return(z);}voidf2(){printf("%d\n",z);}局部变量

变量x、y、z的作用域引用错误!第53页,共74页,2023年,2月20日,星期三

说明

(1)主函数main()中定义的变量也是局部变量,它只能在主函数中使用,其它函数不能使用。同时,主函数中也不能使用其它函数中定义的局部变量。

intf3(intx);voidmain(){inta=2,b;b=a+y;printf("%d\n",b);}intf3(intx

){inty;y=a+5;return(y);}局部变量

变量a、b的作用域变量x、y的作用域局部变量

错误!错误!第54页,共74页,2023年,2月20日,星期三

说明

(2)形参变量属于被调用函数的局部变量;实参变量则属于全局变量或调用函数的局部变量。

(3)允许在不同的函数中使用相同的变量名,它们代表不同的对象,分配不同的单元,互不干扰,也不会发生混淆。#include<stdio.h>voidsubf();voidmain(){

inta,b;

a=3,b=4;printf("main:a=%d,b=%d\n",a,b);subf();printf("main:a=%d,b=%d\n",a,b);}voidsubf(){inta,b;a=6,b=7;printf("subf:a=%d,b=%d\n",a,b);}运行结果:main:a=3,b=4subf:a=6,b=7main:a=3,b=4变量名相同

第55页,共74页,2023年,2月20日,星期三

说明

(4)在复合语句中定义的变量也是局部变量,其作用域只在复合语句范围内。其生存期是从复合语句被执行的时刻到复合语句执行完毕的时刻。#include<stdio.h>voidmain(){

inta=2,b=4;

{intk,b;k=a+5;b=a*5;printf("k=%d\n",k);printf("b=%d\n",b);}printf("b=%d\n",b);a=k+2;}main中的局部变量

复合语句中的局部变量

mian中变量a、b的作用域

复合语句中变量k、b的作用域输出k=7

输出b=10

输出b=4

错误!第56页,共74页,2023年,2月20日,星期三6.6.2全局变量作用域和生存期定义在函数外部作定义说明的变量,也称为外部变量

。它不属于哪一个函数,而属于一个源程序文件。

作用域从定义变量的位置开始到本源文件结束,及有extern说明的其它源文件。

生存期与程序相同。即从程序开始执行到程序终止的这段时间内,全局变量都有效。

#include<stdio.h>#include<math.h>intsign();//计算数n的平方根floatsqr(){if(n>0)return(sqrt(n));elsereturn(-1);}floatn=0;voidmain(){ints;floatt;scanf("%f",&n);s=sign();//取符号

t=sqr();//取平方根

printf("s=%dt=%f",s,t);}//取数n的符号intsign(){intr=0;if(n>0)r=1;if(n<0)r=-1;return(r);}定义全局变量,并赋初值局部变量全局变量n的作用域

局部变量s、t的作用域局部变量局部变量r的作用域错误!第57页,共74页,2023年,2月20日,星期三

说明

(1)应尽量少使用全局变量。全局变量在程序全部执行过程中始终占用存储单元降低了函数的独立性、通用性、可靠性及可移植性降低程序清晰性,容易出错

(2)若外部变量与局部变量同名,则外部变量被屏蔽。要引用全局变量,则必须在变量名前家上两个冒号“::”

#include<stdio.h>inta=10;

//全局变量voidmain(){

inta=100;

//局部变量(与全局变量同名)

printf("locala=%d\n",a);printf("globala=%d\n",::a);}运行结果:locala=100globala=10注意:局部变量与全局变量同名极易导致程序员犯逻辑错误。第58页,共74页,2023年,2月20日,星期三#include<stdio.h>inta=3,b=5;max(inta,intb){ intc; c=a>b?a:b; return(c);}main(){ inta=8; printf("%d\n",max(a,b));}运行结果?第59页,共74页,2023年,2月20日,星期三

说明

(3)全局变量定义必须在所有的函数之外,且只能定义一次,并可赋初始值。全局变量定义的一般形式为:[extern]类型说明符全局变量名1[=初始值1],……,全局变量名n[=初始值n];可缺省!charch='Y';voidmain(){……}charch;voidfunc(){……}定义全局变量ch错误!ch只能定义一次例:inta=2,b=4;externinta=2,b=4;第60页,共74页,2023年,2月20日,星期三

说明

(4)对全局变量进行说明,可扩展全局变量的作用域。全局变量说明的一般形式为:extern

类型说明符全局变量名1,…,全局变量名n;不可缺省!不可赋初值!voidgx(),gy();voidmain(){externintx,y;printf("1:x=%d\ty=%d\n",x,y);y=246;gx();gy();}externintx,y;voidgx(){x=135;printf("2:x=%d\ty=%d\n",x,y);}intx=0,y=0;voidgy(){printf("3:x=%d\ty=%d\n",x,y);}全局变量定义未说明前的作用域全局变量说明说明后的作用域全局变量说明说明后的作用域运行结果:

1:x=0y=02:x=135y=2463:x=135y=246第61页,共74页,2023年,2月20日,星期三

说明

(5)全局变量定义与全局变量的说明的区分

externinta;

voidfunc1(){……//引用变量a}externinta=2;

voidfunc2(){……//引用变量a}谁是定义?谁是说明?全局变量定义(因为赋了初值)全局变量说明

注意:两者中有且只能有一个对变量a赋初始值,不能都对变量a赋初始值或都不赋值,否则编译错!

第62页,共74页,2023年,2月20日,星期三6.7变量的生命期<--变量的存储类型

概述变量的属性①数据类型:变量所持有数据的性质(操作属性)。规定了它们的取值范围和可参与的运算。

②存储类型:

规定了变量占用内存空间的方式,也称为存储方式。

存储类型:寄存器、静态存储区、动态存储区

auto---------自动型

register-----寄存器型

static-------静态型

extern-------外部型动态存储区静态存储区存储类型说明符数据类型说明符变量名1,变量名2,…,变量名n;变量定义的完整形式应为:

第63页,共74页,2023年,2月20日,星期三1、动态变量(auto型变量)[auto]数据类型说明符变量名1,变量名2,…,变量名n;

定义格式说明存储类型说明符auto可以省略。动态变量只能在函数内或复合语句中定义,它属于局部变量(动态局部变量)。voidfunc(){

inti,j,k;

……}等价于autointi,j,k;autointk;

voidfunc(){……}错误!动态变量不可定义在函数外

第64页,共74页,2023年,2月20日,星期三2、静态变量(static型变量)静态变量的类型说明符是static。静态变量属于静态存储类型。静态局部变量在局部变量的说明前加上static就构成静态局部变量

例如:

staticinta,b;staticfloatarray[5]={1,2,3,4,5};第65页,共74页,2023年,2月20日,星期三静态局部变量与动态变量之比较静态局部变量与动态变量均属于局部变量静态局部变量生存期长,为整个源程序。动态变量生存期短静态局部变量的生存期虽然为整个源程序,但是其作用域仍与动态变量相同voidfunc();voidmain()

{inta;a=s+5;……}voidfunc(){staticints;……}定义静态局部变量s错误!s的作用域第66页,共74页,2023年,2月20日,星期三静态局部变量与动态变量之比较静态局部变量若在定义时未赋初值,则系统自动赋初值0

静态局部变量赋初值只一次,而动态变量赋初值可能多次#include<stdio.h>voidmain(){inti;voidfunc();//函数说明

for(i=1;i<=5;i++)func();//函数调用}voidfunc()//函数定义{

autointj=0;++j;printf("%d",j);}#include<stdio.h>voidmain(){inti;voidfunc();//函数说明

for(i=1;i<=5;i++)func();//函数调用}voidfunc()//函数定义{

staticintj=0;++j;printf("%d",j);}动态变量静态变量运行结果:11111

运行结果:12345

第67页,共74页,2023年,2月20日,星期

温馨提示

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

最新文档

评论

0/150

提交评论