第五章 函数 5.1 函数的定义、调用与说明 5.2 函数间参数传递 5.3 递归函数 5.4 函数参数缺省 5.5 函数重载

Slides:



Advertisements
Similar presentations
因数与倍数 2 、 5 的倍数的特征
Advertisements

因数与倍数 2 、 5 、 3 的倍数的特 征 新人教版五年级数学下册 执教者:佛山市高明区明城镇明城小学 谭道芬.
第一章 C语言概述 计算机公共教学部.
6.4 字符串与指针 1. 用字符数组存放一个字符串.
第14章 c++中的代码重用.
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
第九章 指针 目录 指针与指针变量的概念 变量的指针和指向变量的指针变量 数组的指针和指向数组的指针变量
第8讲 函数 8.1 函数的定义与调用 8.2 函数的参数 8.3 函数重载与递归 8.4 标识符作用域与变量的存储特性.
第5章 函数与模块化设计 学习目的与要求: 掌握函数的定义及调用方法 理解并掌握参数的传递方法 理解函数的嵌套与递归调用
复习与总结.
4.3函数 4.3.1函数的概念及定义 1、函数的概念: 可以被其它程序调用具有 特定功能的一段相对独立的 程序(模块),称函数。
由C程序结构所知,一个完整的C语言程序是由一个且只能有一个main()函数(又称主函数)和若干个其他函数组合而成的。而前面各章仅学习main()函数的编程,本章将介绍其他函数的编程,包括其他函数的定义、调用、参数传递及变量的作用域等。
第4章 函数与预处理 4.1 概述 4.2 定义函数的一般形式 4.3 函数参数和函数的值 4.4 函数的调用 *4.5 内置函数
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C语言程序设计基础 刘新国.
第七章 函数 目录 有参的加法函数的开发 函数定义的一般形式 函数参数和函数的值 函数的调用
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
第7章 函 数 本章要点: C语言程序结构和特点 函数的定义 函数的返回值与函数的类型 函数的调用及参数的传递关系 函数的嵌套与递归
Object-Oriented Programming in C++ 第一章 C++的初步知识
走进编程 程序的顺序结构(二).
第八章 函数.
辅导课程六.
第7章 函 数 为什么要使用函数? 函数定义、调用、声明 局部变量和全局变量 变量的存储类别 内部函数和外部函数 函数的嵌套调用和递归调用
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
Chap 5 函数 5.1 计算圆柱体积 5.2 使用函数编写程序 5.3 变量与函数.
第二章 C++对C 在非面向对象方面的改进 更简洁,更安全.
第五章 函 数. 第五章 函 数 教学目标 (1) 了解函数在程序设计中的作用; (2) 掌握函数的定义方法; (3) 掌握函数调用和参数传递的机制和方法; (4) 了解变量的作用域和生存期的概念。
第八章 使用指针.
第七章 函数 西安工程大学.
第五章 习题课 电子信息与计算机科学系 曾庆尚.
用event class 从input的root文件中,由DmpDataBuffer::ReadObject读取数据的问题
第七章 操作符重载 胡昊 南京大学计算机系软件所.
授课老师:龚涛 信息科学与技术学院 2016年3月 教材:《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
第4讲 C++程序控制结构(二) 4.1 循环结构 4.2 转向控制 4.3 综合案例分析.
C++大学基础教程 第3章 C++控制语句 北京科技大学 信息基础科学系.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
1.3 C语言的语句和关键字 一、C语言的语句 与其它高级语言一样,C语言也是利用函数体中的可执行 语句,向计算机系统发出操作命令。按照语句功能或构成的不 同,可将C语言的语句分为五类。 goto, return.
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
C语言大学实用教程 第5章 函数与程序结构 西南财经大学经济信息工程学院 刘家芬
$9 泛型基础.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C++语言程序设计 第三章 函数.
第一章 程序设计和C语言 主讲人:高晓娟 计算机学院.
C++语言程序设计 C++语言程序设计 第三章 控制语句 第十一组 C++语言程序设计.
函数 概述 模块化程序设计 基本思想:将一个大的程序按功能分割成一些小模块, 特点: 开发方法: 自上向下,逐步分解,分而治之
目录 7.1 用户自定义函数的种类 7.2 函数的定义 7.3 被调函数的声明 7.4 函数的调用 7.5 函数的嵌套调用
C语言程序设计 第一章 数据类型, 运算符与表达式 第二章 顺序程序设计 第三章 选择结构程序设计 第四章 循环控制 第五章 数组.
第六章 指针 C++程序设计中使用指针可以: 使程序简洁、紧凑、高效 有效地表示复杂的数据结构 动态分配内存 得到多于一个的函数返回值.
Chap 5 函数 5.1 计算圆柱体积 5.2 使用函数编写程序 5.3 变量与函数.
7.1 C程序的结构 7.2 作用域和作用域规则 7.3 存储属性和生存期 7.4 变量的初始化
第五章 函 数 要点:掌握函数的定义,函数的原形,函数的返回值,函数的调用,函数的形式参数和实际参数之间的关系;掌握函数重载的使用方法,关键字inline的含义与使用,掌握变量的作用域与生存期,了解函数的作用域。
第十四章 若干深入问题和C独有的特性 作业: 函数指针 函数作参数 函数副作用 运算 语句 位段 存储类别 编译预处理
第十章 指针 指针是C语言的重要概念,是C语言的特色,是C语言的精华。 10.1 地址和指针的概念 内存中的每一个字节都有一个地址。
C程序设计.
第4章 Excel电子表格制作软件 4.4 函数(一).
第九节 赋值运算符和赋值表达式.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
#include <iostream.h>
第四章 函数 丘志杰 电子科技大学 计算机学院 软件学院.
第7章 模板 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.
本节内容 C语言的汇编表示 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第十章 多态 第十一组 C++语言程序设计.
第9章 C++程序设计初步 9.1 C++的特点 9.2 最简单的C++程序 9.3 C++的输入输出 9.4 函数的重载
第六章 复合数据类型 指针的声明与使用 数组的声明与使用 指针与数组的相互引用 字符串及相关库函数 new与delete
第二次课后作业答案 函数式编程和逻辑式编程
计算机编程 信息管理与工程学院 2014年9月.
Presentation transcript:

