版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
“学生成绩管理系统”中项目整体框架设计
本模块的主要任务是对“班级学生成绩管理系统”这一项目的整体框架进行设计并进行函数定义。主要掌握函数的定义和调用方法,能够善于利用函数,减少重复编写程序段的工作量。学习本模块后应能对“班级学生成绩管理系统”的整体框架结构进行正确的函数设计。知识目标:熟悉模块化设计思想。掌握函数的定义和调用方法。了解局部变量和全局变量的概念及其作用范围。能力目标:能够对项目整体框架的函数进行设计。7.1项目整体框架设计
7.1.1任务情境7.1.2知识必备7.1.3任务实施7.1.4知识扩展任务目标:能够对“班级学生成绩管理系统”中所涉及到的函数进行总体设计。7.1.1任务情境项目的整体框架设计是程序开发中关系重大的一环。整体框架是程序的总体结构,是程序设计中非常重要的部分。整体框架设计的好处是为项目搭好一个骨架,这个骨架包含了项目的各种功能模块,后面的工作就是如何完成这些功能模块,当这些功能模块全部实现后,整个项目也就完成了。项目的整体框架设计应当充分的进行调查研究,充分与用户进行沟通,充分了解用户的需要,在此基础上给出项目的总体规则设计方案并写出相应的函数设计。引例:编写一个函数,打印一条由星号构成的横线。7.1.2知识必备1#include<stdio.h>voidmain(){voidprint_star();print_star();\\第一次调用print_starprintf("欢迎使用本程序!\n");print_star();\\第二次调用print_star}voidprint_star()\\定义print_star{printf("********************************\n");}程序代码如下:代码贴士这个程序中,main()函数两次调用print_star()函数都打印出数目相同的星号构成的横线。1、模块化程序设计思想
在进行程序设计时,如果遇到一个复杂的问题,最好的办法就是将原始问题分解成若干个易于求解的小问题,每一个小问题都用一个相对独立的程序模块来处理,最后,再把所有的模块像搭积木一样拼合在一起,形成一个完整的程序。这种在程序设计中分而治之的策略,被称为模块化程序设计方法,这是结构化程序设计中的一条重要原则。几乎所有的高级程序设计语言都提供了自己实现程序模块化的方法。在C语言中,由于函数是程序的基本组成单位,所以,可以很方便的利用函数来实现程序的模块化,这也是C语言的重要特色之一。利用函数不仅可以实现程序的模块化,使程序设计变得简单和直观,同时,也提高了程序的易读性和易维护性。而且,我们还可以把程序中需要多次执行的计算或操作编写成通用的函数,以备需要时调用。同一函数不论在程序中被调用多少次,在源程序中只须书写依次,编译一次,这样,避免了大量重复程序段,缩短了源程序的长度,也节省了占用的内存空间,减少了编译时间。2、C函数的分类(1)从函数定义的角度看,函数可分为库函数和用户定义函数两种。1)库函数:由C系统提供,用户无须定义,也不必在程序中作类型说明,只需在程序前包含有该函数原型的头文件即可在程序中直接调用。在前面各章的例题中反复用到printf、scanf、getchar、putchar、gets、puts、strcat等函数均属此类。2)用户定义函数:由用户按需要写的函数。对于用户自定义函数,不仅要在程序中定义函数本身,而且在主调函数模块中还必须对该被调函数进行类型说明,然后才能使用。(2)从函数的返回值来分,可把函数分为有返回值函数和无返回值函数两种。1)有返回值函数:此类函数被调用执行完后将向调用者返回一个执行结果,称为函数返回值。如数学函数即属于此类函数。由用户定义的这种要返回函数值的函数,必须在函数定义和函数说明中明确返回值的类型。2)无返回值函数:此类函数用于完成某项特定的处理任务,执行完成后不向调用者返回函数值。这类函数类似于其它语言的过程。由于函数无须返回值,用户在定义此类函数时可指定它的返回为“空类型”,空类型的说明符为“void”。(3)从主调函数和被调函数之间数据传送的角度看,可分为无参函数和有参函数两种。1)无参函数:函数定义、函数说明及函数调用中均不带参数。主调函数和被调函数之间不进行参数传送。此类函数通常用来完成一组指定的功能,可以返回或不返回函数值。2)有参函数:也称为带参函数。在函数定义及函数说明时都有参数,称为形式参数(简称为形参)。在函数调用时也必须给出参数,称为实际参数(简称为实参)。进行函数调用时,主调函数将把实参的值传送给形参,供被调函数使用。3、函数的定义1)无参函数的定义形式类型标识符函数名(){声明部分语句
}其中类型标识符和函数名称为函数头。类型标识符指明了本函数的类型,函数的类型实际上是、函数返回值的类型。该类型标识符与前面介绍的各种说明符相同。函数名是由用户定义的标识符,函数名后有一个空括号,其中无参数,但括号不可少。{}中的内容称为函数体。在函数体中声明部分,是对函数体内部所用到的变量的类型说明。在很多情况下都不要求无参函数有返回值,此时函数类型符可以写为void。我们可以改写一个函数定义:voidHello(){printf("Hello,world\n");}
这里,只把main改为Hello作为函数名,其余不变。Hello函数是一个无参函数,当被其它函数调用时,输出Helloworld字符串。(2)有参函数定义的一般形式类型标识符函数名(形式参数表列){声明部分语句
}有参函数比无参函数多了一个内容,即形式参数表列。在形参表中给出的参数称为形式参数,它们可以是各种类型的变量,各参数之间用逗号间隔。在进行函数调用时,主调函数将赋予这些形式参数实际的值。形参既然是变量,必须在形参表中给出形参的类型说明。例如,定义一个函数,用于求两个数中的大数,可写为:
intmax(inta,intb){if(a>b)returna;elsereturnb;}第一行说明max函数是一个整型函数,其返回的函数值是一个整数。形参为a,b,均为整型量。a,b的具体值是由主调函数在调用时传送过来的。在{}中的函数体内,除形参外没有使用其它变量,因此只有语句而没有声明部分。在max函数体中的return语句是把a(或b)的值作为函数的值返回给主调函数。有返回值函数中至少应有一个return语句。在C程序中,一个函数的定义可以放在任意位置,既可放在主函数main之前,也可放在main之后。4、函数的参数—形参和实参函数的参数分为形参和实参两种。形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用。实参出现在主调函数中,进入被调函数后,实参变量也不能使用。形参和实参的功能是作数据传送。发生函数调用时,主调函数把实参的值传送给被调函数的形参从而实现主调函数向被调函数的数据传送。函数的形参和实参具有以下特点:(1)形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变量。(2)实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使实参获得确定值。(3)实参和形参在数量上,类型上,顺序上应严格一致,否则会发生类型不匹配”的错误。(4)函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。【例7.1】求两个数的最大值#include<string.h>#include<stdio.h>intmax(inta,intb){intk;if(a>b)k=a;elsek=b;returnk;}voidmain(){intmax(inta,intb);intx,y,z;printf("inputtwonumbers:\n");scanf("%d%d",&x,&y);z=max(x,y);printf("maxmum=%d\n",z);}代码贴士现在我们可以从函数定义、函数说明及函数调用的角度来分析整个程序,从中进一步了解函数的各种特点。程序的第1行至第5行为max函数定义。进入主函数后,因为准备调用max函数,故先对max函数进行说明。从第8行可以看出函数说明与函数定义中的函数头部分相同,但是末尾要加分号。程序第12行为调用max函数,并把x,y中的值传送给max的形参a,b。max函数执行的结果(a或b)将返回给变量z。最后由主函数输出z的值5、函数的返回值有的函数在被调用执行完后会向主调函数返回一个执行结果,这个结果就称为函数的返回值。函数的返回值用return语句来实现。它的语法格式为:return符合返回值类型的表达式;对于返回值,有两层意思。其一是指将表达式的值作为该函数运行的结果反馈给调用函数的地方。例如程序7.1中returnb就是把b的值作为max函数的运行结果反馈给主函数,即z=max(x,y)。其二是指结束该函数的运行,返回到调用该函数的地方,继续执行后面的语句。所以,如果执行了函数中的某一个return语句,那么之后的语句不会再被运行。如果返回值类型不是空类型,那么必须保证函数一定会返回一个值,否则会导致错误。比如下列函数定义就是有问题的,因为当a<b的时候,函数没有返回值。intm(inta,intb){if(a>=b)returna;}如果返回类型为空类型,则return语句的用法为:return;在返回空类型的函数中可以使用return语句,人为地停止函数的运行,也可以不使用return语句,使其运行完所有语句后自然停止。我们平时在返回空类型的主函数中不使用return语句就属于第二种情况。要注意,返回值和运行结果是两种概念。返回值是函数反馈给调用函数处的信息,运行结果是函数通过屏幕反馈给用户的信息。6、函数的调用(1)函数语句调用函数的语句调用时把函数作为一个语句,一般形式为:函数名(实际参数表)这种调用方式通常用于调用一个不带回返回值的函数。例如,引例中对print_star函数的调用就是语句调用。如果调用的函数无形式参数,则实参表可以没有,但函数名后面的小括号不能省去。下面是一个函数语句调用的例子。6、函数的调用(1)函数语句调用函数的语句调用时把函数作为一个语句,一般形式为:函数名(实际参数表)
这种调用方式通常用于调用一个不带回返回值的函数。例如,引例中对print_star函数的调用就是语句调用。如果调用的函数无形式参数,则实参表可以没有,但函数名后面的小括号不能省去。下面是一个函数语句调用的例子。【例7.2】求3个数的最大值#include<string.h>#include<stdio.h>voidmax(intn1,intn2,intn3){intm;if(n1>n2)m=n1;elsem=n2;if(m>n3)printf(“最大值为:%d”,m);elseprintf(“最大值为:%d”,n3);}voidmain(){inta,b,c;printf("输入三个数:\n");scanf("%d%d%d",&a,&b,&c);max(a,b,c);}代码贴士
程序的第1行至第12行为max函数定义。进入主函数后,程序第18行为调用max函数,并把a,b,c中的值传送给max的形参n1,n2,n3。max函数执行的结果就是程序执行的结果,在这里,被调用的函数max是作为一个语句执行的。(2)函数的表达式调用函数可以出现在表达式中,这种表达式称为函数表达式。其一般形式为:变量名=函数表达式这种调用方式用于调用带有返回值的函数,函数的返回值将参表达式的运算。例如例7.1中对max函数的调用就是函数表达式调用。【例7.3】例7.2改写,求3个数的最大值。#include<string.h>#include<stdio.h>intmax(intn1,intn2,n3){intm;if(n1>n2)m=n1;elsem=n2;if(m>n3)return(m);elsereturn(n3);}voidmain(){inta,b,c,z;printf("输入三个数:\n");scanf("%d%d%d",&a,&b,&c);z=max(a,b,c);}代码贴士
这个例子是对例7.2的改写,在第8行到11行给出了返回值,因此在第18行调用的时候,将返回值赋给了变量z。这是一个把函数作为表达式调用的例子。(3)函数声明【例7.3】调用函数求n!。#include<stdio.h>voidmain(){intn,t;intf(intnum);\\声明被调函数f()的类型为int型
printf("输入一个整数:\n");scanf("%d",&n);t=f(n);printf("%d!=%d\n",n,t);}intf(intnum){intx;inti;x=1;for(i=1;i<=num;i++)x*=i;return(x);}其一般形式为:类型说明符被调函数名(类型形参,类型形参…);或为:类型说明符被调函数名(类型,类型…);
主函数中的函数声明语句intf();该语句声明了f()函数的返回值类型为int型。在主调函数中对被调函数声明,意在告诉编译系统本函数中将要用到的某函数是什么类型,以便让编译系统作出相应的处理。代码贴士例7.3main函数中对f函数的说明为:longf(intnum);或写为:longf(int);C语言中又规定在以下几种情况时可以省去主调函数中对被调函数的函数说明。1)如果被调函数的返回值是整型或字符型时,可以不对被调函数作说明,而直接调用。这时系统将自动对被调函数返回值按整型处理。例8.2的主函数中未对函数s作说明而直接调用即属此种情形。2)当被调函数的函数定义出现在主调函数之前时,在主调函数中也可以不对被调函数再作说明而直接调用。例如例8.1中,函数max的定义放在main函数之前,因此可在main函数中省去对max函数的函数说明intmax(inta,intb)。3)如在所有函数定义之前,在函数外预先说明了各个函数的类型,则在以后的各主调函数中,可不再对被调函数作说明。例如:
charstr(inta);floatf(floatb);main(){……}charstr(inta){……}floatf(floatb){……}其中第一,二行对str函数和f函数预先作了说明。因此在以后各函数中无须对str和f函数再作说明就可直接调用。4)对库函数的调用不需要再作说明,但必须把该函数的头文件用include命令包含在源文件前部。(4)函数的嵌套调用
C语言中不允许作嵌套的函数定义。因此各函数之间是平行的,不存在上一级函数和下一级函数的问题。但是C语言允许在一个函数的定义中出现对另一个函数的调用。这样就出现了函数的嵌套用。即在被调函数中又调用其它函数。这与其它语言的子程序嵌套的情形是类似的。【例7.4】函数的嵌套调用。求两数之和。#include<stdio.h>voidmain(){inta,b;voidhead();head();printf(“请输入二数:”);scanf(“%d%d”,&a,&b);;printf(“a+b=%d”,a+b);}voidhead(){voidpstar();pstar();printf(“本程序的功能是求两个整数之和\n”);pstar();}voidpstar(){printf(“*******************************************\n”);}
程序中,main函数调用了head()函数,head()函数又调用了pstar()函数。pstar()函数执行完之后,返回到调用它的head()函数中,继续执行调用处后面的语句。同样,head()函数执行完之后,返回到调用它的main函数中。代码贴士7.1.3任务实施1、需求分析2、学生成绩管理系统结构设计3、C语言中函数的设计【例7.5】主函数设计:由于系统中菜单选项比较多,因此函数中可使用switch语句实现菜单选项调用各个功能函数。#include<stdio.h>#include<conio.h>#include<windows.h>#include<stdlib.h>voidStuCover();\\项目封面函数声明voidMainMenu();\\主菜单函数声明voidEditMenu();\\编辑子菜单函数声明voidDispMenu();\\显示子菜单函数声明voidCompMenu();\\计算子菜单函数声明voidSortMenu();\\排序子菜单函数声明voidOpen();\\打开文件子菜单函数声明voidSave();\\保存文件函数声明voidAdd();\\增加学生记录函数声明voidDel();\\删除学生记录函数声明voidModify();\\修改学生记录函数声明voidDispOne();\\查看一个记录函数声明voidDispAll();\\显示全部记录函数声明voidAsceSort();\\按升序排序函数声明voidDropSort();\\按降序排序函数声明voidNotElig();\\查找不及格记录函数声明voidCompSum();\\计算总成绩和平均成绩函数声明voidSearchMax();\\查找最高成绩函数声明voidSearchMin();\\查找最低成绩函数声明voidExplain();\\程序说明函数声明voidQuit(int);\\退出函数声明voidgotoxy(intx,inty);\\光标定位函数声明voidmain(){intchoose,editnum,dispnum,compnum,sortnum;\\定义5个输入变量
system(“cls”);StuCover();getch();while(1)\\外循环开始
{MainMenu();\\调用主菜单函数
printf(“\t\t请输入序号:”);scanf(“%d”,&choose);switch(choose)\\主菜单的switch开始
{case1:Open();break;case2:Save();break;case3:do\\内循环1开始
{EditMenu();\\调用编辑子菜单函数
printf(“\t\t请输入序号:”);scanf(“%d”,&editnum);switch(editnum)\\编辑子菜单switch开始
{case1:Add();break;
case2:Del();break;case3:Modify();break;case0:Quit(0);break;}\\编辑子菜单switch结束
}while(editnum!=0);\\内循环1结束
break;case4:do\\内循环2开始
{DispMenu();\\调用查看子菜单函数
printf(“\t\t请输入序号:”);scanf(“%d”,&dispnum);switch(dispnum)\\显示子菜单switch开始
{case1:DispOne();break;case2:DispAll();break;case3:do\\内循环3开始
{printf(“\t\t请输入序号:”);scanf(“%d”,&sortnum);switch(sortnum)\\排序子菜单switch开始
{case1:AsceSort();break;case2:DropSort();break;case0:Quit(0);break;}\\排序子菜单switch结束
}while(sortnum!=0);\\内循环3结束
break;case4:NotElig();break;
case‘0’:Quit(0);break;}\\显示子菜单switch结束
}while(dispnum!=0);\\内循环2结束
break;case5:do\\内循环4开始
{CompMenu();\\调用计算子菜单函数
printf(“\t\t请输入序号:”);scanf(“%d”,&compnum);switch(compnum)\\计算子菜单switch开始
{case1:CompSum();break;case2:SearchMax();break;case3:SearchMin();break;case0:Quit(0);break;}\\计算子菜单switch结束
}while(compnum!=0);\\内循环4结束
break;case6:Explain();break;\\程序说明
case0:Quit(1);break;}\\主菜单的switch结束
}\\外循环结束代码贴士
这是“班级成绩管理系统”的main()函数,程序先声明了在main()函数中要调用的所有函数,接着显示了主菜单,用switch语句分别对应主菜单中的选项,选择选项1调用Open()函数,选项2调用Save()函数,选项3调用调用编辑子菜单函数,选项4调用NotElig()函数,选项5调用调用计算子菜单函数,选项6调用Explain()函数,选项0调用Quit()函数。【例7.6】其它函数框架设计:根据函数的特性,设计出各个功能函数的框架,这些函数都使用了一个getch库函数,它在这里的作用是使屏幕发生暂停,当程序执行到此函数时发生暂停,等待用户输入一个任意字符后程序继续向下执行。各函数框架设计如下:voidOpen()\\打开文件函数{printf(“打开文件!\n”);getch();}voidSave()\\保存文件函数{printf(“保存文件!\n”);getch();}voidAdd()\\增加学生记录函数{printf(“增加记录!\n”);getch();}voidDel()\\删除学生记录函数{printf(“删除记录!\n”);getch();}voidModify()\\修改学生记录函数{printf(“修改记录!\n”);getch();}voidDispOne()\\查看一个记录函数{printf(“查看选定记录!\n”);getch();}voidDispAll()\\查看全部记录函数{
printf(“查看全部记录!\n”);getch();}voidAsceSort()\\按升序排列函数{printf(“按升序排序!\n”);getch();}voidDropSort()\\按降序排列函数{printf(“按降序排序!\n”);getch();}voidNotElig()\\显示不及格记录函数{printf(“显示不及格记录!\n”);getch();}voidCompSum()\\计算总成绩和平均成绩函数{printf(“计算总成绩和平均成绩!\n”);getch();}voidSearchMax()\\查找最高成绩函数{printf(“计算最高分!\n”);getch();}voidSearchMin()\\查找最低成绩函数{printf(“按计算最低分!\n”);getch();}
这是main()函数调用函数的框架,这些函数分散在各个章节之中,学习的时候把它们补充完整就可以了。代码贴士【例7.7】光标定位函数在VC++环境中是没有光标定位函数gotoxy的,为了方便系统格式输出,因此给出gotoxy函数代码如下:voidgotoxy(intx,inty)\\光标定位函数{COORDc;c.X=x-1;c.Y=y-1;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),c);}代码贴士
函数中的COORD和SetConsoleCursorPosition定义在wincon.h中,SetConsoleCursorPosition用于在相应的设备设置光标的位置,两个参数分别是设备句柄和光标位置结构。GetStdHandle定义在winbase.h上用于获得标准输入、输出、错误输出句柄,当参数标识为STD_OUTPUT_HANDLE时获得标准输出句柄。【例7.8】退出函数。函数代码设计如下:voidQuit(intflag)\\退出函数{if(flag==1){system(“cls”);printf(“\n\n\n\n\n\n\t\t\t操作结束,退出系统!”);getch();system(“cls”);exit(0);\\退出程序,返回到操作系统库函数
}elseif(flag==0)\\返回上级菜单
{system(“cls”);printf(“\n\n\n\n\n\n\t\t\t操作结束,返回上级菜单!”);getch();system(“cls”);}代码贴士
本函数是当函数传递过来的参数flag的值为1时,退出程序,返回到操作系统界面;当flag的值为0时,返回到上级菜单。【例7.9】程序说明函数函数代码设计如下:voidExplain()\\程序说明{system(“cls”);gotoxy(10,3);\\光标定位函数printf(“这是一个教学程序。它以开发班级学生成绩管理系统为主要项目,”);gotoxy(10,5);printf(“旨在通过简单学生成绩管理系统软件的开发,使读者了解并掌握用C语”);gotoxy(10,7);printf(“言开发程序的方法与技巧。”);gotoxy(10,9);printf(“该项目由15个任务来完成,将C语言基本知识与理论溶入到任务中,”);gotoxy(10,11);printf(“完成15个任务后就完成整个项目的设计。通过任务驱动和项目导向教学,”);gotoxy(10,13);printf(“最终实现教学目的,达到培养目标。”);gotoxy(10,15);printf(“该项目实施贯穿在整个教学过程中,它将重点与难点分散在各个任务”);gotoxy(10,17);printf(“中,达到循序渐进,逐个突破的目的,教学最后将安排一定的时间归纳汇”);gotoxy(10,19);printf(“总。”);getch();}代码贴士本函数使用自定义的光标定位函数gotoxy()和输出函数printf()对程序作出说明。7.1.4知识扩展1、函数的递归调用一个函数在它的函数体内调用它自身称为递归调用。这种函数称为递归函数。C语言允许函数的递归调用。在递归调用中,主调函数又是被调函数。执行递归函数将反复调用其自身,每调用一次就进入新的一层。例如有函数f如下:
intf(intx){inty;z=f(y);returnz;}
这个函数是一个递归函数。但是运行该函数将无休止地调用其自身,这当然是不正确的。为了防止递归调用无终止地进行,必须在函数内有终止递归调用的手段。常用的办法是加条件判断,满足某种条件后就不再作递归调用,然后逐层返回。下面举例说明递归调用的执行过程。【例7.10】用递归法计算n!程序分析:用递归法计算n!可用下述公式表示:1(n=0,1)n×(n-1)!(n>1)n!=求n!可以使用递归的方法,按公式可编程如下:#include<stdio.h>longff(intn){longf;if(n<0)printf("n<0,inputerror");elseif(n==0||n==1)f=1;elsef=ff(n-1)*n;return(f);}voidmain(){intn;longy;printf("\ninputainteagernumber:\n");scanf("%d",&n);y=ff(n);printf("%d!=%ld",n,y);}代码贴士
程序中给出的函数ff是一个递归函数。主函数调用ff后即进入函数ff执行,如果n<0,n==0或n=1时都将结束函数的执行,否则就递归调用ff函数自身。由于每次递归调用的实参为n-1,即把n-1的值赋予形参n,最后当n-1的值为1时再作递归调用,形参n的值也为1,将使递归终止。然后可逐层退回。2、数组作为函数参数
数组可以作为函数的参数使用,进行数据传送。数组用作函数参数有两种形式,一种是把数组元素(下标变量)作为实参使用;另一种是把数组名作为函数的形参和实参使用。(1)数组元素作函数实参数组元素就是下标变量,它与普通变量并无区别。因此它作为函数实参使用与普通变量是完全相同的,在发生函数调用时,把作为实参的数组元素的值传送给形参,实现单向的值传送。【例7.11】判别一个整数数组中各元素的值,若大于0则输出该值,若小于等于0则输出0值。#include<stdio.h>voidnzp(intv){if(v>0)printf("%d",v);elseprintf("%d",0);}voidmain(){inta[5],i;printf("input5numbers\n");for(i=0;i<5;i++){scanf("%d",&a[i]); nzp(a[i]);}}代码贴士
本程序中首先定义一个无返回值函数nzp,并说明其形参v为整型变量。在函数体中根据v值输出相应的结果。在main函数中用一个for语句输入数组各元素,每输入一个就以该元素作实参调用一次nzp函数,即把a[i]的值传送给形参v,供nzp函数使用。(2)数组名作为函数参数数组名作函数参数时,实参和形参都应为数组名,此时,实参和形参的传递为“地址传递”,所谓地址传递是指在调用函数时,系统并没有给形参数组分配新的存储空间,而只是将实参数组的首地址传递给形参数组,使形参数组与实参数组共用同一数组空间。3)在变量作函数参数时,所进行的值传送是单向。即只能从实参传向形参,不能从形参传回实参。形参的初值和实参相同,而形参的值发生改变后,实参并不变化,两者的终值是不同的。而当用数组名作函数参数时,情况则不同。由于实际上形参和实参为同一数组,因此当形参数组发生变化时,实参数组也随之变化。当然这种情况不能理解为发生了“双向”的值传递。但从实际情况来看,调用函数之后实参数组的值将由于形参数组值的变化而变化【例7.12】数组a中存放了一个学生5门课程的成绩,求平均成绩。#include<stdio.h>floataver(floata[5]){inti;floatav,s=a[0];for(i=1;i<5;i++)s=s+a[i];av=s/5;returnav;}voidmain(){floatsco[5],av;inti;printf("\ninput5scores:\n");for(i=0;i<5;i++)scanf("%f",&sco[i]);av=aver(sco);printf("averagescoreis%5.2f",av);}代码贴士
本程序首先定义了一个实型函数aver,有一个形参为实型数组a,长度为5。在函数aver中,把各元素值相加求出平均值,返回给主函数。主函数main中首先完成数组sco的输入,然后以sco作为实参调用aver函数,函数返回值送av,最后输出v值。从运行情况可以看出,程序实现了所要求的功能。【例7.13】题目同7.11例。改用数组名作函数参数。#include<stdio.h>voidnzp(inta[5]){inti;printf("\nvaluesofarrayaare:\n");for(i=0;i<5;i++){ if(a[i]<0)a[i]=0; printf("%d",a[i]);}}voidmain(){intb[5],i;printf("\ninput5numbers:\n");for(i=0;i<5;i++)scanf("%d",&b[i]);printf("initialvaluesofarraybare:\n");for(i=0;i<5;i++)printf("%d",b[i]);nzp(b);printf("\nlastvaluesofarraybare:\n");for(i=0;i<5;i++)printf("%d",b[i]);}代码贴士本程序中函数nzp的形参为整数组a,长度为5。主函数中实参数组b也为整型,长度也为5。在主函数中首先输入数组b的值,然后输出数组b的初始值。然后以数组名b为实参调用nzp函数。在nzp中,按要求把负值单元清0,并输出形参数组a的值。返回主函数之后,再次输出数组b的值。从运行结果可以看出,数组b的初值和终值是不同的,数组b的终值和数组a是相同的。这说明实参形参为同一数组,它们的值同时得以改变。在讨论函数的形参变量时曾经提到,存单元,调用结束立即释放。这一点表明形参变量只有在函数内才是有效的,离开该函数就不能再使用了。这种变量有效性的范围称变量的作用域。不仅对于形参变量,C语言中所有的量都有自己的作用域。变量说明的方式不同,其作用域也不同。C语言中的变量,按作用域范围可分为两种,即局部变量和全局变量。(1)局部变量(2)全局变量3、局部变量和全局变量(1)局部变量局部变量也称为内部变量。局部变量是在函数内作定义说明的。其作用域仅限于函数内,离开该函数后再使用这种变量是非法的。
在函数f1内定义了三个变量,a为形参,b,c为一般变量。在f1的范围内a,b,c有效,或者说a,b,c变量的作用域限于f1内。同理,x,y,z的作用域限于f2内。m,n的作用域限于main函数内。关于局部变量的作用域还要说明以下几点:
1)主函数中定义的变量也只能在主函数中使用,不能在其它函数中使用。同时,主函数中也不能使用其它函数中定义的变量。因为主函数也是一个函数,它与其它函数是平行关系。这一点是与其它语言不同的,应予以注意。
2)形参变量是属于被调函数的局部变量,实参变量是属于主调函数的局部变量。允许在不同的函数中使用相同的变量名,它们代表不同的对象,分配不同的单元,互不干扰,也不会发生混淆。如在前例中,形参和实参的变量名都为n,是完全允许的。
3)在复合语句中也可定义变量,其作用域只在复合语句范围内。【例7.14】复合语句变量作用域。#include<stdio.h>voidmain(){inti=2,j=3,k;k=i+j;{intk=8;printf("%d\n",k);}printf("%d\n",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。但在一个函数之前定义的全局变量,在该函数内使用可不再加以说明。(2)全局变量【例7.15】外部变量与局部变量同名。#include<stdio.h>inta=3,b=5;\\a,b为外部变量max(inta,intb)\\a,b为外部变量{intc;c=a>b?a:b;return(c);}main(){inta=8;printf("%d\n",m
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026副主任医师副高-中医儿科学(副高)074历年题库含答案详解
- 《复活(节选)》课件
- 创意语文试题及答案
- 小学英语Storytime教案
- 小学音乐花城版二年级下册歌曲《我们的小乐队》教案
- 2026酒店REITs市场发展现状及资产定价模型研究
- 五年级品社下册《圆明园在哭泣》教案 浙教版
- 拒绝霸凌快乐校园(教学设计)初三下学期教育主题班会
- 2026中国乳制品包装形式创新与货架期延长技术报告
- 2026全国同等学力申硕考试(工商管理)历年参考题库含答案详解
- 少年宫-中国象棋教案集
- DB13(J)-T 8634-2025 低碳混凝土应用技术标准
- 2026苏教版五年级数学上册第一单元第2课《图形的旋转》课件
- 贵州省劳动合同书
- JJG 1189.1-2026 测量用互感器检定规程 第1部分:标准电流互感器
- 申请2026年新产品试用函(6篇)范文
- JJG 1189.8-2026测量用互感器检定规程第8部分:宽量程电流互感器
- 小微企业安全生产管理台账(参考)
- 综治中心入驻单位工作制度
- 2026年上海围棋定级考测试题及答案
- 精益管理培训教学课件
评论
0/150
提交评论