C++大学基础教程 第4章 函数 北京科技大学 信息基础科学系.

Slides:



Advertisements
Similar presentations
1 第二讲 C++ 编程基础. 2 主要内容 C++ 语言概述 C++ 编程基础 数据的简单输入输出 C++ 的发展 C++ 源程序结构与书写规范 C++ 编译器和集成开发环境.
Advertisements

1 第 3 章 C++ 中的条件与循环 第 3 次见面! acm.nefu.edu.cn/C++_03.ppt.
C++语言程序设计教程 第5章 构造数据类型 第6章 C++程序的结构.
移动应用软件开发技术 第二讲:C++编程基础
第一章 C语言概述 计算机公共教学部.
第4章 数组 数组是由一定数目的同类元素顺序排列而成的结构类型数据 一个数组在内存占有一片连续的存储区域 数组名是存储空间的首地址
第5章 函数与预处理 《 C语言程序设计》 (Visual C++ 6.0环境) 本章导读
第二章 C# 基础知识.
C++程序设计 第二讲 清华大学软件学院.
第4章 函数与预处理 4.1 概述 4.2 定义函数的一般形式 4.3 函数参数和函数的值 4.4 函数的调用 *4.5 内置函数
C 程式設計— 語言簡介 台大資訊工程學系 資訊系統訓練班.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第一章 程序的基本结构. 第一章 程序的基本结构 教材及授课结构 本章目标 基本内容 扩展阅读 上机指导 应用举例 习题.
C++ 程式設計— 語言簡介 台大資訊工程學系 資訊系統訓練班.
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
Object-Oriented Programming in C++ 第一章 C++的初步知识
第12章 從C到C++語言 12-1 C++語言的基礎 12-2 C++語言的輸出與輸入 12-3 C++語言的動態記憶體配置
前處理指令可以要求前處理器 (preprocessor) 在程式編譯之前,先進行加入其它檔案的內容、文字取代以及選擇性編譯等工作。
第 6 章 函式.
2 C++ 的基本語法和使用環境 親自撰寫和執行程式是學好程式語言的不二法門。本章藉由兩個簡單的程式,介紹C++ 程式的基本結構和開發環境,讓初學者能逐漸建立使用C++ 的信心。
6 使用者函數 6.1 函數定義 宣告函數 呼叫函數 呼叫多個函數 6-6
第二章 C++对C 在非面向对象方面的改进 更简洁,更安全.
第3章 程序设计初步 第4章 函数与预处理 第5章 数组 第6章 指针 第7章 自定义数据类型
第3讲 C++程序控制结构 3.1 顺序结构 3.2 分支结构 3.3 循环结构 3.4 转向控制 3.5 综合案例分析.
Chapter 3 – Functions 函式 目標 能夠明白如何利用一些函式、用模組化的方式建立程式 能夠建立新的函式
C++语言程序设计 第二章 C++简单程序设计.
程序的三种基本结构 if条件分支语句 switch多路开关语句 循环语句 循环嵌套 break,continue和goto语句
3 數學運算 3.1 鍵盤輸入 輸入函數cin 多重輸入cin 輸出格式化 3-3
谭浩强 编著 中国高等院校计算机基础教育课程体系规划教材 C++程序设计.
切換Dev c++顯示語言 工具->環境選項(V)->介面->language (Chinese TW)
授课老师:龚涛 信息科学与技术学院 2016年3月 教材:《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
第2章 C++流程控制语句 if 语句 switch语句 for语句 while语句 do - while语句 break语句
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
C++ 程式設計 基礎篇 張啟中 Chang Chi-Chung.
六、函数 教学目标: 函数的概念、定义、调用和返回 带自定义函数的程序设计 递推算法 递归思想及算法实现 函数的参数传递方式 C语言程序设计.
C++大学基础教程 第3章 C++控制语句 北京科技大学 信息基础科学系.
C++大学基础教程 第11章 多态性 北京科技大学 信息基础科学系 2019/4/8 北京科技大学.
第二章 基本数据类型及运算 C数据类型概述 基本数据类型 运算符和表达式 混合运算与类型转换 数据的输入输出 顺序程序设计举例.
第1讲 C语言基础 要求: (1) C程序的组成 (2) C语言的标识符是如何定义的。 (3) C语言有哪些基本数据类型?各种基本数
C++语言程序设计 C++语言程序设计 第五章 函数 第十一组 C++语言程序设计.
程式結構&語法.
第三章 C++的语句和简单的程序设计 主要内容:
第 二 章 数据类型、运算符与表达式.
C++语言程序设计 C++语言程序设计 第三章 控制语句 第十一组 C++语言程序设计.
Oop8 function函式.
Chap 5 函数 5.1 计算圆柱体积 5.2 使用函数编写程序 5.3 变量与函数.
7.1 C程序的结构 7.2 作用域和作用域规则 7.3 存储属性和生存期 7.4 变量的初始化
第11章 從C到C++語言 11-1 C++語言的基礎 11-2 C++語言的資料型態與運算子 11-3 C++語言的輸出與輸入
第十四章 若干深入问题和C独有的特性 作业: 函数指针 函数作参数 函数副作用 运算 语句 位段 存储类别 编译预处理
C程序设计.
C++语言程序设计教程 第2章 数据类型与表达式 第2章 数据类型与表达式 制作人:杨进才 沈显君.
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
C++程式設計入門 變數與運算子 作者:黃建庭.
第三章 程序的控制结构 第一节 概述 第二节 if选择结构 第三节 switch语句.
第2章 数据类型、运算符与表达式 本章要点: 基本数据类型 常量和变量 算术运算符和算术表达式 关系运算符和关系表达式
第二讲 基本数据类 型及数组等 此为封面页,需列出课程编码、课程名称和课程开发室名称。
第 3 章 类的基础部分 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.
#include <iostream.h>
第四章 函数 丘志杰 电子科技大学 计算机学院 软件学院.
第二章 Java基本语法 讲师:复凡.
C++语言程序设计 C++语言程序设计 第八章 继承 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
本章主題 C++的程式結構 資料型態與宣告 算術運算 簡易的輸入輸出指令 程式編譯(Compile)的過程與原理.
《数据结构与算法设计》第一部分 面向对象的C++程序设计基础.
第三章 高级函数特性.
基本資料型態 變數與常數 運算子 基本的資料處理 授課:ANT 日期:2014/03/03.
第9章 C++程序设计初步 9.1 C++的特点 9.2 最简单的C++程序 9.3 C++的输入输出 9.4 函数的重载
變數與資料型態  綠園.
第二章 Java基础语法 北京传智播客教育
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
Presentation transcript:

C++大学基础教程 第4章 函数 北京科技大学 信息基础科学系

C++程序的组成

程序设计中,把具有一定功能的程序模块用函数或类来实现 函数是具有一定功能又经常使用的相对独立的代码段

第4章 函数 4.1 函数概述 4.2 函数定义 4.3 函数调用 4.4 内联函数 4.5 重载函数 4.6 默认参数值的函数 4.7 全局变量与局部变量 4.8 变量的存储类型 4.9 编译预处理(自学)

4.1 函数概述

