版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第六章函数本章教学目标(1)掌握函数的结构,函数的类型和返回值;(2)掌握函数的调用方法;(3)掌握函数参数传递的类型;(4)掌握函数的嵌套机制和递归机制。16.1显示学生成绩管理系统功能菜单
6.1.1问题描述************StudentsScoreManageSystem****************************************************************MenuItems*****************************************************1-------InputStudentsInformation**2-------ModifyStudentsInformation**3-------QueryStudentsInformation**4-------StatisticStudentsInformation**5-------DisplayStudentsInformation**6-------ExitSystem*****************************************************PleaseSelectanOption(1-6):
程序运行界面26.1.2问题抽象显示菜单选项提示用户进行选择用户进行输入根据输入的选项执行相应的模块是否在给定范围中?YN
菜单程序功能思路分析从问题空间对进行分析3
可以自定义一个菜单函数,取名DisplayMenu(),从整体来看,应该是一个大循环结构,内嵌一个小循环,小循环的功能是实现用户的正确输入,代码段(P87)。
从平台空间对上面问题进行解析46.1.3映射编码#include<stdio.h>#include<stdlib.h>voidDisplayMenu(){charMenuItem;while(1){printf("\n");printf("************StudentsScoreManageSystem*************\n");printf("***************************************************\n");printf("MenuItems\n");printf("****************************************************\n");printf("*1-------InputStudentsInformation*\n");printf("*2-------ModifyStudentsInformation*\n");printf("*3-------QueryStudentsInformation*\n");printf("*4-------StatisticStudentsInformation*\n");printf("*5-------DisplayStudentsInformation*\n");printf("*6-------ExitSystem*\n");printf("****************************************************\n");
5do{printf("PleaseSelectanOption(1-6):\n");
fflush(stdin);/*ClearBuffer*/scanf("%c",&MenuItem);getchar();}while(MenuItem<'1'||MenuItem>'6');switch(MenuItem){case'1':printf("WelcomeInputStudentsInformationInterface\n");
/*Addfunction*/printf("PressAnyKeyContinue……….\n");getchar();break;case'2':printf("WelcomeModifyStudentsInformationInterface\n");
/*Addfunction*/printf("PressAnyKeyContinue……….\n");getchar();break;
6case'3':printf("WelcomeQueryStudentsInformationInterface\n");
/*Addfunction*/printf("PressAnyKeyContinue……….\n");getchar();break;case'4':printf("WelcomeStatisticStudentsInformationInterface\n");
/*Addfunction*/printf("PressAnyKeyContinue……….\n");getchar();break;case'5':printf("WelcomeDisplayStudentsInformationInterface\n");
/*Addfunction*/printf("PressAnyKeyContinue……….\n");getchar();break;case'6':printf("ThanksyouUsethisSystem\n");printf("PressAnyKeyExitSystem\n");getchar();exit(0);}}}7voidmain(){DisplayMenu();}运行结果:************StudentsScoreManageSystem****************************************************************MenuItems*****************************************************1-------InputStudentsInformation**2-------ModifyStudentsInformation**3-------QueryStudentsInformation**4-------StatisticStudentsInformation**5-------DisplayStudentsInformation**6-------ExitSystem*****************************************************PleaseSelectanOption(1-6):1WelcomeInputStudentsInformationInterfacePressAnyKeyContinue……….86.1.4编码分析通过上面实例,要熟练掌握函数的定义形式。理解函数调用的过程。(3)#include<stdlib.h>标准库函数头文件,程序中退出程序的exit(0)函数需要它。(4)stdin是系统变量,表示标准输入设备变量。96.2函数
6.2.1函数的定义函数的分类从函数定义的角度看,函数可分为库函数和用户定义函数两种;从函数有无返回值的角度看,可以分“无返回值函数”和“有返回值函数”两种;从主调函数和被调函数之间数据传送的角度看又可分为无参函数和有参函数两种。
10①无参函数的定义形式 类型标识符函数名() {
局部变量声明部分 语句组
[return表达式;] }
11②有参函数的定义形式第一种形式是:函数返回值类型函数名(类型参数1,类型参数2,……) {
局部变量声明部分 语句组
[return表达式;] }
第二种形式是:
函数返回值类型函数名(参数1,参数2,……)类型参数1,类型参数2,……/*形参定义*/ {
局部变量声明部分 语句组
[return表达式;] }
12注意:(1)在一个函数的函数体内,不能再定义另一个函数,即不能嵌套定义。但是在一个的体内可以调用另一个函数,即函数可以相互调用。(2)如果函数自己调用自己,这种函数调用称为函数的递归调用。(3)main函数是主函数,它可以调用其他函数,而不允许被其他函数调用。(4)一个C源程序必须有、也只能有一个主函数main。136.2.2函数的调用(1)函数的调用形式
函数名([参数列表])
函数的调用主要是指出函数名,有参数的时候必须指出参数。这里的参数称为实在参数,简称实参。定义函数时括弧()中的参数称为形式参数,简称形参。在C语言中,函数的参数分为形参和实参两种。形参出现在函数定义中,实参出现在主调函数中,形参和实参的功能是作数据传送。14
函数的形参和实参具有以下特点:(1)形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。(2)在进行函数调用时,应预先用赋值、输入等办法使实参获得确定值。(3)实参和形参在数量上、类型上、顺序上应严格一致,否则会发生类型不匹配的错误。
15有以下三种情况,使用函数的调用格式:第一种:以语句的形式调用函数。这种情况一般用于调用无返回值的函数。形式为:
函数名(参数列表);
16第二种情况:以表达式的形式调用函数。这种情况一般用于调用有返回值的函数。通过调用函数的表达式,接收被调用函数的返回值。形式为:
变量名=函数名([实参列表]);17例如:输入两个整数,输出其中的最大值。#include<stdio.h>intmax(intx,inty){intz;if(x>y)z=x;elsez=y;returnz;}运行结果为:8878Max=88voidmain(){inta,b,Max;scanf("%d%d",&a,&b);
Max=max(a,b);
/*使用表达式方式调用函数*/printf("Max=%d\n",Max);}18第三种情况:调用函数值为函数的参数。这种形也一般情况使用在有返回值的函数调用中。例如:输入三个整型数据,输出其中的最大数。#include<stdio.h>intmax(intx,inty){intz;if(x>y)z=x;elsez=y;returnz;}voidmain(){inta,b,c,Max;scanf("%d%d%d",&a,&b,&c);Max=max(max(a,b),c);/*把函数作为函数的参数形式调用函数*/printf("Max=%d\n",Max);}运行结果为:687875Max=7819(2)函数的声明
一般情况下,如果被调用函数的定义出现在主调函数之后,应该在主调函数中添加对被调函数的声明。函数声明的作用是告诉编译程序,被调用的函数函数的返回值类型是什么,函数名是什么,函数带了几个什么类型的参数,至于形式参数的名字是什么,编译系统并不关心。20C语言又规定在以下几种情况时可以省去主调函数中对被调函数的函数声明,直接调用。(1)如果被调函数的返回值是整型或字符型时。这时系统将自动对被调函数返回值按整型处理。(2)当被调函数的函数定义出现在主调函数之前时。(3)如在所有函数定义之前,在函数外预先说明了各个函数的类型。(4)对库函数的调用不需要再作声明,但必须把该函数的头文件用include命令包含在源文件前部。216.2.3函数参数的传递
参数传递称为“实形结合”,即实参向形参传递信息,使形参具有确切的含义(即具有对应的存储空间和初值)。这种参数传递又分为两种不同的方式,一种是按值传递,另一种是地址传递。22(1)按值传递
以按值传递方式进行参数传递的过程为:首先计算出实参表达式的值,接着给对应的形参变量分配一个存储空间,该空间的大小等于该形参类型的长度,然后把已求出的实参表达式的值复制到为形参变量分配的存储空间中,成为形参变量的初值,供被调用函数执行时使用。这种传递是把实参表达式的值传送给对应的形参变量,故称这种传递方式为“按值传递”。这种方式被调用函数本身不对实参进行操作,也就是说,即使形参的值在函数中发生了变化,实参的值也完全不会受到影响,仍为调用前的值。23例如:有人为了实现两个数据的交换,编写了下面的程序,分析程序的结果:#include<stdio.h>voidmain(){voidswap(int,int);inta=3,b=4;printf("a=%d,b=%d\n",a,b);swap(a,b);printf("a=%d,b=%d\n",a,b);}voidswap(intx,inty){intt;t=x;x=y;y=t;}
注意:在C语言中,当实参是常量或者普通变量时,参数传递的形式都是按值传递。24(2)地址传递
如果在函数定义时将形参的类型说明成数组名或者指针变量,对这样的函数进行调用时就需要指定地址值形式的实参。这时的参数传递方式即为地址传递方式。这种地址传递与上述的按值传递不同,它把实参的存储地址传送给对应的形参,从而使得形参指针和实参指针指向同一个地址。因此,被调用函数中对形参指针所指向的地址中内容的任何改变都会影响到实参。25实例:编写一个程序,要求定义一个一维数组score,存放10个学生的成绩,首先通过键盘输入学生成绩,再将存放在数组中的学生成绩输出,接着对存放在数组中的学生成绩从低分到高分排序,最后把排序后的学生成绩输出。每个过程都编写一个函数完成,在main函数中调用。26
问题分析:依据题意,我们可以建立如下的一个main函数,其中包括:首先定义score数组,再给score数组中输入成绩数据,调用input函数,接着将排序前的数据输出,调用output函数;再对score中的数据进行排序,调用sort函数,最后把排序后score数组中的数据输出,调用output函数。27从问题空间的角度来处理:主函数main可以这样编写:voidmain(){
定义一个存放10个学生的一维数组;输入10个成绩数据,并存放在一维数组中;输出排序前的10个成绩数据;对10个成绩数据进行排序;输出排序后的10个成绩数据;}28从平台空间角度来看:可以转化为下面的C语言程序:voidmain(){intscore[10];
input(score,10);/*输入10个成绩数据*/printf("BeforeSortData:\n");
output(score,10);/*输出10个成绩数据*/
sort(score,10);/*对10个成绩数据进行排序*/printf("\nAfterSortData:\n");
output(score,10);/*输出10个成绩数据*/}29(1)编写input(score,10)函数注意到主函数中调用的input(score,10)函数没有返回值,有两个实参,第一个是一个数组名,即就是数组中第一个元素的地址,第二个是一个普通变量,那么在定义该函数时,形参的形式应该与其相同,因此input函数应该这样编写:voidinput(inta[],intn){inti;for(i=0;i<n;i++)/*从键盘输入数据给数组赋值*/scanf("%d",&a[i]);}30(2)编写output(score,10)函数分析与输入类似,output函数应该这样编写:voidoutput(inta[],intn){inti;for(i=0;i<n;i++)/*score中数据输出*/printf("%d",a[i]);}313)编写sort(score,10)函数该函数的功能就是把实参中传递过来的数组按升序进行排序,排序算法我们在一维数组中已经讲解,现在直接可以使用。因此sort函数应该这样编写:voidsort(inta[],intn){inti,j,temp;for(i=0;i<n-1;i++)/*冒泡排序*/for(j=0;j<n-1-i;j++)if(a[j]>a[j+1]){temp=a[j];/*交换a[j]与a[j+1]*/a[j]=a[j+1];a[j+1]=temp;}}32完整程序如下:#include<stdio.h>voidmain(){voidinput(inta[],intn);/*被调函数的声明*/voidoutput(inta[],intn);voidsort(inta[],intn);intscore[10];input(score,10);/*输入10个成绩数据*/printf("BeforeSortData:\n");output(score,10);/*输出10个成绩数据*/sort(score,10);/*对10个成绩数据进行排序*/printf("\nAfterSortData:\n");output(score,10);/*输出10个成绩数据*/}33voidinput(inta[],intn){inti;for(i=0;i<n;i++)/*从键盘输入数据给数组赋值*/scanf("%d",&a[i]);}voidoutput(inta[],intn){inti;for(i=0;i<n;i++)/*score中数据输出*/printf("%d",a[i]);}voidsort(inta[],intn){inti,j,temp;for(i=0;i<n-1;i++)/*冒泡排序*/for(j=0;j<n-1-i;j++)if(a[j]>a[j+1]){temp=a[j];/*交换a[j]与a[j+1]*/a[j]=a[j+1];a[j+1]=temp;}}346.2.4函数的返回值
在C语言中,return语句用于返回调用它的函数,同时向被调者返回函数的结果,即函数返回值。return语句的使用形式:
return(表达式);
说明:(1)当函数的返回值类型为void时,小括弧连同其内的内容都可以省略。这时return语句只起返回到主调函数中的作用,不返回任何值。(2)当函数有返回值时,return语句除了返回主调函数外,将表达式的值送回给主调它的函数,小括弧可以省略。356.2.5函数的嵌套调用
函数的嵌套调用是指在调用一个函数的过程中,被调函数可以调用另一个函数。
main(){…………f1();…………}f1(){…………f2();…………}f2(){…………………………}①执行②调用③执行④调用⑤执行⑥返回⑦执行⑧返回⑨执行函数嵌套调用与返回过程36实例:下面我们把6.1节中的程序修改为使用函数嵌套调用的结构。
376.2.6函数的递归调用
实例:键盘输入一个正整数N,计算N!。问题分析:对于计算N阶乘的问题,对于不同的解决思路就会有不同的解决问题的方法,因此对于这个问题,可以建立下面两个的数学模型:数学模型一:数学模型二:38
针对模型一,我们发现是一个累计求乘积的问题,那么就可以编写这样一个函数:
longfact(intn){longp=1;inti;for(i=1;i<=n;i++)p=p*i;returnp;}39
针对模型二,我们发现是一个递归调用的问题,因为,想要求N!,先计算出(N-1)!后与N相乘,依次类推,最后1!=1,再回推,可以算出2!=1!*2,依次回推计算出N!,那么我们可以编写这样一个函数:
longfact(intn){longp=1;if(n==0||==1)p=1;elsep=n*fact(n-1);returnp;}一个函数直接或间接地调用自身,称为函数的递归调用。40fac(5)5*fac(4)4*fac(3)3*fac(2)2*fac(1)12*13*2*14*3*2*15*4*3*2*1120递归41下面给出完成程序:#include<stdio.h>longfact(intn){longp=1;if(n==0||n==1)/*递归结束条件*/ p=1;elsep=n*fact(n-1);returnp;}voidmain(){longx;/*定义变量*/intn;scanf("%d",&n);/*输入变量*/
x=fact(n);/*使用自定义函数计算*/printf("%d!=%ld",n,x);/*输出结果*/}42小结:使用函数的优点:(1)可读性好;(2)易于查错和修改;(3)便于分工编写,分阶段调试;(4)各个函数之间接口清晰,便于相互间交换信息和使用;(5)节省程序代码和存储空间;(6)减少用户总的工作量;(7)成为实现结构程序设计思想的重要工具;(8)扩充语言和计算机的原设计能力;(9)便于验证程序正确性。436.3变量的作用域6.3.1变量的存储类型变量的存储类型存储类型标识符含义auto自动变量static静态变量extern外部变量register寄存器变量存储类型标识符
数据类型变量名;44一、auto实例:键盘输入两个整数,输出最大数和最小数#include<stdio.h>voidmain(){autointmin,max;/*定义自动变量,等价intmin,max;*/scanf(“%d%d”,&min,&max);if(min>max){autointtemp;/*定义自动变量,等价inttemp;*/temp=min;min=max;max=temp;}printf(“max=%d,min=%d”,max,min);}
45程序分析:(1)上面程序定义变量时,有两个位置,第一个位置是在函数内定义的变量,第二个位置是在if语句的组合语句块内定义。这样定义变量的存储类型都是自动类型。当把变量定义为自动类型时,关键词auto可以省略。(2)自动变量语句动态存储类,系统在函数运行时,自动为其动态分配内存空间,离开它的作用范围时,系统回收它的存储空间,变量的值也就不存在了。因此自动变量的生存期就是程序进入其作用域期间。(3)自动变量在初始化之前,或者没有赋初始值之前,其值是不确定的。46例如:
#include<stdio.h>voidmain(){inti,sum;/*定义自动变量*/for(i=1;i<=100;i++)/*累计求和*/sum+=i;printf(“sum=%d”,sum);/*输出结果*/}运行结果:sum=-85898841047程序分析:上面程序是求自然数1+2+3+……+100的和,大家都知道结果应该是5050,可是程序的运行结果并非如此,分析原因就是,累计和的自动变量sum没有赋初值。只要在定义sum并初始化为0,即可。(4)变量出现的有效区域称为变量的作用域。在函数体内或者复合语句块内定义的变量称为局部变量。在函数体内定义的变量,从定义位置开始起,到本函数结束有效,在复合语句块内定义的局部变量,从定义位置起,到复合语句结束有效,例如48#include<stdio.h>voidmain(){autointmin,max;/*定义自动变量,等价intmin,max;*/scanf(“%d%d”,&min,&max);if(min>max){
autointtemp;/*定义自动变量,等价inttemp;*/
temp=min;min=max;max=temp;}printf(“temp=%d”,temp);/*错误,不能访问temp变量*/printf(“max=%d,min=%d”,max,min);}
49二、static
实例:分析下面程序的运行结果
#include<stdio.h>voidfun(){intx=0;x=x+1;printf(“%d”,x);}voidmain(){inti;for(i=1;i<=3;i++)fun();}
50如果把上面程序改变为:
#include<stdio.h>voidfun(){
staticintx=0;x=x+1;printf(“%d”,x);}voidmain(){inti;for(i=1;i<=3;i++)fun();}51程序分析:两个程序仅仅一个关键词之差,结果完全不同,是因为fun函数中的变量被定义为静态局部变量,第一次调用时,输出其值为1,当出了x变量的作用域后,系统没有回收它的存储空间,因此空间的值也存在,当第二次调用是,系统没有重新分配空间,因此在原来基础上做x=x+1,因此x值变为2,被输出,第三次,同样,在原来基础上加1,x值变为3,被输出。
52
使用静态变量时应该注意以下几点:(1)动态的局部变量的值在其作用域范围内有效,出了作用域,系统将回收给其分配的内存空间。如果希望一个局部变量的值,当它离开其作用域范围后不消失,并保持原来的值,它占用的存储空间也不释放,因此空间在,变量的值也就在。这种变量在C语言中,用关键词static来定义,称为静态变量。(2)定义的一般形式:
static数据类型变量名;(3)整型静态变量在初始化之前,或者没有赋初始值之前,其值是0。
53上面程序写成:#include<stdio.h>voidfun(){staticintx;/*定义静态变量*/x=0;x=x+1;printf(“%d”,x);}voidmain(){inti;/*定义变量*/for(i=1;i<=3;i++)/*循环调用fun()函数*/fun();}
54三、register寄存器变量在程序运行中,存取变量要消耗一定的时间开销,如果一个变量使用非常频繁,为了节省时间开销,可以使用寄存器变量速度快的特点,将变量存放在CPU的寄存器中,可以提高程序的运行效率。使用寄存器变量时应该注意以下几点:(1)只有函数的形参或者局部变量才可以定义为寄存器变量,不能用于全局变量,局部静态变量不能定义为寄存器变量。(2)寄存器变量占有的是CPU的高速寄存器单元,不占用内存存储空间,因此不宜定义的寄存器变量过多。
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 课题申报参考:金融高质量发展视角下的区域广义协调发展机理与政策统筹研究
- 课题申报参考:减碳责任量化与多产品企业投资绿色转型:内在机理、效应评估与策略选择
- 2025版委托担保合同范本:供应链金融合作风险控制协议3篇
- 二零二五版国际物流保险合同订立与理赔3篇
- 2025年伊犁货车从业资格证考什么
- 2025年度个人自建别墅地基买卖合同8篇
- 二零二五年度混凝土工程进度协调协议2篇
- 二零二五版木材加工企业环保责任承诺合同4篇
- 2025年建筑钢材批量供应及售后保障合同3篇
- 二零二五年度夫妻离婚后子女医疗费用分担协议2篇
- 2025-2030年中国陶瓷电容器行业运营状况与发展前景分析报告
- 二零二五年仓储配送中心物业管理与优化升级合同3篇
- 2025届厦门高三1月质检期末联考数学答案
- 音乐作品录制许可
- 江苏省无锡市2023-2024学年高三上学期期终教学质量调研测试语文试题(解析版)
- 拉萨市2025届高三第一次联考(一模)英语试卷(含答案解析)
- 开题报告:AIGC背景下大学英语教学设计重构研究
- 师德标兵先进事迹材料师德标兵个人主要事迹
- 连锁商务酒店述职报告
- 2024年山东省烟台市初中学业水平考试地理试卷含答案
- 《实践论》(原文)毛泽东
评论
0/150
提交评论