第五章 函数 5.1 函数的定义、调用与说明 5.2 函数间参数传递 5.3 递归函数 5.4 函数参数缺省 5.5 函数重载 5.6 函数模板 5.7 作用域与存储类

5.1 函数的定义、调用与说明 5.1.1 引例 已知五边形的各条边的长度,计算其面积 计算多边形面积,可将多边形分解成若干个三角形 5.1.1 引例 已知五边形的各条边的长度,计算其面积 计算多边形面积,可将多边形分解成若干个三角形 x y z 计算三角形面积的公式如下:

用前面所学的知识实现: #include "math.h" #include "iostream.h" void main() {float a,b,c,d,e,f,g,p1,p2,p3,s1,s2,s3,s; cin>>a>>b>>c>>d>>e>>f>>g; p1=(a+b+c)/2; s1=sqrt(p1*(p1-a)*(p1-b)*(p1-c)); p2=(c+d+e)/2; s2=sqrt(p2*(p2-c)*(p2-d)*(p2-e)); p3=(e+f+g)/2; s3=sqrt(p3*(p3-e)*(p3-f)*(p3-g)); s=s1+s2+s3; cout<<s<<endl; }

float area(float x, float y, float z) //定义求三角形面积函数 { float c,s ; 用函数实现: #include "math.h" #include "iostream.h" float area(float x, float y, float z) //定义求三角形面积函数 { float c,s ; c = (x + y + z)/2; s = sqrt(c*(c-x) * (c-y) * (c-z)); return s; } void main() //主函数 {float a,b,c,d,e,f,g,s; cin>>a>>b>>c>>d>>e>>f>>g; s=area(a,b,c)+area(c,d,e) +area(e,f,g); cout<<s<<endl; 特点: 函数具有相对独立的功能 函数与函数之间通过参数(输入)和返回值(输出)来联系 使用函数有利于代码重用,提高开发效率

