C语言程序设计课件:函数和变量_第1页
C语言程序设计课件:函数和变量_第2页
C语言程序设计课件:函数和变量_第3页
C语言程序设计课件:函数和变量_第4页
C语言程序设计课件:函数和变量_第5页
已阅读5页,还剩37页未读 继续免费阅读

下载本文档

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

文档简介

函数和变量第一节函数的定义第二节函数的参数传递第三节变量的分类第四节函数的作用域第五节项目任务:输入输出子模块的编程实现第一节函数的定义一、函数概述在进行程序设计时,程序员总是将复杂的问题进行分解,化整为零,编写一段小程序就能解决一个小问题,然后将这些小程序拼装起来就能解决非常大而复杂的问题。在C语言中,这些小程序统称为函数,因此,构成C语言程序的基本单位就是函数。图6.1C语言模块化程序设计示意图由上图可以看出,函数是C源程序的基本模块,通过对函数模块的调用实现特定的功能。C语言不仅提供了极为丰富的库函数,还允许用户建立自己定义的函数。库函数是系统定义的,它们的定义分别放在不同的头文件中,用户只要用#include文件包含将头文件包含到程序中即可调用它们。用户自己定义的函数是为解决自己的特定问题自行编写的,用户可把自己的算法编成一个个相对独立的函数模块,然后用调用的方法来使用函数。例如:我们前面设计的学生成绩统计系统,这个系统要能完成学生信息的输入、学生信息的修改、学生信息的删除、学生信息的查找、学生信息的显示等功能。根据程序的功能,可以把整个程序分成6大模块,其中,菜单模块用主函数实现,其余5个功能分别用5个函数实现,通过主函数可以对另外5个函数进行调用来完成整个学生成绩统计的功能。图6.2表示了这个程序的模块结构。图6.2学生成绩统计程序的模块结构二、无参函数和有参函数的定义函数的定义主要是确定函数的名称、函数的类型以及该函数完成什么功能。(一)无参函数的定义当调用函数时,不需要向函数提供数据,则该函数成为无参函数。多数无参函数调用之后,仅完成某一操作,而不需要带回一个结果,因此,也可以不指明函数的类型。无参函数定义的一般形式如下:函数名(){

变量声明部分;执行部分;}【案例6-1】编写一个函数,输出“Hello,World!””。#include<stdio.h>display()/*display()是一个无参函数*/{printf(“*********************\n”);printf(“Hello,World!\n”);printf(“*********************\n”);}main(){display();}(二)有参函数的定义有参函数定义的一般形式如下:类型标识符函数名(形式参数列表)形式参数声明{

变量声明部分;执行部分;}【案例6-2】定义一个max函数,求两个整数中较大的一个整数。#include<stdio.h>main(){intmax(intx,inty);/*声明函数,说明本函数中要调用的函数max()在本函数后面定义*/