4.1 函数概述 1.函数简介 一般是将整个程序分为若干个程序模块 每个模块用来实现一个特定的的功能 C++中模块的实现 函数 类 这就是结构化程序设计的思想! 1.函数简介 一般是将整个程序分为若干个程序模块 每个模块用来实现一个特定的的功能 C++中模块的实现 函数 库函数 自定义函数 类 技巧:要熟悉C++标准库提供的类和函数集合。不要事事从头做起,要尽可能利用C++标准库提供的函数而不是生成新函数,以便减少程序开发的时间。

库函数 #include <iostream> #include <cmath> using namespace std; int main() { cout << "Enter Quadratic coefficients: "; double a, b, c; cin >> a >> b >> c; if ( (a != 0) && (b*b - 4*a*c > 0) ) { double radical = sqrt(b*b - 4*a*c); double root1 = (-b + radical) / (2*a); double root2 = (-b - radical) / (2*a); cout << "Roots: " << root1 << " " << root2; } else cout << "Does not have two real roots"; return 0; 调用函数 或主调函数 被调函数 库函数

自定义函数 自定义函数 #include <iostream> using namespace std; float CircleArea(float r); // main(): manage circle computation int main() { cout << "Enter radius: "; float MyRadius; cin >> MyRadius; float Area = CircleArea(MyRadius); cout << "Circle has area " << Area; return 0; } // CircleArea(): compute area of radius r circle float CircleArea(float r) { const float Pi = 3.1415; return Pi * r * r; 自定义函数

2.数学库函数 C++语言提供的库函数中有一些是专门完成特定的 数学运算的,称为数学库函数。 实现常见的数学计算 例如: 求绝对值、平方根等。 调用数学函数: 函数名(参数1,…,参数n) 例如: cout<<sqrt(900.0);

2.数学库函数 数学函数库中的多数函数都返回double类型结果。 使用数学库函数,需要在程序中包含math.h头文件,这个头文件在新的C++标准库中称为cmath。 函数参数可取常量、变量或表达式。 例: 如果c=13.0、d=3.0和f=4.0,则下列语句: cout<<sqrt(c+d*f); 计算并显示13.0+3.0*4.0=25.0的平方根,即5.0。

4.2 函数定义

4.2 函数定义及使用 函数定义 函数原型 return语句 函数使用的三种方式

1.函数的定义 包括接口和函数体 接口 函数类型 函数名 形式参数表 函数体 完成函数功能的语句集合 返回值

函数定义语法形式 函数类型 函数名(形式参数表) { 函数体(变量声明和语句) return 表达式; }

函数定义 函数名 形式参数 函数类型 局部变量定义 float CircleArea (float r) { const float Pi = 3.1415; return Pi * r * r; } 函数类型 局部变量定义 函数体 返回值语句

(一般多以反映函数功能的单词组合命名,以增强程序的可读性) 函数名 函数名是这个独立代码段(函数体)的外部标识符 函数定义之后,即可通过函数名调用函数(函数体代码段)。 例: cout << CircleArea(MyRadius) << endl; 函数名的构成可以是任何有效标识符 (一般多以反映函数功能的单词组合命名,以增强程序的可读性)

Sum() // Sum(): compute sum of integers in a ... b int Sum(int a, int b) { int Total = 0; for (int i = a; i <= b; ++i) { Total += i; } return Total;

形式参数表 函数的形式参数表,简称形参表 形式: (类型1 形式参数1,…,类型n 形式参数n) 形式参数表示主调函数和被调函数之间需要交换的信息 (1)传给被调函数的待处理的数据; (2)控制被调函数操作执行的信息; (3)被调函数执行的结果。 形式参数表从参数的类型、个数、排列顺序上规定了主调函数和被调函数之间信息交换的形式。 如果函数之间没有需要交换的信息,也可以没有形参,形参表内写void或空着。

Sum() // Sum(): compute sum of integers in a ... b int Sum(int a, int b) { int Total = 0; for (int i = a; i <= b; ++i) { Total += i; } return Total;

PromptAndRead() // PromptAndRead(): prompt and extract next // integer int PromptAndRead() { cout << "Enter number (integer): "; int Response; cin >> Response; return Response; }

函数返回值 函数返回值类型规定了函数返回给主调函数的值的类型,也称为函数类型。 当需要函数向主调函数返回一个值时,可以使用return语句,将需要返回的值返回给主调函数,故称之为返回值。 需要注意的是由return语句返回的值的类型必须与函数定义时指定的函数返回值类型一致。 如果不需要向主调函数返回值,函数可以定义成无类型的,函数类型写成void,函数结束时也不必用return语句。

Sum() // Sum(): compute sum of integers in a ... b int Sum(int a, int b) { int Total = 0; for (int i = a; i <= b; ++i) { Total += i; } return Total;

函数体 函数体是实现函数功能的代码部分 从组成结构看,函数体是由程序的三种基本控制结构即顺序、选择、循环结构组合而成的。 变量声明 完成函数功能的语句两部分 从组成结构看,函数体是由程序的三种基本控制结构即顺序、选择、循环结构组合而成的。

Sum() // Sum(): compute sum of integers in a ... b int Sum(int a, int b) { int Total = 0; for (int i = a; i <= b; ++i) { Total += i; } return Total;

函数是由函数名、函数类型、形参表 和函数体四部分组成的,使用时通过 函数名和参数表调用函数.

例4.1 编写一个函数cube,计算整数的立方。调用函数cube计算从1到10相邻整数的立方差。

//计算整数的立方 #include <iostream> using namespace std; int cube( int ); // 函数原型声明 void main() { int last,nowcb; last=1; cout <<"the difference of cube: "<<endl; for ( int x = 2; x <= 10; x++ ) nowcb=cube( x ); cout <<nowcb-last << " "; last=nowcb; } cout << endl; //函数定义 int cube( int y ) { return y*y*y; }

例4.2 在三个浮点数中确定最大值,使用自定义函数maximum完成。

// 在三个浮点中找出最大值 #include <iostream> using namespace std; float maximum(float, float, float ); // 函数原型声明  void main() { float a, b, c; cout << "Enter three floating numbers: "; cin >> a >> b >> c; //调用maximum函数,a,b,c为实际参数 cout << "Maximum is: " << maximum( a, b, c ) << endl; //函数调用 } // maximum函数定义 // 函数的形式参数x,y ,z float maximum(float x, float y, float z) { float max; max = x>=y?x:y; max = max>=z?max:z; return max; }

2.函数原型 引用函数之前,要先指定函数的接口形式 函数原型声明格式: 函数类型 函数名(形式参数表); 函数定义 函数原型声明格式: 函数类型 函数名(形式参数表); 例: int Max(int a, int b)

函数原型 函数原型声明使编译器获得关于函数名称、函数类型、函数形参个数、形参类型和形参顺序的信息。 函数调用时,编译器根据函数原型声明验证函数调用正确与否。

函数原型 库函数的声明在相应的库的头文件中,使用库函数时要包含相应的头文件。 例: #include <cmath> 调用数学库函数: sqrt(…) sin(…) abs(…) …… fstream File stream processing assert C-based library for assertion processing iomanip Formatted input/output (I/O) requests ctype C-based library for character manipulations math C-based library for trigonometric and logarithmic functions

函数原型 程序中,如果调用自定义的函数,且函数定义在后,调用在先,则必须在调用函数之前有函数原型声明。 void subfun1(…);//原型声明 main() { ┆ subfun1(…);//函数调用 } void subfun1(…)//函数定义 …

函数原型 如果是函数定义在先,调用在后,则不必进行函数原型声明。因为编译器已经从函数定义得到关于函数的信息。 void subfun1(…)//函数定义 { … } main() ┆ subfun1(…);//函数调用

