400 likes | 567 Views
高级语言. (第十五讲). 我们的黑匣子. 设置密码. 绍兴文理学院. 计算机系计算机应用教研室. 第七章 函 数 (1). 一、教学目的: 掌握函数定义的形式;掌握函数形参、实参和函数值的概念和使用;掌握函数调用的方法;利用设计自定义函数进行编程;算法和程序设计能力的训练。. 二、教学重点: 函数定义的形式;函数形参、实参和函数值的概念和使用;函数调用的方法;设计自定义的函数进行编程;算法和程序设计能力的训练。. 三、教学难点: 函数形参、实参的概念和使用;函数调用的方法;设计自定义的函数进行编程;算法和程序设计。 四、教学过程:. 设置密码
E N D
高级语言 (第十五讲) 我们的黑匣子 设置密码 绍兴文理学院 计算机系计算机应用教研室
第七章 函 数(1) 一、教学目的:掌握函数定义的形式;掌握函数形参、实参和函数值的概念和使用;掌握函数调用的方法;利用设计自定义函数进行编程;算法和程序设计能力的训练。 二、教学重点:函数定义的形式;函数形参、实参和函数值的概念和使用;函数调用的方法;设计自定义的函数进行编程;算法和程序设计能力的训练。 三、教学难点:函数形参、实参的概念和使用;函数调用的方法;设计自定义的函数进行编程;算法和程序设计。 四、教学过程:
设置密码 Problem Description 密码很重要。Sg想你帮他判断一下他设置的密码是否可行,他规定密码必须满足的要求如下:(1)至少有1个元音字母(a,e,i,o,u) ;(2)不能有3个元音连在一起;(3)不能有3个非元音连在一起;(4)除了ee和oo之外,不能有2个相同字母连在一起。 Input测试数据有多组,每组测试输入一个只包含小写字符的字符串(长度小于50),一直处理到输入end为止,end不用处理。 Output对于每组测试,判断密码是否可行,按Sample Output输出。 —模块化程序设计 ? TKS 3 10:31
main a b c d e f g h h I e g TKS 4 §7.1函数的定义 §7.1.0 概述 1、概述 (1) 程序设计方法:自上而下,逐步细化。 (2) 将一个大程序分成几个子程序模块,每个子程序的作用是由函数完成(自定义函数)。是功能单一、结构清晰、接口简单、易于理解的小程序。 (3) 一个C++程序可由一个主函数和若干个函数构成。由主函数调用其他函数 ,其他函数可以互相任意(多次)调用。 (4) 程序模块结构及其函数调用示意图如右。 (5) 将常用功能做成标准模块(标准函数)放在函数库中供其他程序调用。 如果把编程比做制造一台机器,函数就好比其零部件。 10:31
可将这些“零部件”单独设计、调试、测试好,用时拿出来装配,再总体调试。可将这些“零部件”单独设计、调试、测试好,用时拿出来装配,再总体调试。 TKS 5 零部件 (函数) * * * * * * * * * How do you do! * * * * * * * * * 这些“零部件”可以是自己设计制造/别人设计制造/现在的标准产品。而且,许多“零部件”我们可以只知道需向它提供什么(如控制信号),它能产生什么(如速度/动力),并不需要了解它是如何工作、如何设计制造的——所谓“黑盒子”。 速度/动力 (返回结果) 控制信号 (输入参数) 例 8.1 在屏幕上显示: int main() {cout<<"* * * * * * * * *"<<endl; cout<<"How do you do!"<<endl; cout<<"* * * * * * * * *"<<endl; return 1; } ★ 用函数模块设计 10:31
printstar() TKS 6 printstar() {cout<<"* * * * * * * * *“<<endl; } main() {printstar(); print_mess(); printstar(); } print_mess() print_mess() {cout<<“ How do you do!"<<endl; } C+15_1 10:31
补充例1 一个儿童算术能力测试软件 显示软件封面 检查密码 产生题目 接受回答 评判计分 显示结果 是否继续练习 告别词 TKS 7 main() {char ans=‘y’; clrscr(); cover();/*调用软件封面显示函数*/ password();/*调用密码检查函数*/ while(ans ==’y’|| ans ==’Y’) {question();/*调用产生题目函数*/ answers();/*调用接受回答函数*/ marks();/*调用评分函数*/ results();/*调用结果显示函数*/ printf(“是否继续练习?(Y/N)\n”); ans=getch(); } printf(“谢谢使用,再见!”); } 10:31
◆一个C++程序可由一个主函数和若干个函数构成。由主函数调用其他函数,其他函数可以互相任意(多次)调用。 ◆一个C++程序可由一个主函数和若干个函数构成。由主函数调用其他函数,其他函数可以互相任意(多次)调用。 操 作 系 统 TKS 8 10:31
◆ 由函数构成的自顶向下的层次结构 TKS 9 10:31
补充例2 一个高等院校的信息管理系统的程序结构 TKS 10 10:31
补充例2一个高等院校的信息管理系统的菜单界面补充例2一个高等院校的信息管理系统的菜单界面 TKS 11 大学信息管理系统 1. 办公室管理 5. 财务管理 2. 教务管理 6. 图书管理 3. 科研管理 7. 设备管理 4. 人事管理 8. 后勤管理 0. 退出系统 请你在上述功能中选择(0—8): 10:31
补充例2 一个高等院校的信息管理系统的菜单界面 TKS 12 #include <iostream> using namespace std; int main(void) {char choice; printf("=====大学信息管理系统=====\n"); printf("------------------------------------\n"); printf("1. 办公室管理 5. 财务管理\n"); printf("2. 教务管理 6. 图书管理\n"); printf("3. 科研管理 7. 设备管理\n"); printf("4. 人事管理 8. 后勤管理\n"); printf("0. 退出系统\n"); printf("------------------------------------\n"); printf("请您在上述功能中选择(O--8):"); 10:31
do {choice=getche(); switch(choice) {case '1': funct1(); break; case '2': funct2(); break; case '3': funct3(); break; case '4': funct4(); break; case '5': funct5(); break; case '6': funct6(); break; case '7': funct7(); break; case '8': funct8(); break; case '0': funct0(); } }while(1); return 0; } 补充例2 一个高等院校的信息管理系统的菜单界面C+15_0 TKS 13 10:31
2、说明 TKS 14 (1) 一个C++程序由一个或多个源(程序)文件组成——可分别编写、编译和调试。 (2) 一个源文件由一个或多个函数组成,可为多个C++程序公用。 (3) C++语言是以源文件为单位而不以函数为单位进行编译的。 (4) C++程序执行总是从main函数开始,调用其它函数后总是回到main函数,最后在 main函数中结束整个程序的运行。 main函数是系统定义的。 (5) 所有函数都是平行的、互相独立的,即在一个函数内只能调用其他函数,不能再定义一个函数(嵌套定义)。 (6) 一个函数可以调用其他函数或其本身,但任何函数均不可调用main函数。 (7) 从函数定义的角度看,函数可分为库函数和用户定义函数两种。 10:31
(8) C++语言的函数兼有其它语言中的函数和过程两种功能,从这个角度看,又可把函数分为有返回值函数和无返回值函数两种。 TKS 15 (9) 从主调函数和被调函数之间数据传送的角度看又可分为无参函数和有参函数两种。 (10) C++语言提供了极为丰富的库函数。按功能可分为若干类。 §7.1.1 函数定义格式 [<有效范围>] <类型名> <函数名>([类型 参数名,……, 类型 参数名]) { [变量定义和函数说明部分] [语句] } <有效范围>由所使用的保留字extern或static决定。若使用extern,则称为全局函数或外部函数,它在整个程序的所有文件中都有效;若使用static则称为局部函数或静态函数,它只在所属的 10:31
程序文件中有效。若<有效范围>被省略,则默认是使用extern。程序文件中有效。若<有效范围>被省略,则默认是使用extern。 TKS 16 如: staticdoublepower(intn,floatx) 有效范围 函数名 参数名 类型名 参数类型 §7.1.2 函数定义格式举例 1、无参函数的定义形式 类型名 函数名() { 声明部分 语句 } 10:31
【注意】 TKS 17 每个函数之前可以有自己的编译预处理命令组。 {}中的内容称为函数体。在函数体中声明部分,是对函数体内部所用到的变量的类型说明。 2、有参函数定义的一般形式 类型名 函数名(形式参数表列) { 声明部分 语句 } 在形参表中给出的参数称为形式参数,它们可以是各种类型的变量,各参数之间用逗号间隔。在进行函数调用时,主调函数将赋予这些形式参数实际的值。形参既然是变量,必须在形参表中给出形参的类型说明。 10:31
例如,定义一个函数,用于求两个数中的大数,可写为: TKS 18 int max(int a, int b) { if (a>b) return a; else return b; } 3、可以有“空函数” 类型名 函数名() {} 一般作为以后扩充函数功能时的补充上。 §7.1.3 有关函数定义的几点说明 1、函数原型语句 在一个函数定义中,函数体之前的所有部分称为函数头,它给出了函数名、返回类型、每个参数的次序和类型等函数原型信息。 一个函数必须先定义或声明而后才能被调用。一个函数的声明 10:31
是通过一条函数原型语句实现的。 TKS 19 如: int max2(int a,int b); 2、常量形参 常量形参是指只允许函数体访问该参数,而不允许修改它的值,这时应把该形参说明为常量,只要在形参说明前面加上const保留字即可。如: int max2(const int a,const int b) { if(a>b) return a; else return b; } 常量形参示例 C+15_2 10:31
3、默认值参数 TKS 20 在一个函数中,可根据需要对参数表末尾的一个或连续若干个参数给出默认值,当调用这个函数时,若实参表中没有给出对应的实参,则形参将采用这个默认值。如: void fun(int a,int b=3) { cout<<a+b<<endl; } int main() {int x,y; cin>>x>>y; fun(x,y); fun(x); return 1; } 默认值参数示例 C+15_3 10:31
4、数组参数 TKS 21 在函数定义中的每个数组参数实际上是数组的首地址(指向数组存储第一个元素的指针)参数。 一维数组参数的说明:<数据类型> <数组名>[] 如: void sort(int n,int a[]) 二维数组参数的说明:<数据类型> <数组名>[][第2维尺寸] 如: void sort(int n,int stu[][3]) 5、函数类型 即函数返回值类型。对于类型为非void的函数,函数体中至少必须有一条return语句,且每条return语句必须带有一个表达式,当执行到一条return语句时,将计算出其表达式的值,结束整个函数的调用过程,把这个值作为所求的函数值带回到调用位置; 对于类型为void的函数,不需要返回任何值,可以没有return语句,也可有不带表达式的return语句。 10:31
§7.2函数调用 如: int max2(int x,int y) {int z; z=x>y?x:y; return(z); } int main() {int a,b,c; cin>>a>>b; c=max2(a,b); printf(Max is %d”,c); return 1; } TKS 22 §7.2.1调用格式 1、函数调用的一般形式 函数名(实际参数表); 对无参函数调用时则无实际参数表。实际参数表中的参数可以是常数,变量或其它构造类型数据及表达式。各实参之间用逗号分隔函数和变量一样,在其主调函数中也必须“先说明,后使用”。 注意关系: 函数定义----制造函数 函数使用----说明(准备使用)和 调用(使用函数) 10:31
2、函数调用的方式 TKS 23 (1) 函数语句: 函数的调用作为一个语句。 如:max2(x,y); (2) 函数表达式: 函数作为表达式中的一项出现在表达式中,以函数返回值参与表达式的运算。这种方式要求函数是有返回值的。 如:c=max2(x,y); (3) 函数值作为实参: 函数作为另一个函数调用的实际参数出现。这种情况是把该函数的返回值作为实参进行传送,因此要求该函数必须是有返回值的。 如: m=max2(a,max(b,c)); 又如: printf(“Max=%d\n”,max2(x,y)); 10:31
§7.2.2调用过程 TKS 24 当调用一个函数时,整个调用过程分为三步进行:第一步是参数传递;第二步是函数体执行;第三步是返回。 int max2(int x,int y) {int z; z=x>y?x:y; return(z); } int main() {int a,b,c; cin>>a>>b; c=max2(a,b); printf(Max is %d”,c); return 1; } 1、参数传递过程 (1) 形式参数和实际参数 形式参数: 在定义函数时函数名后面括弧中的变量名。 实际参数: 在主调函数中调用一个函数时,函数名后面括弧中的参数。 10:31
int max2(int x,int y) {int z; z=x>y?x:y; return(z); } int main() {int a,b,c; cin>>a>>b; c=max2(a,b); printf(Max is %d”,c); return 1; } TKS 25 形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用。 实参出现在主调函数中,进入被调函数后,实参变量也不能使用。 参数是函数调用时进行信息交换的载体。 实参是调用函数中的变量,形参是被调函数中的变量。 10:31
在函数调用过程中实现实参与形参的结合。这称为“实虚结合”。即实参向形参传递信息,使形参具有确切的含义(即具有对应的存储空间和初值)。从而实现主调函数向被调函数的数据传送。在函数调用过程中实现实参与形参的结合。这称为“实虚结合”。即实参向形参传递信息,使形参具有确切的含义(即具有对应的存储空间和初值)。从而实现主调函数向被调函数的数据传送。 TKS 26 如: 4 3 x=3;y=4; t=func(x,y); int func(int a,int b) { …… } 10:31
int max2(int x,int y) {int z; z=x>y?x:y; return(z); } int main() {int a,b,c; cin>>a>>b; c=max2(a,b); printf(Max is %d”,c); return 1; } TKS 27 (2) 说明 ① 形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变量。 ② 实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,都必须具有确定的值,以便把这些值传送给形参。预先可用赋值,输入等办法使实参获得确定值。 ③ 实参和形参在数量上,类型上,顺序上应严格一致,否则会发生“类型不匹配”的错误。 10:31
④ 函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。在内存中,实参单元与形参单元是不同的单元。如图所示。 X y 3 2 TKS 28 int main() {int a,b; cin>>a>>b; cout<<a<<" "<<b<<endl; swap(a,b); getch(); cout<<a<<" "<<b<<endl; return 1; } swap 补充例1 参数单向传递 C+15_4 void swap(int x,int y) {int z; z=x;x=y;y=z; cout<<"x="<<x<<" "<<"y="<<y<<endl; } 10:31
(3) 传值调用的虚实结合过程 TKS 29 函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。在内存中,实参单元与形参单元是不同的单元。其过程如下。 ① 调用开始,系统为形参开辟一个临时存储区,形参与实参各占一个独立的存储空问。 main() int a=3,b=5; swap(int x,int y) ② 然后将各实参之值传递给形参,这时形参就得到了实参的值。这种虚实结合方式称为“值结合”。 a b x y 3 5 5 3 3 5 temp=x; x=y; ③ 函数返回时,临时存储区也被撤销。 y=temp; 10:31
补充例2 还是参数单向传递 C+15_5 TKS 30 int main() {int n; printf("input number: "); cin>>n; s(n); printf("n2=%d\n",n); return 1; } void s(int n) {int i; for(i=n-1;i>=1;i--) n=n+i; printf("n1=%d\n",n); } 2、执行函数体 执行函数体就是按照从上到下、同一行从左到右的次序执行函数函数体中的每条语句。当碰到return语句或右花括号(无函数类型)时就结束返回。 10:31
3、函数返回 TKS 31 ① 概念 函数被调用之后,执行函数体中的程序段所取得的并返回给主调函数的值为函数的值。 ② 说明 Ⅰ函数的值只能通过 return 语句返回主调函数。 return 语句的一般形式为:return表达式; 或者为:return(表达式); 该语句的功能是计算表达式的值,并返回给主调函数。 在函数中允许有多个return语句,但每次调用只能有一个return 语句被执行,因此只能返回一个函数值。 Ⅱ 函数值的类型和函数定义中函数的类型应保持一致。如果两者不一致,则以函数类型为准,自动进行类型转换。 Ⅲ 不返回函数值的函数,可以明确定义为“空类型”,类型说明符为“void”。 10:31
4、其他说明 TKS 32 (1)函数中参数的求值顺序问题C+15_6 int main() {int i=2,p; p=f(i,++i); printf("%d\n",p); return 1; } int f(int a,int b) {int c; cout<<a<<" "<<b<<endl; if(a>b) c=1; else if(a==b) c=0; else c=-1; return(c); } (2) 被调用函数的声明和函数原型 在主调函数中调用某函数之前应对该被调函数进行说明(声明),这与使用变量之前要先进行变量说明是一样的。 10:31
一般形式为:类型名 函数名(类型 形参,类型 形参 … ); TKS 33 或为:类型名 函数名(类型,类型 …); ★ 说明 ① 当被调函数的函数定义出现在主调函数之前时,在主调函数中也可以不对被调函数再作说明而直接调用。 ② 如在所有函数定义之前,在函数外预先说明了各个函数的类型,则在以后的各主调函数中,可不再对被调函数作说明。 例如: char str(int a); float f(float b); main() {……} char str(int a) {……} float f(float b) {……} ③对库函数的调用不需要再作说明,但必须把该函数的头文件用include命令包含在源文件前部。 10:31
设置密码 TKS 34 Problem Description 密码很重要。Sg想你帮他判断一下他设置的密码是否可行,他规定密码必须满足的要求如下:(1)至少有1个元音字母(a,e,i,o,u) ;(2)不能有3个元音连在一起;(3)不能有3个非元音连在一起;(4)除了ee和oo之外,不能有2个相同字母连在一起。 Input测试数据有多组,每组测试输入一个只包含小写字符的字符串(长度小于50),一直处理到输入end为止,end不用处理。 Output对于每组测试,判断密码是否可行,按Sample Output输出。 10:31
Sample Input a tv ptoui bontres zoggax wiinq eep houctuh end Sample Output <a> is acceptable. <tv> is not acceptable. <ptoui> is not acceptable. <bontres> is not acceptable. <zoggax> is not acceptable. <wiinq> is not acceptable. <eep> is acceptable. <houctuh> is acceptable. TKS 35 分析: 1、设计一个测试字符是否为元音的函数,供其他函数调用。 2、设计四个函数,分别测试四个条件,供主函数条用。 3、设计主函数。 10:31
补充例3 设置密码 C+15_7 TKS 36 bool f0(string s,int i) {if(s[i]=='a'||s[i]=='e'||s[i]=='i'||s[i]=='o'||s[i]=='u') return true; return false; } bool f1(string s) {int i=0; bool flag=false; while(!flag&&i<s.size()) { if(f0(s,i)) flag=true; i++; } return flag; } 10:31
补充例3 设置密码 C+15_7 TKS 37 bool f2(string s) {int i=0; bool flag=true; while(flag&&i<int(s.size()-2)) { if(f0(s,i)&&f0(s,i+1)&&f0(s,i+2)) flag=false; i++; } return flag; } 10:31
补充例3 设置密码 C+15_7 TKS 38 bool f3(string s) {int i=0; bool flag=true; while(flag&&i<int(s.size()-2)) { if(!f0(s,i)&&!f0(s,i+1)&&!f0(s,i+2)) flag=false; i++; } return flag; } 10:31
补充例3 设置密码 C+15_7 TKS 39 bool f4(string s) {int i=0; bool flag=true; while(flag&&i<int(s.size()-2)) { if(s[i]==s[i+1]&&s[i]!='e'&&s[i]!='o') flag=false; i++; } return flag; } 10:31
int main() TKS 40 {string str; while(getline(cin,str)) {if(str=="end") break; if(f1(str)&&f2(str)&&f3(str)&&f4(str)) cout<<"<"<<str<<"> is acceptable.\n"; else cout<<"<"<<str<<"> is not acceptable.\n"; } return 1; } 补充例3 设置密码 C+15_7 ? 五、作业与实践: 1、上机编程:6060~6063 2、实验一 数组程序设计 10:31