intnumber1,number2;intm;printf("输入两个整数:");scanf("%d%d",&number1,&number2);m=max(number1,number2);/*调用max函数,并把得到的函数返回值存入变量m中*/printf("两个数之中较大的数为:%d",m);}intmax(intx,inty)/*自定义函数,求两个数中的较大数,定义了两个整型的形式参数x和y*/{intz;z=x>y?x:y;return((z);}程序说明:(1)这个程序由两个函数组成,一个是主函数main(),一个是自定义函数max(),max()函数的功能是求x、y之中较大的数,并将较大的数返回,总之,一个C程序可以由若干函数组成,其中必须有且仅有一个主函数main()。C程序总是从主函数开始执行(不管它在程序中的什么位置),而其他函数只能被调用。(2)程序中的#include是将要用到的库函数的头文件包含到程序中来,这个程序中因为用到了标准输入输出函数scanf()和printf(),才使用#include<stdio.h>。(3)函数名前的类型标识符说明了函数的类型,max函数的数据类型为int型,这也说明该函数有返回值,而返回值的类型是int型。(4)如果形式参数不止一个,那么每个形式参数之间则以逗号分隔。(5)如果把intmax(intx,inty)写成intmax(intx,y)是错误的,因此,即使多个形式参数的类型一致,也要单独定义。(6)如果被调用函数在调用函数的后面定义,则必须在调用函数中进行声明。函数声明的一般形式为:类型标识符函数名([形参表列]);如:本例的intmax(intx,inty);三、函数调用的方式在程序中是通过对函数的调用来执行函数体的,其过程与其它语言的子程序调用相似。C语言中,函数调用的一般形式为:函数名(实际参数列表)如果是调用无参函数,则实际参表列可以没有,但括弧不能省略。实际参数表中的参数可以是常数,变量或其它构造类型数据及表达式。各实参之间用逗号分隔,实参与形参的个数应相等,类型应一致。在C语言中,可以用以下几种方式调用函数:1.函数表达式:函数作为表达式中的一项出现在表达式中,以函数返回值参与表达式的运算。这种方式要求函数是有返回值的。例如:z=max(x,y)是一个赋值表达式,把max的返回值赋予变量z。2.函数语句:函数调用的一般形式加上分号即构成函数语句。例如:printf("%d",a);scanf("%d",&b);都是以函数语句的方式调用函数。这时不要求函数带回值,只要求函数完成一定的操作。3.函数实参:函数作为另一个函数调用的实际参数出现。这种情况是把该函数的返回值作为实参进行传送,因此要求该函数必须是有返回值的。例如:printf("%d",max(x,y));即是把max调用的返回值又作为printf函数的实参来使用的。四、对被调用函数的声明在一个函数中调用另一函数(即被调用函数)需要具备哪些条件呢?首先被调用的函数必须是已经存在的函数(是库函数或用户自己定义的函数)。但只有这一条件还不够。如果使用库函数,一般还应该在本文件开头用#include命令将用到的库函数的头文件包含到程序中来。例如,前面程序中已经用过的:#include"stdio.h",其中"stdio.h"是一个“头文件”,stdio是Standardinput&output的缩写,意为“标准输入输出”。在stdio.h中放了输入输出库函数所用到的一些宏定义信息。如果不包含“stdio.h”文件中的信息就无法使用输入输出库中的函数。同样如果用到数学库中的函数,应该用#include"math.h"。如果使用用户自己定义的函数,而且该函数与调用它的函数(即主调函数)在同一个文件中,一般还应该在调函数中对被调用函数的返回值类型作说明。这种类型说明的一般形式为:函数类型被调用函数的函数名(类型1参数名1,类型2参数名2);C语言规定:以下几种情况,可以不必在调用函数前对被调函数作说明。1.若函数的值是整型或字符型,可以不必进行说明,系统对它们自动按整型说明。但是使用这种方法时,系统无法对参数的类型做检查。若调用函数时参数使用不当,在编译时也不会报错。因此,为了程序清晰和安全,建议都加以说明为好。2.若被调函数的定义出现在主调函数之前,则不必加以说明了。3.若已在所有函数定义之前,在文件的开头,在函数的外部已说明了函数类型,则在主调函数中不必对所调用的函数再作类型说明。除了以上三种情况外,都应该按上述介绍的方法对所调用函数的返回值作类型说明,否则编译时就会出现错误。【案例6-3】编写一个求三个数均值的函数,要求如下:函数名:average;参数分别是:doublea,doubleb,doublec;返回值类型:double。函数功能:要求函数返回a,b,c三个浮点数的均值。#include<stdio.h>main(){floataverage(floata,floatb,floatc);/*对被调函数的说明*/floatx,y,z,c;printf("请输入三个浮点数:");scanf("%f,%f",&x,&y,&z);c=average(x,y,z);/*调用函数aveage求三个浮点数的平均值*/printf("三个浮点数的平均值是:%f",c);}floataverage(floata,floatb,floatc)/*定义average函数*/{floatave;ave=(a+b+c)/3.0;return(ave);}【注意】主函数中的ave变量要定义float类型,average函数的类型也为float类型。第二节函数的参数传递在程序中,如果仅仅用函数代替一个语句序列,那么函数的作用就不大了。一般情况下,常常要求同一个函数可以根据不同的数据,进行相同的处理之后得到不同的结果,这样,函数与函数之间通常要传递数据和计算结果。C语言中采用参数、返回值和全局变量三种方式进行数据传递。主调函数与被调函数之间是双向传递数据,当调用函数时,通过函数的参数,主调函数为形参提供数据,调用结束时,被调函数通过返回语句将函数的运行结果(称为返回值)带回主调函数中,函数之间还可以通过使用全局变量,在一个函数内使用其他函数中的某些变量的结果,本节仅讨论函数的参数传递和函数的返回值,一、形式参数和实际参数形式参数(简称“形参”)是指定义函数时,跟在函数名后的小括号内的变量名。实际参数(简称“实参”)则是指调用函数时,跟在函数名后的小括号内的表达式。在C语言中,实参向形参传送的方式是“值传递”。C语言函数参数采用“值传递”的方法,其含义是:在调用函数时,将实参变量的值取出来,复制给形参变量,使形参变量在数值上与实参变量相等,在函数内部使用从实参中复制来的值进行处理。C语言中的实参可以是一个表达式,调用时先计算表达式的值,再将结果(值)复制到形参对应的存储单元中,一旦函数执行完毕,这些存储单元所保存的值不再保留。形式参数是函数的局部变量,仅在函数内部才有意义,不能用它来传递函数的结果。实参与形参的个数必须相同,顺序一致,并且实参与对应的形参类型应相同或赋值兼容。值传递的优点在于被调用的函数不可能改变主调函数中变量的值,而只能改变它的局部的临时副本。这样就可以避免被调用函数的操作对调用函数中的变量可能产生的副作用。前面的案例6-2和6-3都是采用值传递的方式进行参数传递的。【案例6-4】分析如下的程序代码,看看结果如何?若在主函数中变量a=5,b=10,编写一个函数交换主函数中两个变量的值,使变量a=10,b=5。#include<stdio.h>voidswap(intx,inty){inttemp;/*借助临时变量交换两个形参变量x和y的值*/temp=x;x=y;y=temp;}main(){inta,b;a=5;b=10;/*说明两个变量并赋初值*/printf("beforeswapa=%d,b=%d\n",a,b);swap(a,b);/*用变量a和b作为实际参数调用函数*/printf("afterswapa=%d,b=%d\n",a,b);}程序说明:在程序中调用swap时,实参变量a和b的值传递给了形参变量x和y,并且在函数的内部完成了x和y值的交换,但是形参变量x和y与实参变量a和b各自使用自己的内存区域,他们之间仅仅在参数传递时进行了数值的传递,所以变量x和y的变化并不影响变量a和b。因此,在主程序中变量a,b的值还是没有变化。【想一想】如何才能完成变量a和b的值的互换呢?二、函数的返回值通常,希望通过函数调用使主调函数能得到一个确定的值,这就是函数的返回值。函数的返回值用return语句来实现返回语句格式:return(表达式);或return表达式;下面对函数返回值作一些说明:1、函数中可以有多个return语句,执行到哪一个return语句,就从哪一个return语句返回。Return语句后面的括弧也可以不要,如:returnx;它与return(x)是相同的。2、return只能返回一个值,而不能返回多个值。下面的使用是错误的:return(x,y);试图让一个函数返回两个值,从数学上也是讲不通的。3、函数值的类型。既然函数有返回值,这个值当然应属于某个确定的类型,因此应当在定义函数时指定函数值的类型。例如:intmax(x,y);函数值为整型,charstr(c1,c2);函数值为字符型floatmin(x,y);函数值为浮点型。C语言规定,凡不加类型说明的函数,一律自动按整型处理。return(表达式)语句中的表达式值的类型应与定义函数时函数的类型一致。如果不一致,以定义函数时规定的函数类型为准进行类型转换。4、如果函数中没有return语句,并不代表函数没有返回值,只能说明函数的返回值是一个不确定的数5、为了明确规定函数没有返回值,可以用void关键字来定义函数,表示“无类型”。如下:voidecholine(){}这样函数就绝对没有返回值了。一般情况下,如果函数没有返回值,一定要将函数定义为void类型的。三、数组作函数参数前面几节中,我们使用的函数参数均是简单变量,如int型、float型、char型等。函数参数除了可以是简单变量之外,还可以是数组。数组作函数参数分两种情形,一种是数组元素作函数参数,另一种则是数组名作函数参数。(一)数组元素作函数参数数组元素就是下标变量,它与普通变量并无区别。因此它作为函数实参使用与普通变量是完全相同的,在发生函数调用时,把作为实参的数组元素的值传送给形参,实现单向的值传送。【案例6-5】判别一个整数数组中各元素的值,若大于0则输出该值,若小于等于0则输出0值。分析:首先定义一个无返回值函数output,并说明其形参n为整型变量。在函数体中根据n值输出相应的结果。在main函数中用一个for语句输入数组各元素,每输入一个就以该元素作实参调用一次output函数,即把数组元素a[i]的值传送给形参n,供output函数使用。#include<stdio.h>voidoutput(intn){if(n>0)printf("%d",n);

elseprintf("0");}voidmain(){inta[5];inti;printf("请输入5个整数:\n");for(i=0;i<5;i++){scanf("%d",&a[i]);output(a[i]);/*函数的参数是数组元素*/}}(二)数组名作函数参数前面已经讨论过,在变量作函数参数时,所进行的值传送是单向的。即只能从实参传向形参,不能从形参传回实参。形参的初值和实参相同,而形参的值发生改变后,实参并不变化,两者的终值是不同的。而当用数组名作函数参数时,情况则不同。由于实际上形参和实参为同一数组,因此当形参数组发生变化时,实参数组也随之变化。当然这种情况不能理解为发生了“双向”的值传递。但从实际情况来看,调用函数之后实参数组的值将由于形参数组值的变化而变化。【案例6-6】数组student中存放了一个学生5门课程的成绩,求平均成绩。#include<stdio.h>floatave(floats[5])/*求平均值*/{inti;floatave1,sum=s[0];for(i=1;i<5;i++)sum=sum+s[i];ave1=sum/5;returnave1;}voidmain(){floatscore[5],average;inti;printf("\n输入5门课的成绩:\n");for(i=0;i<5;i++)scanf("%f",&score[i]);average=ave(score);/*以数组名为实参调用ave函数*/printf("平均分数是:%5.2f",average);}【注意】①程序中用数组名作函数实参,函数ave的形参也定义为数组。注意,应在主调函数和被调用函数中分别定义数组,例中s是形参数组名,score是实参数组名,分别在其所在函数中定义,不能只在一方定义。②数组名作函数参数时,实参和形参都应为数组名,此时,实参与形参的传递为“地址传递”,所谓地址传递是指在调用函数时,系统并没有给形参数组分配新的存储空间,而只是将实参数组的首地址传送给形参数组,使形参数组与实参数组共用同一数组空间。第三节变量的分类一、变量的作用域变量的作用域是指变量的有效范围。C语言允许把一个大的程序分成几个文件,每个文件分别包含若干函数,各个文件可以分别进行编译,然后再链接到一起形成一个完整的可执行文件。程序中各个函数之间的通信可以通过参数传递来实现,也可以通过使用公共的数据来实现。那么,哪些数据可以被各个函数共用而哪些数据又不能共用呢?这就涉及到变量的作用范围问题。根据变量的作用范围的不同,可将变量分为局部变量和全局变量。(一)局部变量局部变量是指在函数内部或程序块内定义的变量。局部变量只在定义它的函数或程序块内有效。在函数内定义的变量以及形式参数均是局部变量。【案例6-7】有关局部变量的例子。分析:在程序中两个num变量都是局部变量,只在本身函数里可见。因此,在两个函数出现同名的变量不会互相干扰。#include<stdio.h>voidadd(int);main(){intnum=5;add(num);printf("\n%d",num);/*输出5*/}voidadd(intnum){num++;printf("%d",num);/*输出6*/}【试一试】运行程序,看看你的结果是否正确。(二)全局变量在函数外部定义的变量,从其的定义位置开始,到本文件结束为止的所有函数都可以直接引用,所以这种变量又称为全局变量或外部变量。例如:a、b的作用范围x、y的作用范围intx,y;main(){/*...*/}inta,b;fun1(){a、b的作用范围x、y的作用范围/*...*/}fun2(){/*...*/}对于具有全局作用域的变量,我们可以在程序的任何位置访问它们。当一个变量是在所有函数的外部声明,也就是在程序的开头声明,那么这个变量就是全局变量。【案例6-8】有关全局变量的例子。#include<stdio.h>voidadd();intnum=10;/*num是一个全局变量*/main(){add();printf("\n%d",num);/*输出11*/}voidadd(){num++;printf("%d",num);/*输出11*/}【说明】上面的main()和add()里面,并没有声明num,但是在最后输出的时候却要求输出num,这是由于在程序的开始声明了num是全局变量,也就是在所有函数里都可以使用这个变量。这时候一个函数里改变了变量的值,其他函数里的值也会出现影响。上面的例子输出都是11,因为在add()函数里改变了num的值,由于num是全局变量,就好象它们两个函数共用一个变量,所以在main()函数里的num也随之改变了。二、变量的存储类型在C语言中,对变量的存储类型说明有以下四种:自动变量(auto)、寄存器变量(register)、外部变量(extern)、静态变量(static)。(一)Auto变量1.定义定义格式:[auto]数据类型变量表;例如:inta;autointb;2.说明(1)自动变量属于动态存储方式。在函数中定义的自动变量,只在该函数内有效;函数被调用时分配存储空间,调用结束就释放。在复合语句中定义的自动变量,只在该复合语句中有效;退出复合语句后,也不能再使用,否则将引起错误。(2)定义但不初始化,则其值是不确定的。如果初始化,则赋初值操作是在调用时进行的,且每次调用都要重新赋一次初值。(3)由于自动变量的作用域和生存期,都局限于定义它的个体内(函数或复合语句),因此不同的个体中允许使用同名的变量而不会混淆。即使在函数内定义的自动变量,也可与该函数内部的复合语句中定义的自动变量同名。(二)Static变量1.定义定义格式:static数据类型内部变量表;例如:staticintb;2.说明(1)静态内部变量属于静态存储。在程序执行过程中,即使所在函数调用结束也不释放。即在程序执行期间,静态内部变量始终存在,但其它函数是不能引用它们的。(2)定义但不初始化,则自动赋以“0”(整型和实型)或'\0'(字符型);且每次调用它们所在的函数时,不再重新赋初值,只是保留上次调用结束时的值!(3)需要保留函数上一次调用结束时的值或变量只被引用而不改变其值,可以使用静态内部变量(4)静态全局变量,只能在本文件中的各个函数中使用,其他文件中的函数不能使用。(三)Register变量一般情况下,变量的值都是存储在内存中的。为提高执行效率,C语言允许将局部变量的值存放到寄存器中,这种变量就称为寄存器变量。定义格式如下:1.定义