函数原型 源文件中,如果在所有函数定义体之外声明函数原型,则该函数可被位于其原型声明之后的所有函数调用。

void subfun1(…);//原型声明 main() { ┆ subfun1(…);//函数调用 } void subfun2() void subfun1(…)//函数定义 … main() { void subfun1(…);//函数原型声明 ┆ subfun1(…);//函数调用 } void subfun2() subfun1(…);//函数调用,┆ void subfun1(…) … 错误,编译器不识别sunfun1标识符。

3.return语句 return语句使程序执行流程从被调函数返回主调函数,有两种形式: (1) 不返回值的形式: return; (2) 返回值的形式 return 表达式;

例4.3 从键盘输入三角形的三个边长,计算三角形 的面积。

//给定三角形的三个边长,计算三角形的面积。 #include<iostream> #include <cmath> using namespace std;  void TriangleAreabySide(float a, float b, float c);  void main() { float a,b,c; cout<<"input three numbers of the triangle sides:"; cin>>a>>b>>c; TriangleAreabySide(a, b, c); }

//利用边长计算三角形的面积 void TriangleAreabySide(float a, float b, float c) { float area, s; if (a+b<=c || a+c<=b || b+c<=a ) cout<<"Not a triangle!"<<endl;; return; } else { s=(a+b+c)/2; area=sqrt(s*(s-a)*(s-b)*(s-c)); cout<<"area of the triangle("<<a<<","<<b<<","<<c<<"): "<<area<<endl;

例4.4 利用随机数产生函数rand()产生的随机数模拟 考试成绩,统计成绩的平均值。

//统计分数均值 #include<iostream> #include<cstdlib> #include <ctime> using namespace std;  int CalMean(int count);  void main() { int count;//数据个数 int mean;//均值   //输入数据 cout<<"input number:"; cin>>count; mean=CalMean(count); cout<<"mean= "<<mean<<endl; }

//计算均值 int CalMean(int count) { int score;//分数 int sum(0), mean;   srand( (unsigned)time( NULL ) );//种子   //累积求和 int k(0); cout<<"the scores:"<<endl;