5.1.2 函数的定义 函数类型 函数名(形式参数类型表) {函数体} 【例5.1】求三个整型数中最大的数。 将两数的比较独立出来编一函数: 5.1.2 函数的定义 函数类型 函数名(形式参数类型表) {函数体} 【例5.1】求三个整型数中最大的数。 将两数的比较独立出来编一函数: int max(int x,int y) { int z; if(x>y) z=x; else z=y; return z; //将大的数返回 } void main() { int a,b,c,m; cin>>a>>b>>c; m=max(a,b); m=max(c,m); cout<<m<<endl; }

【例5.2】编一程序,输出如右图形。 将n行构成的三角形独立出来编一函数: void pic(int n) { for(int i=0;i<n;i++) cout.width(10-i); //控制每行输出的起始位 for(int j=0;j<2*i+1;j++)cout<<"*"; cout<<endl; } void main() { pic(4); pic(6); }

函数体中必须有return语句,形式为: return 表达式 ; 或 return (表达式) ; 说明: 函数类型指函数返回值的数据类型 函数体由语句和其它分程序组成。 形式参数可以为空,但圆括号不能省略。 函数体中不允许再嵌套定义函数 对没有返回值的函数,函数类型定为void型(无类型或空类型)。 非void型函数 函数体中必须有return语句,形式为:      return 表达式 ; 或 return (表达式) ;   用于返回函数值。表达式值的类型与函数类型最好一致。 void型函数 函数体中return语句可以不出现。若出现,则不能带表达式。

5.1.3 函数调用 形式: 函数名(实在参数表) 函数调用的过程: 注意: 5.1.3 函数调用 形式: 函数名(实在参数表)   函数调用的过程: 注意: 实参与形参的个数、位置与类型必须一致。它可以是同类型的常量、变量或表达式。 调用的形式可以是表达式,也可以是语句。 函数定义中的形参只有当发生函数调用时,才被分配内存单元。

void pic(int n) { for(int i=0;i<n;i++) cout.width(10-i); for(int j=0;j<2*i+1;j++) cout<<"*"; cout<<endl; } #include "iostream.h" #include "iomanip.h" void main() { pic(4); //以语句形式调用 pic(6); }

函数调用和返回的过程: 注意:数据的输入、输出一般放在主函数中 主函数 自定义函数 ① 保存:返回地址、当前现场 ④ 输入数据 处理过程 ③ ② ⑤ 调用函数 ⑥ 函数结束或 函数值返回 ⑦ 恢复:主调程序现场、返回地址 输出 ⑧ 结束 注意:数据的输入、输出一般放在主函数中

【例5.3】 求正整数m,n的最大公约数和最小公倍数 。 分析:m、n的最小公倍数为: m*n/最大公约数。 int gcd(int m,int n) //求最大公约数   { while(int r=m%n) {m=n;n=r;} return(n); } #include "iostream.h“ void main() { int m,n; cin>>m>>n; cout<<gcd(m,n)<<endl; cout<<sct(m,n)<<endl; } int sct(int m,int n) //求最小公倍数 { return( m*n/gcd(m,n) ); } 注意: 函数中参数传递是单向“传值”。

函数嵌套调用的示意图:

5.1.4 函数说明(函数原型) 形式: 函数类型 函数名(形式参数类型表); 【例5.4】函数说明示例 5.1.4 函数说明(函数原型) 形式: 函数类型 函数名(形式参数类型表); 【例5.4】函数说明示例 #include "iostream.h" void main() {int a,b,c; int max(int x,int y); //函数说明,也可int max(int,int); cin>>a>>b; c=max(a,b); cout<<c<<endl; } int max(int x,int y) { return x>y?x:y ; } 省略参数名 注意:  函数调用在前,定义在后,则必须对函数进行说明,函数说明可以放在函数调用之前所在的函数内,也可以放在源文件开头、函数的外部。  函数说明和函数定义在返回类型、函数名和参数表上必须要完全一致。

5.2 函数间参数传递 5.2.1 传值参数 特点:形参的改变不会影响实参的值 5.2 函数间参数传递 5.2.1 传值参数 特点:形参的改变不会影响实参的值 【例5.5】m是一个3位的正整数,将满足m、m2、m3均为回文数的正整数输出。所谓回文数是指顺读与倒读数字相同,如4、151、34543。 分析:将正整数的每位数取出,构造一个逆序的正整数,若该数与原来的相同,即为回文数。 实参:常量、变量和表达式。 形参:变量 bool palindrome(int x) { int m=x,n=0,k; while(x!=0) //构造一逆序数 { k=x%10; n=n*10+k; x/=10; } return m==n; }

cin>>a>>b; swap(a,b); 【例5.6】分析下面程序,能否交换两个变量的值? #include "iostream.h" void swap(int x,int y) {int temp; temp=x;x=y;y=temp; } void main() {int a,b; cin>>a>>b; swap(a,b); cout<<"a="<<a<<" b="<<b<<endl;

5.2.1 指针参数 1.形参为指针变量 特点:形参的改变能影响实参值 【例5.7】交换两个变量的值 5.2.1 指针参数 1.形参为指针变量 特点:形参的改变能影响实参值 【例5.7】交换两个变量的值 #include "iostream.h" void swap(int * ,int * ); void main() { int a,b;cin>>a>>b; swap(&a,&b); cout<<a<<b<<endl; } void swap(int *x,int *y) {int temp=*x;*x=*y;*y=temp;} 形参:指针变量 实参:变量的地址、指针变量或数组名

【例5.8】随机生成10个1~100之间的数放在一维数组中,求其平均值及最大的元素值 。 #include "iostream.h" #include "stdlib.h" const int N=10; void fun(float *p,float *p1,int *p2) { float sum,max1; sum=max1=*p++; for(int i=1;i<N;i++) { if (max1<*p) max1=*p; sum=sum+*p;p++; } *p1=sum/N; *p2=max1; } void main() { float a[10],aver,max,x; for(int i=0;i<10;i++) { x=rand()%100+1; a[i]=x; } fun(a,&aver,&max); //注意实参的写法 cout<<aver<<max<<endl; 程序:

【例5.9】字符串的复制 程序: #include "iostream.h" void copy_string(char *from, char *to) { while(*from!='\0') *to++=*from++; *to='\0'; } void main() { char a[]="I am a teacher.", b[]="You are a student."; cout<<a<<endl<<b<<endl; copy_string(a,b); cout<<a<<endl<<b<<endl; }

注意:若对应的实参是指针变量,则该指针应有确定的指向。 若该二语句删除,程序运行时将异常终止。 void main() {char *a,*b; a=new char[40]; b=new char[20]; cin>>a>>b; copy_string(a,b); cout<<a<< b<<endl; delete []a; delete []b; }

{ int x=5; cout<<f(&x); } *p=a; return *p; 2.形参为常指针 防止被调函数对实参所指对象的修改 错误,不能修改const对象 #include "iostream.h " int f(const int * p) { int a=100; a=*p; return a; } void main() { int x=5; cout<<f(&x); } *p=a; return *p;

注意:若实参是常对象的地址,则形参必须定义为常指针。 #include "iostream.h" int f(const int *p) { int a=100; a=*p; return a; } void main() const int x=5; cout<<f(&x); 形参不能定义为int *p

3.函数返回值为指针 即函数的返回值可以是变量的地址、数组名或指针变量等。 如: float *fun(float x[],float y); char *strcat(char *strDest,const char *strSource); 在说明或定义返回值为指针的函数时,只须在函数名前加一指针类型说明符即可。

【例5.10】拼接两个字符串s1和s2,将拼接后的字符串存于s1中返回。 char *strcat1(char *s1,const char *s2) {char *p=s1; while(*p++); --p; while(*p++=*s2++) ; return(s1); } 思考:若不定义为返回指针值的函数,则程序应如何修改?

注意:不能返回一个局部变量(在函数内定义的变量)的地址 #include "iostream.h" int *fun(int x) { int y=x*x; return &y; } void main() int a=5, *p; p=fun(a); cout<<*p; p指向的对象已经不存在

5.2.2 引用参数 特点:形参的改变可影响实参值。 #include "iostream.h" 5.2.2 引用参数 特点:形参的改变可影响实参值。 &为引用声明符。 x是a的引用, y是b的引用。 #include "iostream.h" void swap(int &x,int &y) { int temp=x;x=y;y=temp; } void main() { int a,b; cin>>a>>b; swap(a,b); cout<<"a="<<a<<"b="<<b; } 形参是引用 实参只能是变量名 引用是一种特殊类型的变量,可认为是另一个变量的别名,它不占用存储空间,对引用的操作就是对被引用者的操作,它们代表的是同一存储单元。

【例5.11】编一函数,判别一个自然数N是否是降序数,同时,求出该数各位数和。并加以调用,若是降序数输出“yes”,否则输出“no”。例如:3、441、531是降序数;而412不是降序数。 bool drop(int x,int &sum) { bool flag=1;int x1=x; while(x1) sum+=x1%10;x1/=10; } while(x>=10&&flag) //判断是否降序数 if(x/10%10>=x%10) x/=10; else flag=0; return flag;

5.2.3 数组名作参数 特点:在被调函数中对形参数组的任何改变均会影响实参所指地址里的内容 。 形参:数组名 实参:数组名或指针变量 5.2.3 数组名作参数 特点:在被调函数中对形参数组的任何改变均会影响实参所指地址里的内容 。 形参:数组名 实参:数组名或指针变量 【例5.12】对含有n个元素的整型数组a,从大到小进行排序。 void sort(int x[],int n) {int i,j,k,w; for(i=0;i<n-1;i++) {k=i; for(j=i+1;j<n;j++)if(x[k]<x[j])k=j; if(i!=k){w=x[i];x[i]=x[k];x[k]=w;} } 数值型数组的元素个数一般须传给形参 调用:sort(a,10);

调用: cout<<len(str); 【例5.13】 求字符串长度,并调用之。 int len(char s[]) { int i=0; while(s[i]!='\0')i++; return i; } 字符型数组的元素个数一般不用传给形参 调用: cout<<len(str);

注意: ① 形参和实参的类型应保持一致。 ② 函数头里的参数,要一个一个地分别说明或 列出。 下面是几种函数头正确与错误的写法: 正确 错误 int max(int x,int y) int max(int x,y) void sort(int a[],int n) void sort(int a[n],int n) void sort(int a[];int n) void sort(int a[],n) int m(int x[][4],int y) int m(int x[][],int y)

5.2.4 对象参数 【例5.14】 统计字符串str1中出现子串sub的个数 5.2.4 对象参数 实参为CString对象,则形参可以是: (1) CString 参数,对形参的改变不影响实参; (2) CString &参数, 对形参的改变将影响实参; (3) const CString &参数,不允许改变形参值。 【例5.14】 统计字符串str1中出现子串sub的个数 int count(CString str1,const CString sub) { int i,count=0,k; i=str1.Find(sub); while(i>=0) {count++; k=str1.GetLength(); str1=str1.Mid(i+1,k-i); i=str1.Find(sub); } return count; }

5.3 递归函数 用自身的结构来描述自身就称为递归。 最典型的例子是对阶乘运算: 特点: ① 原始问题可转化为解决方法相同的新问题; 5.3 递归函数 用自身的结构来描述自身就称为递归。 最典型的例子是对阶乘运算: 特点: ① 原始问题可转化为解决方法相同的新问题; ② 新问题的规模比原始问题小; ③ 新问题又可转化为解决方法相同的规模更小的新问题,直至终结条件为止。

【例5.15】编fac(n)=n! 的递归函数 long fac(int n) { if(n==1) return(1); return (n*fac(n-1)); } 递推 回归 fac(4)=4*fac(3) fac(3)=3*fac(2) fac(2)=2*fac(1) fac(1)=1 fac(4)=4*6 fac(3)=3*2 fac(2)=2*1 递推过程   每调用自身,当前参数压栈,直到达到递归结束条件。 回归过程   不断从栈中弹出当前的参数,直到栈空。 思考:若fac函数中没有语句 if(n==1) return(1);程序运行结果将如何?

【例5.16】用递归函数实现将一个十进制整数转换成二至十六任意进制的字符 void convert(int m,int r) { char b[17]="0123456789ABCDEF"; if(m!=0) { convert(m/r,r);cout<<b[m%r]; } } 任何有意义的递归必须具有: 递归结束条件及结束时的值; 能用递归形式表示,并且递归向终止条件发展。 递归算法设计简单,程序代码简洁易读,但它消耗的机时和占据的内存空间比非递归大。

5.4 函数参数缺省 #include "iostream.h" #include "math.h" 【例5.17】求下面级数的部分和。精度为:   #include "iostream.h" #include "math.h" double s(double x , double eps=1e-6) {int n=1; double w=0.0, t=1.0 ; while(fabs(t)>=eps) {w+=t; t=t*x/(n++); } return w; void main() { cout<<"s1="<<s(2.0); cout<<"s2="<<s(3.0); cout<<"s3="<<s(1.0,1e-5);} 参数eps取默认值1e-6 参数eps的值为1e-5

说明: 默认参数的说明必须出现在函数调用之前。若一个函数说明已给出参数的默认值,则在函数定义中不允许再设置。 要求赋予默认值的参数必须放在形参表列中的最右端。 分析下面各例: void fun(int i, int j, int k, int m=3,int n=4); 假设函数调用语句为: fun(1,2); //错误,至少应有三个实参 fun(10,20,30); //正确,m、n取默认值 fun(10,20,30,40); //正确,m取40 、n取默认值4 fun(10,20,30, ,50); //错误,只能从左至右匹配

5.5 函数重载 引例:求不同类型数据的绝对值 #include <iostream.h> 5.5 函数重载 引例:求不同类型数据的绝对值 #include <iostream.h> #include <math.h> void main() {int x1=-1; double x2=2.5; long x3=3L; cout<<abs(x1)<<endl; cout<<fabs(x2)<<endl; cout<<labs(x3)<<endl; } 不同名函数实现同一类的操作 不足:易出错、难记忆 函数重载:一组参数(个数或类型)不同的函数共用一个函数名。

一. 参数类型不同的重载函数 【例5.18】 #include <iostream.h> int abs(int x) {return x>0?x:-x; } double abs(double x) long abs(long x) void main() {int x1=1; double x2=2.5; long x3=3L; cout<<abs(x1)<<endl; cout<<abs(x2)<<endl; cout<<abs(x3)<<endl; } 编译器根据函数参数的类型来确定应该调用哪个函数

二. 参数个数不同的重载函数 【例5.19】 #include <iostream.h> 二. 参数个数不同的重载函数 【例5.19】 #include <iostream.h> int min(int a,int b) {return a<b?a:b; } int min(int a,int b,int c) {int t=min(a,b); return min(t,c);} int min(int a,int b,int c,int d) {int t1=min(a,b); int t2=min(c,d); return min(t1,t2);} void main() { cout<<min(13,5,4,9)<<endl; cout<<min(-2,8,0)<<endl; } 编译器根据调用语句中实参的个数来确定应该调用哪个函数 可见:重载使得函数的使用更加灵活、方便。 它体现了c++对多态性的支持———一个名字,多个入口 。 注意:不要同时使用重载函数和缺省参数函数。

template <class 类型参数表 > 5.6 函数模板 使用函数重载需编写多个函数,而利用函数模板只需定义一个通用函数即可。 利用函数模板定义的函数称为模板函数,形式: template <class 类型参数表 > 类型 函数名( 参数表) {……} 定义一个数据类型T 使用模板函数时,模板中的类型参数T用实参的类型替换 【例5.20】 #include <iostream.h> template <class T> T min(T a,T b) {return a<b?a:b; } void main() { cout<<min(3,5)<<endl; cout<<min(8.5,5.6)<<endl; }

  分析以下几种模板函数:  template <class T> T fun1(T a,int b) //可含有模板参数表中未给出的数据类型 {…… }  template <class T1,T2,T3> //模板中可带有多个参数 void fun1(T1 a,T2 b,T3 c) {…… }  template <class T> void fun1(int a,int b) //必须至少有一个参数的类型为模板的类型参数 {…… }  template <class T> void fun1(int a,int b) {T i,j; …… }

template <class TEM> void sort(TEM x[],int n) {int i,j,k; TEM w; #include "iostream.h " template <class TEM> void sort(TEM x[],int n) {int i,j,k; TEM w; for(i=0;i<n-1;i++) { k=i; for(j=i+1;j<n;j++) if(x[k]>x[j])k=j; if(i!=k) {w=x[i];x[i]=x[k];x[k]=w;} } void main() {int i,a[6]={6,9,2,4,1,0}; double b[4]={5.5,8.0,3.3,0}; sort(a,10); sort(b,5); for(i=0;i<10;i++) cout<<a[i]<<endl; for(i=0;i<5;i++) cout<<b[i]<<endl; } 注意w变量的定义

5.7 作用域与存储类别 【例5.22】 从下面三方面分析各变量 作用域(可见性): 在什么范围内可以访问 5.7 作用域与存储类别 【例5.22】 从下面三方面分析各变量 作用域(可见性): 在什么范围内可以访问 空间概念 生存期: 在什么时间存在 时间概念 初始化 #include "iostream.h" int digit(long n) { int k=0; while(n!=0) {n/=10; k+=1;} return k; } void main() long x; cin>>x; cout<< digit(x)<<endl; 全局变量(外部变量):      在函数外部定义的变量 局部变量(内部变量):     在函数内部定义的变量, 包括形式参数

5.7.1 自动变量 作用域:从定义点开始到所在的分程序结束 生存期:开始执行分程序就生成,分程序执行结束就消亡 5.7.1 自动变量 作用域:从定义点开始到所在的分程序结束 生存期:开始执行分程序就生成,分程序执行结束就消亡 初始化:可以初始化,缺省值为随机值。 作用域不可以扩展 【例5.23】 #include "iostream.h" int f(int x) { x++; int y=5; //auto int k=5; y++; return x+y; } void main() { int k=2; cout<<f(k)<<endl; cout<<f(k+1)<<endl; 缺省的存储类别:auto 注意:只有内部变量存储类别才能auto

cout<<"i!="<<fac(i); } 5.7.2 静态局部变量 作用域:从定义点开始到所在的分程序结束。 生存期:程序的执行周期 初始化:可以初始化,缺省值为0或'\0 ' 。 初始化一次 在开始执行程序时初始化 作用域不可以扩展 一个函数可能被调用多次, 前一次调用的结果带到下一次去。 【例5.24】 #include "iostream.h" int fac(int n) {static int f=1; f=f*n; return(f);} void main() {auto int i; for(i=1;i<=5;i++) cout<<"i!="<<fac(i); }

5.7.3 全局变量 作用域:从定义点开始到所在的文件结束 生存期:程序的整个执行周期 初始化:可以初始化,缺省值为0或'\0 '。 作用域可以扩展: 向上扩展 横向扩展,扩展到另一个文件 注意:扩展的地方不能初始化

外部变量与局部变量同名,起作用的是局部变量 【例5.25】外部变量示例 #include "iostream.h" int m=10; void f1(int n) { n=2*n;m=m/3; } int n; void f2() { n=5;m++;n++; } void main() { int n=2; f1(n); f2(); cout<<m<<n<<endl; } 外部变量与局部变量同名,起作用的是局部变量 注意: 外部变量的作用域只限于定义处到文件结束,定义点之前的函数或其它文件中的函数不可以引用该外部变量。 可以使用extern声明符来扩展外部变量的作用域

(1)作用域向定义点之前的函数扩展 #include <iostream.h> extern int i; //不能初始化 void fun() { // extern int i; cout<<i; } int i=5; void main() int j=20; cout<<j; fun(); #include <iostream.h> extern int i; void fun() { //extern int i; 错误 cout<<i; } void g() {i++;} int i=5; void main() { int j=20; cout<<j; g(); fun();

(2)作用域扩展到另一个文件 【例5.26】作用域横向扩展示例 //file1.cpp extern max,min; #include "iostream.h" void main() { void maxmin(int x[],int n); int a[10]={11,2,3,-4,5,6,7,8,0,20}; maxmin(a,10); cout<<max<<" "<<min<<endl; } //file2.cpp int max,min; void maxmin(int x[],int n) { max=x[0];min=x[0]; for(int i=0;i<n;i++) { if(x[i]>max)max=x[i]; if(x[i]<min)min=x[i]; }

总结: 外部变量 auto变量 static内部变量 作用域 从定义点到文件结束 用extern扩展 从定义点到分程序 不可扩展 生存期 程序的整个执行周期 分程序的执行周期 初始化 缺省为0或'\0 ' 缺省为随机值

5.8 程序举例 【例5.27】编一判断质数的函数,验证歌德巴赫猜想:任何大于2的偶数均可表示为两个素数的和。例如:4=2+2(特例,仅此一个),6=3+3,8=3+5,…。程序要求输入任一偶数,输出6到该数范围内的各个满足条件的组合。 分析:对一个偶数,分解为两个质数和,既n=a+b。方法是从找最小的质数a为3开始(因2是偶数,另一个必定是偶数,不可能是质数),判断b=n-a是否是质数,若b也是质数,则n符合要求;否则,找下一个质数a,再判断b。

程序: #include "iostream.h" int isprime(int m) //判别m是否为质数 { for(int i=2;m%i!=0;i++); return (i==m); } void main() { int n,x,a,b; cin>>x; for(n=6;n<=x;n+=2) for(a=3;a<=n/2;a+=2) if(isprime(a)) { b=n-a; if(isprime(b)) { cout<<n<<"="<<a<<"+"<<b<<endl; break; //退出a循环,判别下一个n的组合

【例5.28】写一函数itoc(),把数字转变成字符串。如数字-123,经过itoc(-123)后,变为″-123″。 分析:函数itoc()先判断n是否有符号,若有符号,应先保存加以处理。数字变为对应的字符须将其ASCII码加上30H,即加上字符’0’。把一个数(如n)的每一位分离出来可以用n%10,而循环结束条件为n/10>0。但这样处理的数据是从个位向前的,所以还要作反转处理。

程序: #include "iostream.h" #include "string.h" void main() { void itoc(int,char []); int n;char s[100]; cin>>n; itoc(n,s); cout<<s<<endl; } void itoc(int n,char s[]) { void reverse(char []); int i=0; int sign; if((sign=n)<0) n=-n; do {s[i]=n%10+'0';i++;n=n/10;} while (n>0); if(sign<0) s[i++]='-'; s[i]='\0'; reverse(s); } void reverse(char s[]) { int c,i,j; j=strlen(s)-1; for(i=0;i<j;i++,j--) {c=s[i];s[i]=s[j];s[j]=c;} s[i+j+1]='\0'; }

【例5.29】用梯形法求积分: 分析:n等分积分区间[a,b],每一个小梯型的面积和即近似为f(x)在[a,b]的积分值。即将求积分转化求和。

程序: #include "iostream.h" #include "math.h" double f(double x) { return exp(-x*x/2);} double integral(double a,double b,int n) { int sum;double h=(b-a)/n; sum=(f(a)+f(b))/2; int x=a+h; for(int i=1;i<n;i++) { sum+=f(x); x+=h; } return sum*h; } void main() { double a,b; int n; cout<<"输入区间值、等分数:"<<endl; cin>>a>>b>>n; cout<<integral(a,b,n)<<endl;

【例5.30】 统计字符串中各个字母(不区分大、小写)出现的频率,同时找出频率出现最高的字母及次数。 分析:由于函数需要返回多个值,故可通过传址调用或引用调用实现。将要处理的数据及处理的结果设为形参。

#include "iostream.h" #include "stdio.h" #include "string.h" void freq(char s[],int p[],char &chmax,int &max) { for(int i=0;i<26;i++)p[i]=0; strlwr(s); i=0; while(s[i]!='\0') { if(s[i]>='a'&&s[i]<='z') p[(s[i]-'a')]++; i++; } max=p[0]; int k=0; for(i=1;i<26;i++) if(p[i]>max) { max=p[i];k=i;} chmax=k+97; } void main() { int p[26],i,max; char s[80],chmax; gets(s); freq(s,p,chmax,max); for(i=0;i<26;i++) if(p[i])cout<<char(i+97)<<"----"<<p[i]<<endl; cout<<chmax<<"----"<<max<<endl; 程序:

【例5.31】编写两个重载的同名函数find,功能为查找指定的字符或子字符串在串中的位置。既实现Cstring类中二个Find成员函数的功能。 int find(char s[],char ch) { for(int i=0;s[i];i++) if(s[i]==ch)break; return i; } int find(char s1[],char s2[]) { char s[80]; for(int i=0;s1[i];i++) { for(int j=0;s2[j];j++) s[j]=s1[i+j]; s[j]='\0'; if(!strcmp(s,s2)) return i;