register数据类型变量表;2.说明(1)只有局部变量才能定义成寄存器变量,即全局变量不行。(2)允许使用的寄存器数目是有限的,不能定义任意多个寄存器变量。(四)Extern变量1.定义定义格式:extern数据类型变量表;例如:externinta;2.说明(1)在一个程序文件中,后面定义的全局变量,前面函数中要使用时,必须把该变量说明为extern变量。(2)在多文件程序中,一个文件中定义的全局变量,其他文件中要使用时,必须把该变量说明为extern变量。第四节函数的作用域一般情况下,函数可以被其他的所有函数调用,即:可以把函数看作是全局的。但如果一个函数被声明成静态的,则该函数只能在定义它的文件中被调用,而其他文件中的函数则不能调用它。根据函数是否能被其他文件调用,可将函数分为内部函数和外部函数。一、内部函数(局部函数)1.概念如果一个函数只能被本文件中其他函数调用,而不能被其他文件中的函数调用,则该函数被称为内部函数。2.定义定义格式:static数据类型函数名(变量表);例如:staticintfunc(inta,intb);3.说明内部函数又称静态函数。使用内部函数,可以使函数只局限于所在文件,如果在不同的文件中有同名的内部函数,互不干扰。二、外部函数(全局函数)1.概念如果一个函数能被本文件和其他文件中的函数调用,则该函数为外部函数。2.定义定义格式:[extern]数据类型函数名(变量表);例如:externintfunc(inta,intb);3.说明一般定义函数时,前面都不加extern,此时函数默认为外部函数,外部函数在其他文件中调用时,需用extern进行声明。第五节项目任务:输入输出子模块的编程实现【项目案例】输入输出子模块的编程实现分析:前几章中,我们完成了一些简单的成绩管理功能,现在我们采用模块化程序设计的思想来对它进行一些修改。我们将在main函数中实现菜单显示及选择功能,而学生成绩的输入和显示功能则分别用函数来实现,再把程序模块像搭积木一样装配起来形成一个完整的系统。#defineN30#include"stdio.h"/*I/O函数*/#include"conio.h"/*屏幕操作函数*/intnumber[N];charname[N][9];floatmark[N][6];voidshuru()/*定义输入学生信息的函数*/{inti;charch;printf("%10s%10s%10s%10s%10s%10s%10s\n","学号","姓名","语文","数学","英语","物理","化学");for(i=0;i<N;i++){printf("\n请输入学号:");scanf

温馨提示

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

评论

0/150

提交评论