while(k<=count) { score=rand()%100; if (score<10) continue; //假设没有低于10分的,舍弃此数据。 else cout<<score<<" "; sum+=score;//累积分数 k++;//累积个数 }

cout<<endl; //计算平均值 if(count>0) mean=sum/count; else mean=0; return mean; }

当被调函数只需要把一个数值结果返回给主调函数时,使用return语句返回比较合适。 如果使用return语句给主调函数返回一个值,则return语句必须返回一个与所在函数的函数类型一致的表达式。若表达式的结果与函数类型不一致,不能通过编译,需要作强制类型转换,将表达式的类型强制转换成与函数类型一致。 例如,如果函数是float型,则return语句应为: return (float)mean;

4.函数使用的三种方式(week 6) (1) 函数语句 函数语句形式: 函数名(实参数表); (1)    函数语句  函数语句形式: 函数名(实参数表);   例如:TriangleAreabySide(a, b, c);

实际参数表 实际参数表,简称为实参表 实参表是按与被调函数形参表一一对应的格式组织的参数表,即参数的类型、个数和排列顺序必须与被调函数声明的形参数表严格一致。 实际参数表的各实际参数以逗号间隔,实际参数可以是常量、变量和表达式(常量和变量都是最简单的表达式)。 在执行到函数调用语句时,由主调函数提供给被调函数的数据和控制信息的参数(视为输入参数)必须具有确定值。 如果被调函数无形参,则实参表也是空的。 实际参数以数据值(值传递)或实际存储空间(地址传递)提供了形式参数所需的内容。 实际编程中,从可读性考虑,一般使用变量(普通变量或指针变量)作实际参数。

调用无参数的函数 #include<iostream> using namespace std; void DisplayMessage(); void main() { DisplayMessage (); //函数调用语句 } void DisplayMessage () cout<<"只显示确定信息的简单函数不带参数"<<endl;

(2)函数表达式 函数调用出现在一个表达式中,其形式: 变量名=函数名(实际参数表); 或 变量名=带有函数调用的表达式 ; 这种表达式称为函数表达式,由函数名和实参表 组成。 此时函数要使用return语句向主调函数返回一个 确定的值,参与它所在的表达式的运算。

例4.5 编写程序,实现坐标旋转公式:

//实现坐标旋转公式 #include<iostream> #include <cmath> using namespace std;  void main() { const double PI=3.14; int x,y;//旋转后坐标 int x0,y0;//原始坐标 int angle; //旋转角度  

//输入数据 cout<<"input point(x,y):"; cin>>x0>>y0; cout<<"input angle of rotation:"; cin>>angle; //计算旋转后的坐标 double theta=angle*PI/180; x=x0*cos(theta)-y0*sin(theta); y=x0*sin(theta)+y0*cos(theta); //输出结果 cout<<"x="<<x<<endl; cout<<"y="<<y<<endl; }

注意: 当函数调用出现在表达式中时,函数一定要通过return语句返回一个与函数类型一致的值,作为这个函数表达式的值参与相关计算。

(3)函数参数 利用函数的返回值作实际参数,再作函数调用。 例如:m=max(a,max(b,c)); 实质上也是函数表达式形式调用的一种 。

上次课内容 函数定义、原型声明、函数调用 函数类型、形参、实参、返回值 函数调用的三种形式

4.3 函数调用

4.3 函数调用 函数调用的执行机制 值调用 嵌套调用 递归调用

1.函数调用的执行机制 系统在调用函数时,要在称为堆栈的特定内存空间中为函数建立一个活动记录 函数的活动记录存储 在函数内定义的变量和函数的形参 主调函数的断点地址 被调函数的返回值 (保存信息的具体内容与所使用的编译器有关) 活动记录是函数正常执行、调用和返回的物理基础

在程序执行过程中,如果遇到调用其它函数,则系统暂停当前函数的执行,将下一条指令的地址(返回地址,亦称断点地址)存入活动记录,流程转去执行被调函数。 系统为被调函数建立一个活动记录,被调函数的形参和在被调函数内定义的变量将存入它的活动记录。 当执行完被调函数时,系统撤销它的活动记录,流程重新回到主调函数,恢复其断点处的运行状态,继续执行程序的后序语句,直至结束。

void fun(…); void main() { ┆ fun(…); } void fun(…) return;

例4.6 从键盘输入屏幕上两点的坐标(x, y),计算两点 之间的距离。 (分析函数调用时活动记录 )

//计算两点之间的距离 #include<iostream> #include <cmath> using namespace std; float CalDistance(int x1, int y1, int x2, int y2); int square(int x);  void main() { int x1,y1,x2,y2;//两点坐标 float dist; //两点间距离  

//输入数据 cout<<"input point 1 (x1,y1):"; cin>>x1>>y1; cout<<"input point 2 (x2,y2):"; cin>>x2>>y2;   //计算距离 dist=CalDistance(x1,y1,x2,y2);   //输出结果 cout<<"distance between point ("<<x1<<","<<y1<<") and point ("<<x2<<","<<y2<<"): "<<dist<<endl; }

//计算距离 float CalDistance(int xx1, int yy1, int xx2, int yy2) {  //计算距离 float CalDistance(int xx1, int yy1, int xx2, int yy2) { int dx2,dy2; dx2=square(xx2-xx1); dy2=square(yy2-yy1); float dist=sqrt(dx2+dy2); return dist; }  //计算一个数的平方 int square(int x) return x*x;

运行结果: input point 1 (x1,y1):10 20 input point 2 (x2,y2):110 120 distance between point (10,20) and point (110,120): 141.421

void main() { int x1,y1,x2,y2;//两点坐标 float dist; //两点间距离 cout<<"input point 1 (x1,y1):"; cin>>x1>>y1; cout<<"input point 2 (x2,y2):"; cin>>x2>>y2;   dist=CalDistance(x1,y1,x2,y2);   cout<<"distance between point ("<<x1<<","<<y1<<") and point ("<<x2<<","<<y2<<"): "<<dist<<endl; }

cout<<"input point 1 (x1,y1):"; cin>>x1>>y1; void main() { int x1,y1,x2,y2;//两点坐标 float dist; //两点间距离 cout<<"input point 1 (x1,y1):"; cin>>x1>>y1; cout<<"input point 2 (x2,y2):"; cin>>x2>>y2;   dist=CalDistance(x1,y1,x2,y2);   cout<<"distance between point ("<<x1<<","<<y1<<") and point ("<<x2<<","<<y2<<"): "<<dist<<endl; } x1 y1 x2 y2

cout<<"input point 1 (x1,y1):"; cin>>x1>>y1; void main() { int x1,y1,x2,y2;//两点坐标 float dist; //两点间距离 cout<<"input point 1 (x1,y1):"; cin>>x1>>y1; cout<<"input point 2 (x2,y2):"; cin>>x2>>y2;   dist=CalDistance(x1,y1,x2,y2);   cout<<"distance between point ("<<x1<<","<<y1<<") and point ("<<x2<<","<<y2<<"): "<<dist<<endl; } x1 y1 x2 y2 dist

cout<<"input point 1 (x1,y1):"; cin>>x1>>y1; void main() { int x1,y1,x2,y2;//两点坐标 float dist; //两点间距离 cout<<"input point 1 (x1,y1):"; cin>>x1>>y1; cout<<"input point 2 (x2,y2):"; cin>>x2>>y2;   dist=CalDistance(x1,y1,x2,y2);   cout<<"distance between point ("<<x1<<","<<y1<<") and point ("<<x2<<","<<y2<<"): "<<dist<<endl; } x1 y1 x2 y2 dist

cout<<"input point 1 (x1,y1):"; cin>>x1>>y1; void main() { int x1,y1,x2,y2;//两点坐标 float dist; //两点间距离 cout<<"input point 1 (x1,y1):"; cin>>x1>>y1; cout<<"input point 2 (x2,y2):"; cin>>x2>>y2;   dist=CalDistance(x1,y1,x2,y2);   cout<<"distance between point ("<<x1<<","<<y1<<") and point ("<<x2<<","<<y2<<"): "<<dist<<endl; } x1 10 y1 20 x2 y2 dist

cout<<"input point 1 (x1,y1):"; cin>>x1>>y1; void main() { int x1,y1,x2,y2;//两点坐标 float dist; //两点间距离 cout<<"input point 1 (x1,y1):"; cin>>x1>>y1; cout<<"input point 2 (x2,y2):"; cin>>x2>>y2;   dist=CalDistance(x1,y1,x2,y2);   cout<<"distance between point ("<<x1<<","<<y1<<") and point ("<<x2<<","<<y2<<"): "<<dist<<endl; } x1 10 y1 20 x2 y2 dist

cout<<"input point 1 (x1,y1):"; cin>>x1>>y1; void main() { int x1,y1,x2,y2;//两点坐标 float dist; //两点间距离 cout<<"input point 1 (x1,y1):"; cin>>x1>>y1; cout<<"input point 2 (x2,y2):"; cin>>x2>>y2;   dist=CalDistance(x1,y1,x2,y2);   cout<<"distance between point ("<<x1<<","<<y1<<") and point ("<<x2<<","<<y2<<"): "<<dist<<endl; } x1 10 y1 20 x2 110 y2 120 dist

//计算距离 float CalDistance(int xx1, int yy1, int xx2, int yy2) { int dx,dy; dx=square(xx2-xx1); dy=square(yy2-yy1); float dist=sqrt(dx+dy); return dist; }  //计算一个数的平方 int square(int x) return x* x; xx1 10 yy1 20 xx2 110 yy2 120

//计算距离 float CalDistance(int xx1, int yy1, int xx2, int yy2) { int dx,dy; dx=square(xx2-xx1); dy=square(yy2-yy1); float dist=sqrt(dx+dy); return dist; }  //计算一个数的平方 int square(int x) return x* x; xx1 10 yy1 20 xx2 110 yy2 120 dx dy

//计算距离 float CalDistance(int xx1, int yy1, int xx2, int yy2) { int dx,dy; dx=square(xx2-xx1); dy=square(yy2-yy1); float dist=sqrt(dx+dy); return dist; }  //计算一个数的平方 int square(int x) return x*x; xx1 10 yy1 20 xx2 110 yy2 120 dx dy

//计算距离 float CalDistance(int xx1, int yy1, int xx2, int yy2) { int dx,dy; dx=square(xx2-xx1); dy=square(yy2-yy1); float dist=sqrt(dx+dy); return dist; }  //计算一个数的平方 int square(int x) return x*x; xx1 10 yy1 20 xx2 110 yy2 120 dx dy x 100

//计算距离 float CalDistance(int xx1, int yy1, int xx2, int yy2) { int dx,dy; dx=square(xx2-xx1); dy=square(yy2-yy1); float dist=sqrt(dx+dy); return dist; }  //计算一个数的平方 int square(int x) return x*x; xx1 10 yy1 20 xx2 110 yy2 120 dx dy x 100

//计算距离 float CalDistance(int xx1, int yy1, int xx2, int yy2) { int dx,dy; dx=square(xx2-xx1); dy=square(yy2-yy1); float dist=sqrt(dx+dy); return dist; }  //计算一个数的平方 int square(int x) return x*x; xx1 10 yy1 20 xx2 110 yy2 120 dx dy x 100

//计算距离 float CalDistance(int xx1, int yy1, int xx2, int yy2) { int dx,dy; dx=square(xx2-xx1); dy=square(yy2-yy1); float dist=sqrt(dx+dy); return dist; }  //计算一个数的平方 int square(int x) return x*x; xx1 10 yy1 20 xx2 110 yy2 120 dx 10000 dy

//计算距离 float CalDistance(int xx1, int yy1, int xx2, int yy2) { int dx,dy; dx=square(xx2-xx1); dy=square(yy2-yy1); float dist=sqrt(dx+dy); return dist; }  //计算一个数的平方 int square(int x) return x*x; xx1 10 yy1 20 xx2 110 yy2 120 dx 10000 dy

//计算距离 float CalDistance(int xx1, int yy1, int xx2, int yy2) { int dx,dy; dx=square(xx2-xx1); dy=square(yy2-yy1); float dist=sqrt(dx+dy); return dist; }  //计算一个数的平方 int square(int x) return x*x; xx1 10 yy1 20 xx2 110 yy2 120 dx 10000 dy x 100

//计算距离 float CalDistance(int xx1, int yy1, int xx2, int yy2) { int dx,dy; dx=square(xx2-xx1); dy=square(yy2-yy1); float dist=sqrt(dx+dy); return dist; }  //计算一个数的平方 int square(int x) return x*x; xx1 10 yy1 20 xx2 110 yy2 120 dx 10000 dy 10000

//计算距离 float CalDistance(int xx1, int yy1, int xx2, int yy2) { int dx,dy; dx=square(xx2-xx1); dy=square(yy2-yy1); float dist=sqrt(dx+dy); return dist; }  //计算一个数的平方 int square(int x) return x*x; xx1 10 yy1 20 xx2 110 yy2 120 dx 10000 dy 10000 dist 141.421

//计算距离 float CalDistance(int xx1, int yy1, int xx2, int yy2) { int dx,dy; dx=square(xx2-xx1); dy=square(yy2-yy1); float dist=sqrt(dx+dy); return dist; }  //计算一个数的平方 int square(int x) return x*x; xx1 10 yy1 20 xx2 110 yy2 120 dx 10000 dy 10000 dist 141.421

cout<<"input point 1 (x1,y1):"; cin>>x1>>y1; void main() { int x1,y1,x2,y2;//两点坐标 float dist; //两点间距离 cout<<"input point 1 (x1,y1):"; cin>>x1>>y1; cout<<"input point 2 (x2,y2):"; cin>>x2>>y2;   dist=CalDistance(x1,y1,x2,y2);   cout<<"distance between point ("<<x1<<","<<y1<<") and point ("<<x2<<","<<y2<<"): "<<dist<<endl; } x1 10 y1 20 x2 110 y2 120 dist 141.421

void main() { int x1,y1,x2,y2;//两点坐标 float dist; //两点间距离 cout<<"input point 1 (x1,y1):"; cin>>x1>>y1; cout<<"input point 2 (x2,y2):"; cin>>x2>>y2;   dist=CalDistance(x1,y1,x2,y2);   cout<<"distance between point ("<<x1<<","<<y1<<") and point ("<<x2<<","<<y2<<"): "<<dist<<endl; }

//计算距离 float CalDistance(int xx1, int yy1, int xx2, int yy2) { int dx2,dy2; dx2=square(xx2-xx1); dy2=square(yy2-yy1); float dist=sqrt(dx2+dy2); return dist; }  //计算一个数的平方 int square(int x) return x*x

2. 函数的参数传递(值调用) 函数之间的信息交换的一种重要形式是函数的参数传递,由函数的形式参数和实际参数实现。 函数在没有被调用时,函数的形式参数并不占有实际的内存空间,也没有实际的值。C++语言中函数的参数传递方式分为两种: 值传递 地址传递

值传递 如果函数的形式参数为普通变量,当函数被调用时,系统为这些形式参数分配内存空间,并用实际参数值初始化对应的形式参数,形式上实际参数的值传递给了形式参数。这就是函数调用时参数的值传递。 值传递方式,实际参数和形式参数各自占有自己的内存空间;参数传递方向只能由实际参数到形式参数;不论函数对形式参数作任何修改,对相应的实际参数都没有影响。

例4.7 如果一个数的所有真因子(包括1,但不包括这个数本身)之和正好等于这个数本身,则称此数为完美数。例如: 6=1×2×3,而 1+2+3=6; 28=1×4×7=1×2×14, 而 1+2+4+7+14=28。 如何确定完美数,欧几里得发现,只要2n-1是一个素数,则2n-1(2n-1)一定是一个完美数。编写程序找出最小的5个完美数。

2n-1 n++ Counter<5 Short n(2),counter(0) 2n-1为素数? 计算并输出: 2n-1(2n-1)

//寻找最小的五个完美数 #include <iostream> #include<cmath> using namespace std;  bool DecidePrime(unsigned int number); unsigned int power(unsigned int x, unsigned int y);  void main() { unsigned int perfect_number; unsigned int num,temp; short n(2); short counter(0);//计数器 

while (counter<5) { temp=power(2,n); num=temp-1; if(DecidePrime(num)) { perfect_number=temp/2*num; cout<<"n="<<n<<","<<"perfect number="<<perfect_number<<endl; counter++; } n++;

//计算指数 unsigned int power(unsigned int x, unsigned int y) { unsigned int mul(1); for(int i=1;i<=y;i++) mul*=x; return mul; }

 //判别素数 bool DecidePrime(unsigned int number) { unsigned int i, k; k=sqrt(number); for(i=2; i<=k; i++) //找number的因数 { if(number%i==0) break; } if(i>=k+1) //判断number是否被小于number的数整除 return true; else return false;

例4.8 从键盘输入两整数,交换次序后输出。

//演示函数参数值传递单向性的例程(week 7) #include<iostream.h> void swap(int a, int b); int main() { int x(5), y(10); cout<<"x="<<x<<" y="<<y<<endl; swap(x,y); return 0; } x 5 1024 y 10 1028 运行结果: x=5 y=10 a=10 b=5 x=5 y=10

void swap(int a, int b) { int t; t=a; a=b; b=t; cout<<“a="<<a<<" b="<<b<<endl; } a 5 10 2048 b 10 5 2052 t 5 2056

3. 嵌套调用 C++的函数不能嵌套定义 C++的函数可以嵌套调用

例4.9 编程计算一个空心圆柱体的体积。用函数 CylinderVolume()计算一个半径为r、高度为h 的圆柱体的体积:

//计算空心圆柱体的体积 #include <iostream> #include <string> using namespace std;  float DonutSize(float Outer, float Inner, float Width); float CylinderVolume(float Radius, float Width);  

void main( ) { cout<<"Outer edge donut radius:"; float OuterEdge; cin>>OuterEdge; cout<<"Hole radius: "; float InnerEdge; cin>>InnerEdge; cout<<"Donut thickness:"; float Thickness; cin>>Thickness;

//计算空心圆柱体的体积 cout<<endl<<"Size of donut with radius "<< OuterEdge<<endl; cout<<" hole radius "<<InnerEdge <<endl; cout<<" thickness "<<Thickness<<endl; cout<<" is "<<DonutSize(OuterEdge, InnerEdge, Thickness)<<endl; }  

//计算空心圆柱体体积 float DonutSize(float Outer, float Inner, float Width) { float OuterSize = CylinderVolume(Outer, Width); float HoleSize = CylinderVolume(Inner, Width); return OuterSize-HoleSize; }  //计算圆柱体体积 float CylinderVolume(float r, float h) const float pi=3.1415f; return pi*r*r*h;

例4.10 用弦割法求方程 在x=1.5 附近的根。

弦割法

解: 分析:设 ,

//用弦割法求方程的根。 #include<iostream> #include<cmath> using namespace std;   float function(float x); float xIntersection(float x1, float x2); float eqRoot(float x1, float x2);

void main() { float x0,x1,x; float y0, y1; do { cout<<"enter x0(1.5),x1:"<<endl; cin>>x0>>x1; y0=function(x0); y1=function(x1); } while(y0*y1>=0); x=eqRoot(x0,x1); cout<<"root :"<<x<<endl; }

float function(float x) { float y= (x - 1)*x*x -1; return y; }   float xIntersection(float x0, float x1) float y=(x0*function(x1)-x1*function(x0))/(function(x1)-function(x0)); return y;

float eqRoot(float x0, float x1) { float x, y, y0; y0=function(x0); do { x=xIntersection(x0,x1); y=function(x); if( y*y0>0) { y0=y; x0=x; } else x1=x; }while(fabs(y)>=0.000001); return x;

4.4 内联函数

4.4 内联函数 函数调用时,系统首先要保存主调函数的相关信息,再将控制转入被调函数,这些操作增加了程序执行的时间开销。 C++提供的内联函数形式可以减少函数调用的额外开销(时间空间开销),特别是一些常用的短小的函数适合采用内联函数形式。

内联函数 内联函数的定义形式: inline 函数类型 函数名(形式参数表) { 函数体 }

例4.13 使用内联函数求三个整数中的最大值。

//内联函数例 #include<iostream> using namespace std;  inline int max(int x, int y, int z) { return ((x>=y) ? (x>=z ? x : z) : (y>=z ? y : z)); } void main() int a,b,c; cout<<"enter three integers:" cin>>a>>b>>c; cout<<"Maximum is "<<max(a,b,c)<<endl; } 

内联函数之所以能够减少函数调用时的系统空间和时间开销,是因为系统在编译程序时就已经把内联函数的函数体代码插入到相应的函数调用位置,成为主调函数内的一段代码,可以直接执行,不必再转换流程控制权。 这样的结构,自然节省了时间和空间开销,但使得主调函数代码变长。 一般是只把短小的函数写成内联函数。

注意: (1)内联函数体不能包含循环语句、switch语句。 (2)内联函数要先定义,后调用。因为编译器需要用内联函数的函数体代码替换对应的函数调用。 如果内联函数不符合要求,编译器就将内联函数当一般函数处理。

4.5 重载函数

4.5 重载函数 重载函数也是函数的一种特殊情况。 C++允许几个功能类似函数同名,但这些同名函数的形式参数必须不同,称这些同名函数为重载函数。 例: int max(int x, int y){return x>y?x:y; } float max(float x, float y) {return x>y?x:y; }

各重载函数形式参数的不同是指参数的个数、类型或顺序彼此不同,不包括参数标识符的不同。如: ① int max(int a, int b){return a>b?a:b;} ② int max(int x, int y){return x>y?x:y; } ③ int max(int x, int y, int z) {return (x>y?x:y)>z? (x>y?x:y):z; } ①②实际是一个函数,如果写在同一个文件中,编译时会出现编译错误。若①③或②③在同一个文件中可形成重载函数。编译器将以形式参数个数的不同来认定和区分重载函数。

#include<iostream> using namespace std; int min(int x, int y) { return x<y?x:y; } double min(double x, double y) void main() int ia(10),ib(20); double da(0.1), db(0.5); cout<<"minimum of integer . is "<<min(ia,ib)<<endl; cout<<"minimum of double is "<<min(da,db)<<endl;

在使用重载函数时需要注意下面三点: (1)   编译器不以形式参数的标识符区分重载函数。例 int max(int a, int b); int max(int x, int y); 编译器认为这是同一个函数声明两次,编译时出错。 (2)   编译器不以函数类型区分重载函数。 float fun(int x,int y); int fun(int x,int y); 如果函数名和形式参数表相同,只是函数类型不同,编译器同样认为它们是同一个函数声明两次,编译出错。 (3)  不应该将完成不同功能的函数写成重载函数,破坏程序的可读性。

重载函数常用于实现功能类似而所处理的数据类型不同的问题,

4.6 默认参数值的函数

4.6 默认参数值的函数 具有默认参数值的函数是一种特殊的函数形式, C++允许函数的形式参数有默认值。 例如:计算圆面积的函数: double CircleArea(double radius=1.0) { const double PI=3.14; return PI*radius*radius; }

调用具有默认参数值的函数时,如果提供实际参数值,则函数的形参值取自实际参数;如果不提供实际参数值,函数的形参采用默认参数值。例如调用CircleArea函数: #include<iostream> using namespace std; void main() { cout<<CircleArea(10.0)<<endl; //提供实际参数值 cout<<CircleArea()<<endl; //不提供实际参数值 }

默认参数值函数如果有多个参数,而其中只有部分参数具有默认值,则这些具有默认值的参数值应该位于形参表的最右端。或者说,形参表中具有默认参数值的参数的右边,不能出现没有默认值的参数。例如: int CuboidVolume(int length=1, int width=1, int height=1); //正确 int CuboidVolume(int length, int width=1, int height=1); //正确 int CuboidVolume(int length, int width, int height=1); //正确   int CuboidVolume(int length=1, int width, int height=1); //错误 int CuboidVolume(int length, int width=1, int height); //错误 int CuboidVolume(int length=1, int width=1, int height); //错误

如果默认参数值函数是先声明,后定义的,则在声明函数原型时就指定默认参数值。 如果函数定义在先(无需原型声明),则在函数定义的形参表中指定默认值。

例4.14 编写具有默认函数值的函数,计算直角三角形的面积。

//使用默认形式参数值的函数编写计算直角三角形面积的程序 #include <iostream> using namespace std; float areaRATriangle( int side1 = 3, int side2 = 4); void main() { cout<< "The area of default right-angled triangle(3,4) is: “ << areaRATriangle()<<endl; cout << "The area of right-angled triangle(6,4) is:“ << areaRATriangle(6)<<endl; cout<< "The area of right-angled triangle(6,8) is:" << areaRATriangle(6, 8)<< endl; }

// 计算直角三角形面积 float areaRATriangle( int side1, int side2) { return side1* side2 /2.0; }

第4章 函数 已学过内容 函数定义、原型声明、函数调用 函数类型、形参、实参、返回值 函数调用的三种形式 函数调用的执行机制 第4章 函数 已学过内容 函数定义、原型声明、函数调用 函数类型、形参、实参、返回值 函数调用的三种形式 函数调用的执行机制 函数调用参数传递的值传递 内联函数、重载函数、默认参数值函数

实验 实验: 作业内容:题目,程序,运行结果 用学号作为文件名,打包发送到如下邮箱: Ucb_cjj@126.com 总结实验二、三,交试验作业 做实验四内容 作业内容:题目,程序,运行结果 用学号作为文件名,打包发送到如下邮箱: Ucb_cjj@126.com

本次课内容 内容 要求 4.7 全局变量与局部变量 4.8 变量的存储类型和生存期 4.9 编译预处理(自学) 掌握全局变量和局部变量的特点及使用 掌握标识符的作用域、可见性及生存期的概念 掌握变量的四种存储类型(auto ,register, extern ,static)的特点、异同及应用

4.7 全局变量和局部变量

4.7 全局变量与局部变量 在程序中,根据变量定义的位置编译器把它们分为局部变量和全局变量。在函数内部定义的变量、函数的形式参数为局部变量,在函数外部定义的变量为全局变量。 由于变量定义的位置不同,所以变量起作用的范围也不同。我们把程序中一个标识符起作用的范围称为其作用域。

局部变量 局部变量包括在函数体内定义的变量和函数的形式参数,它们的作用域就在函数体内,只能在本函数内使用,不能被其它函数直接访问。

#include <iostream> using namespace std; int fun1(int x, int y); int fun2(int x, int y); void main() { int a,b; cout<<"input a,b:" cin>>a>>b; cout<<fun1(a,b) <<endl; cout <<fun2(a,b) <<endl; } int fun1(int x, int y) { int n; n=x*x+y*y; return n; } int fun2(int x, int y) int m; m=x*x-y*y; return m;

局部变量 局部变量能够随其所在的函数被调用而被分配内存空间,也随其所在的函数调用结束而消失(释放内存空间),所以使用这种局部变量能够提高内存利用率。 同时,由于局部变量只能被其所在的函数访问,所以这种变量的数据安全性也比较好(不能被其它函数直接读写)。局部变量在我们实际编程中使用频率最高。

全局变量 一个C++的源文件(.cpp)可以由多个函数组成,我们可以在函数外部定义变量,即全局变量。 全局变量能够被位于其定义位置之后的所有函数(属于本源文件的)共用。也就是说全局变量起作用的范围是从它定义的位置开始至源文件结束。 全局变量的作用域是整个源文件。

#include<iostream> using namespace std; int maximum; int minimum; void fun(int x,int y int z) { int t; t=x>y?x:y; maximum=t>z?t:z; t=x<y?x:y; minimum=t<z?t:z; } void main() { int a,b,c; cout<<"input data a,b,c:"; cin>>a>>b>>c; fun(a,b,c); cout<<"maximum="<<maximum<<endl; cout<<"minimum="<<minimum<<endl; }

全局变量在程序执行的整个过程中,始终位于 全局数据区内固定的内存单元 如果程序没有初始化全局变量,系统会将其初 始化为0 在定义全局变量的程序中,全局变量可以被位 于其定义之后的所有函数使用(数据共享), 这给编程者带来很大方便 但也因此带来数据安全性和程序可读性不好的 缺点 在我们实际编程时一般不要随意使用全局变量

作用域 程序中标识符的作用域也就是标识符起作用的 范围,标识符只能在其起作用的范围内被使用。 程序中标识符的作用域也就是标识符起作用的 范围,标识符只能在其起作用的范围内被使用。 从标识符起作用的范围上划分,作用域主要分 为全局作用域和局部作用域两种。 从标识符在程序中所处的位置,又可区分作用 域为块作用域、函数作用域、类作用域和文件 作用域。

块作用域 块作用域是指标识符起作用的范围为块内范围,在块内定义的标识符具有块作用域。这个块,可以是复合语句的块,也可以是函数定义的函数体块。块内定义的局部变量的作用域是从变量定义起至本块结束。

t的作用域 a和b的作用域 c的作用域 #include<iostream> using namespace std; void main() { int a, b; cout<<"input a,b:" cin>>a>>b; if (a<b) { int t; t=a; a=b; b=t; } int c=a*a-b*b; cout<<a<<"*"<<a<<" - "<<b<<"*"<<b <<"="<<c<<endl; t的作用域 a和b的作用域 c的作用域

函数作用域 函数作用域 语句标号标识符的作用域为函数范围 函数体内定义的语句标号标识符具有函数作用域,即语句标号的作用域是其所在的函数范围。

文件作用域 文件作用域也即全局作用域,指标识符的作用域为文件范围。 在源文件所有函数之外声明或定义的标识符具有文件作用域,全局变量和函数名(不包括在其它函数内部声明原型的函数名)具有全局作用域,起作用的范围是从声明或定义点开始,直至其所在文件结束。

#include<iostream> using namespace std;   int counter1, counter2, counter3; char color; inline void getColor() { cout<<"input color of ball(r-red, y-yellow, g-green):"; cin>>color; }

void displayResult () { switch(color) case 'r': counter1++; cout<<"The number of red balls : "<<counter1<<endl; break; case 'y': counter2++; cout<<"The number of yellow balls : "<<counter2<<endl;

case 'g': counter3++; cout<<"The number of green balls : "<<counter3<<endl; break; default: } void main() { for(int k=0;k<10;k++) { getColor(); displayResult();

可见性 标识符的可见性,是研究标识符在其作用域内 能否被访问到的问题。 标识符在其作用域内,能被访问到的位置称其 为可见的, 标识符的可见性,是研究标识符在其作用域内 能否被访问到的问题。 标识符在其作用域内,能被访问到的位置称其 为可见的, 不能被访问到的位置称其为不可见的。

#include<iostream> using namespace std; double pi=3.1415926;   double BallVolume(double radius) { double volume=pi*radius*radius*radius*4/3; //此处使用的是全局变量pi return volume; }

double CircleArea(double radius) { double area=pi*radius*radius; //此处使用的是全局变量pi return area; }  float CircleArea( float radius) float pi=3.14f; float area=pi*radius*radius; //此处使用的是局部变量pi,全局变量pi在此处不可见。

 void main() { float r; cout<<"input radius: "; cin>>r; double dr=(double) r; cout<<"Ball volume: "<<BallVolume(dr)<<endl; cout<<"Circle area: "<<CircleArea(dr)<<"(double)"<<endl; cout<<"Circle area: "<<CircleArea(r)<<"(float)"<<endl; }

C++规定: 内层(局部变量)标识符与外层(全局变量)标识符同名时内层标识符可见,外层标识符不可见。 函数内,内层(块内)标识符与外层(在块前的局部变量) 标识符同名时内层标识符可见,外层标识符不可见。 对于变量也即内层变量屏蔽外层同名变量。

如果函数内的局部变量与全局变量同名,且在函数内一定要使用这个同名全局变量,可以用全局作用域符号(::)指定要访问的全局变量。

#include<iostream> using namespace std; double pi=3.1415926;   void BallVolume(double radius) { double volume=pi*radius*radius*radius*4/3; //此处使用的是全局变量pi cout<<"Ball volume: "<<volume<<endl; }  

void CircleArea( float radius) { float pi=3.14f; float area=pi*radius*radius; //此处使用的是局部变量pi,全局变量pi在此处不可见。 cout<<"Circle area: "<<area<<"(float)"<<endl; area=::pi*radius*radius; //此处使用的全局变量pi cout<<"Circle area: "<<area<<"(double)"<<endl; }  

void main() { float r; cout<<"input radius: "; cin>>r; BallVolume(r); CircleArea(r); }

关于标识符的使用 (1)标识符应该先声明,后使用。 (2)在同一作用域中,不能声明同名的标识符。 (3)对于两个嵌套的作用域,如果某个标识符在外层中声明,且在内层中没有同一标识符的声明,则该标识符在内层可见;如果在内层作用域内声明了与外层作用域中同名的标识符,则外层作用域的标识符在内层不可见。

4.8 变量的存储类型

4.8 变量的存储类型 一个变量在内存中存在的时间取决于变量的存储类型 C++程序中使用的变量可分为四种存储类型: auto register extern static

auto型变量 auto型变量包括函数体内部定义的局部变量、函数的形式参数,称为自动变量。

#include<iostream> using namespace std; int max(int x, int y) { return x>y?x:y; } void main() { int a,b; cout<<"input a,b:"; cin>>a>>b; cout<<max(a,b)<<endl; } auto int a,b;

自动变量因其所在的函数被调用而产生,随其所在的函数调用结束而消失。因为自动变量存放于动态存储区,不长时间占据固定内存,有利于内存资源的动态使用,故程序中大量使用的都是自动变量。

register型变量 寄存器型变量 定义格式: register 类型标识符 变量标识符; 例: register int counter; 访问寄存器中的变量要比访问内存中的变量速度快,但由于寄存器数量有限,如果设置过多的register型变量,编译器将把这些变量按普通局部变量处理,依然放在内存空间

extern关键字 多个源文件程序结构 在多文件程序结构中,如果一个文件中的函数需要使用其它文件里定义的全局变量,可以用extern关键字声明所要用的全局变量。 //file1.cpp int x,y; void main() { … } //file2.cpp extern int x,y; void fun() { … }

extern关键字 关键字extern提供了多文件程序结构中不同源文件共享数据的一个途径。但实际编程中,共享数据时要注意数据的安全性问题。

静态变量 声明变量时加上关键字static,则该变量为静态 变量,定义格式: static 类型标识符 变量标识符; 静态变量 静态局部变量 static加在局部变量的定义前,则生成静态局部变量 静态全局变量 static加在全局变量定义前,则形成静态全局变量 静态变量在程序运行期间一直在静态存储区占有 固定的存储空间

#include<iostream> using namespace std;   int squareMean(int data) { static int sum(0); static int counter(0); sum+=data*data; counter++; return sum/counter; } 

void main() { int number(1); while(number!=-1) cout<<"input number:"; cin>>number; cout<<"the mean of square is:"<< squareMean(number)<<endl; }

静态局部变量在其所在的函数第一次被调用时,被初始化为一定的值,系统仅对它们作一次初始化。 如果程序中指定初始化值,则初始化为程序指定值;如果程序在定义它们时未指定初始值,则系统将静态局部变量初始化为0。 此后静态局部变量能够保持其在前一次函数调用结束时所获得的值,直到下次函数调用时被修改。

静态全局变量 只能在其定义文件中使用,不能被多文件程序结构 的其它文件访问。 除此之外,静态全局变量在定义它的文件中的用法 与前面介绍的不加static的全局变量一样使用。 静态全局变量的数据安全性好于普通全局变量,但 不便于多文件程序结构不同文件之间的数据共享 实际编程时要根据具体问题决定是否加static。

生存期 一个变量在内存中存在的时间为变量的生存期。 不同存储类型的变量的生存期不同,按生存期可以将变量分为两种: 静态生存期变量 全局变量,静态变量 动态生存期变量 auto型变量,register型变量

生存期 具有静态生存期的变量在程序运行期间一直存在。 具有动态生存期的变量的取决于所在的函数是否被调用,函数被调用,动态生存期的变量存在;函数调用结束,动态生存期变量消失。

生存期 具有静态生存期的变量,如果定义时未指定初始值,则系统将它们初始化为0; 具有动态生存期的变量,如果未作初始化,则为随机值。在循环结构中,使用具有动态生存期的变量时,要特别注意是否需要先赋值的问题,例如迭代求和(和变量初始化为0)或乘积(积变量初始化为1)等。

总结 本章详细介绍了关于函数的知识,重点介绍了对函数的引入、定义、原型声明、函数的参数及函数调用,函数是实现算法的基本单位,函数的设计和使用是学习程序设计必须掌握的基本知识。 函数还有一些特殊的形式,如递归函数、内联函数、具有默认参数值的函数等。内联函数等函数的特殊形式,使我们在利用函数实现算法时更方便灵活。 本章介绍的变量的存储类型以及标识符的作用域等概念,也是我们必须掌握的基本知识。

作业 第4章习题:3,4,17

多文件结构 用C++编写处理比较复杂的问题的程序,一般采用多文件结构程序,即由多个源程序分别完成不同的子功能,这样的程序组织便于管理和维护。

多文件结构 在面向过程的程序设计中,为方便开发和维护程序,将程序的功能分成相对独立的子功能,然后用不同的源程序分别实现各个子功能。在实现每个子功能时,一般可使用两个源文件:一个是包含程序自定义类型、符号常量定义和函数的声明等的头文件(*.h文件),一个是由实现算法的函数构成的.cpp文件(即由函数定义构成的文件)。

例4.15 模拟投币的程序,每次结果应为正面或反面,打印HEADS或TAILS。让程序投币100次,计算每面出现的次数并打印结果。程序应调用一个Flip函数,该函数无参数,返回0表示正面,1表示反面。如果程序真实,模拟投币,则每一面出现的次数应近似相等。

//Mainprog.cpp //模拟投币程序 #include<iostream> #include <cstdlib> #include <cstdio> #include <ctime> #include"flip.h" using namespace std;

 void main() { cout<<"now let's begin:"<<endl; int k(1); int Hcounter(0),Tcounter(0); srand( (unsigned)time( NULL ) );

 while(k<=100) { if(!Flip()) { cout<<"HEADS(k="<<k<<") "; Hcounter++; } else { cout<<"TAILS(k="<<k<<") "; Tcounter++; if(k%4==0) cout<<endl; k++;

cout<<"total:"<<k-1<<endl;    cout<<"total:"<<k-1<<endl; cout<<"HEADS:"<<Hcounter<<endl; cout<<"TAILS:"<<Tcounter<<endl; }

#include <cstdlib> #include <cstdio>   //Flip.cpp //投币 #include <cstdlib> #include <cstdio> #include <ctime> #include"flip.h" using namespace std; int Flip() { return rand()%2; } //flip.h int Flip();

在多文件结构程序中,函数的声明和函数定义、使用分别放在. h文件和 在多文件结构程序中,函数的声明和函数定义、使用分别放在*.h文件和*.cpp文件中,使用时要在cpp文件的最开始使用include将要用的头文件包含进来。

4.9 编译预处理

4.9编译预处理 编译器在编译源程序之前,先由预处理器处理预处理指令

预处理命令 #include 格式 #include<头文件名> #include“头文件名” 功能 将一个头文件嵌入(包含)到当前文件

预处理命令 #define 格式 #define 标识符 字符串 功能 把字符串命名为标识符(用标识符代表字符串) 标识符可以表示符号常量或宏名,编写源程序时 代替”字符串”出现在程序中,编译时又被替换 为”字符串”内容。

预处理命令 #undef 格式 #undef 标识符 功能 撤销前面用#define定义的标识符

预处理命令 #ifdef 格式 #ifdef 标识符 语句 #endif 功能 如果已定义了“标识符”,则编译“语句”

预处理命令 #ifndef 格式 #ifndef 标识符 语句 #endif 功能 如果未定义了“标识符”,则编译“语句”

预处理命令 #if #elif #else #endif 功能 条件编译指令,如果某个表达式成立,则编译相应 的语句。几种形式是: #if-#endif、 #if-#else-#endif、 #if-#elif-#elif-…#endif

预处理命令 #if #elif #else #endif 格式 #if 常量表达式 语句 #endif

预处理命令 #if #elif #else #endif 格式 或: #if 常量表达式1 语句1 #else 语句2 #endif

预处理命令 #if #elif #else #endif 格式 或: #if 常量表达式1 语句1 #elif常量表达式2 语句2 ┇ #else 语句n #endif

课堂练习 编写一个将华氏温度转换为摄氏温度的程序,转换公式为C=(5/9)(F-32),要求输出华氏温度和摄氏温度的对应值。 读程序段写结果。 (1)intx=6,y; cout<<x<<endl; y=++x; cout<<x<<y<<endl; x=6,y=x++; x=6,y=x--; cout<<x<<y<<endl; x=6,y=--x;

cout<<a<<endl; (3) int a=3,b=4,c=5,x,y; x=(a+b>c&&b==c); cout<<x<<endl; x=(a||b+c&&b-c); x=!(a>b&&!c||1); x=(!(a+b)+c-1&&b+c/2); !(x=a)&&(y=b)&&0; cout<<x<<y<<endl; (2)int a=10,b=4; a+=a*=a-=a/b; cout<<a<<endl;