当前位置:首页 >> 理学 >> C++程序设计谭浩强第1-12章课件

C++程序设计谭浩强第1-12章课件


C++语言程序设计
学习目的:
1. 程序设计是计算机及其相关专业学生必备的技能之一。 2. 通过本课程的学习, 不仅要使学生掌握用 C 及 C++语言进行编程的基本方法 和技能,同时还要培养学生进行面向过程程序设计的抽象逻辑思维能力和良好 的程序设计风格。

学习方法和特点
从三个方面进行技能培养的要求:掌握基本知识;大量阅读实例;编写程 序实践。 1. 注重实例的阅读和理解; 2. 注重实践课的学习; 3. 注重自学能力的培养(提倡:以学为主,以教为辅) 。

学习要求
1. 做好理论课前、课后的预习和复习 2. 做好实习课前、课后的准备和总结 3.阅读参考书籍: C 语言程序设计 C 程序设计实践 谭浩强 (美)H.M.Deitel 等著

C++程序设计教程 (美)H.M.DEITEL 等著

1

第一章 C++初步知识
1.1 从 C 到 C++
一、程序设计语言
程序设计语言是人们用来编写程序,为计算机能够接受并理解的语言。他通常是一个能够完整准确表达人的意图,并赖 以控制计算机实现给定运算的符号系统。他是人与计算机进行信息交流的重要工具。 程序设计语言一般分为三大类:面向机器的语言、面向过程的语言和面向对象的语言。 如:FORTRAN、BASIC、 ALGOL、 Pascal、 COBOL、 C 等

二、C++的产生和特点(P1~4) 1、C 语言特点:一种通用的、结构化的程序设计语言。
①简洁、紧凑、灵活。 ②模块化、结构化。 ③移植性强。

2、C++的产生 3、C++的特点
? C++全面兼容 C ? 程序可读性更好、结构更合理 ? 更高质量的代码 ? 更强的软件开发效率 ? 支持面向对象的机制

2

1.2 最简单的 C++程序(P5~11)
例 1.1 输出一行字符

#include <iostream> //包含头文件 iostream using namespace std; //使用命名空间 std int main() { cout<<"This is a C++ program."; return 0; }
程序说明: ①每个以“#”开头的行,称为编译预处理行。#include 是编译预处理命令。 ②using namespace std; 使用命名空间 std ③main( )代表“主函数“的名字。每个 C++程序必有一个 main( )主函数(也只能有一个)。程序的执行就是 从这里开始的。 其中:int main( ) 表明将 main( )函数的返回值类型声明为:int 整型, 在函数体中与之配合的语句: return 0;

④花括号{}部分构成主函数的函数体。 ⑤Cout 与“<<“ (插入运算符)配合使用,表明将其后的信息输出到系统指定的设备中; ⑥ //其后的内容代表注释信息 ⑦ 每个语句末尾均以“ ; ”结尾

例 1.2 求任意两个整数之和

#include <iostream> using namespace std; int main()
3

{ int a,b, sum; cin>>a>>b; sum=a+b; cout<<"a+b="<<sum<<endl; return 0; }
程序说明: ①int a,b, sum; 变量声明语句 ②cin 与“>>”提取运算符 ③endl 表示本行结束换行

例 1.3 求任意两个整数中的较大数

#include <iostream> using namespace std; int max(int x,int y) { int z; if(x<y) z=x; else z=y; return(z); } int main()
4

{

int a,b,m; cin>>a>>b; m=max(a,b); cout<<"max="<<m<<endl; return 0;

}
程序说明:

1.3 C++程序的构成和书写形式 (P12~13)
通过以上三个简单的 C++程序,可大致归纳出 C++程序结构具有以下特点:

①C 的程序结构是由注释、编译预处理和程序主体组成; ②C++程序是由函数构成的。一个 C++程序必须有且仅有一个名为 main 的主函数,C++程序的执行总是从 main 函数开始(无论 main 函数在程序中的位置
如何) 。

③一个函数由函数首部和函数体两部分组成。 ④C++程序书写格式自由。 ⑤C++语句包括两类:声明语句、执行语句 ⑥可用“//”对 C++程序中任何部分做注释。

1.4 C++程序的开发过程 (P14~15)
C++语言是一种高级程序设计语言,它的开发过程与其他高级语言程序开发过程类似,一般要经过以 下几个步骤:

1. 编辑(用 C++语言编写程序是指把按照 C++语法规则编写的程序代码通过编辑器
5

(Visual C++ 6.0)输入计算机,并存盘。在存盘时,C++源文件的扩展名为 .CPP。

2. 编译
将编辑好的 C++源程序通过编译器转换为目标文件(.obj 文件) 。即生成该源文件的目标代码。

3.链接
将用户程序生成的多个目标代码文件(.obj)和系统提供的库文件(.lib)中的某些代码连接在一起, 生成一个可执行文件(.exe) 。

4. 执行
把生成的可执行文件运行,在屏幕上显示运行结果。用户可以根据运行结果来判断程序是否出错。

5. 分析运行结果

1.5 关于 C++的上机实践 (P15)
作业:3,5,6,7,8,9

第二章 数据类型与表达式 2. 1 C++数据类型(P19~21) int

1.整数类型
整数类型的标识符是 。计算机中整型数据的取值范围是数学中整数集中的一个有限子集。对 于不同的计算机系统,这个有限子集是不同的,他与计算机分配给整数所占的存储空间有关。 整型数据根据其所占用的内存字节数不同,还可以加限定词:

short (短) 、 long (长) 、

unsigned(无符号) 2.实数类型
实数类型(又称做浮点数据类型)分为单精度 (float) 、 双精度 (double)类型和长双精度(long

double)其区别在于所占存储位的多少。从而决定了其取值的范围。
6

3.字符类型
字符类型的标识符为 chat

。一个字符型数据只能是一个单个

字符,且必须用一对单引号括起来。通常在内存中占用一个字节,
用来存储该字符对应的 ASCII 码值(无符号整数) 。
注:仔细阅读 P20 中的表及关于各种类型的说明

2.2 常量
常量是指在程序的执行过程中其值不能被改变的量。 常量 具有类型属性, 类型决定了各种常量在内存中占据存储空间的 大小。 一、数值常量 (常数) 1.整型常量(三种形式) (P21) 十进制常量:一般占一个机器字长,是一个带正负号的常数(默认情况下为正数) , 如: +3,-7 等。 八进制常量:由数字 0 开头,其后由若干 0~7 的数字组成, 如 :0376 代表(376)8,0123 代表(123)8 等。 十六进制常量:以 0x 开头,其后由若干 0~9 的数字及 A~F(或小写 a~f)的字母组成, 如:0x173 代表(173)16,0x 代表(3af)16。 在 C++中,一个整型数据没有任何说明,表示 int 型,也 可在整型常量后跟字母 l 或 L 表示 long 型(长整数) ,也可以 跟 u 或 U 表示 unsigned 整数(无符号整数) 。 如以下数是合法的: 375u //无符号整数 12345UL
7

//无符号长整数 54321L 13579ul
注:整数在内存中的存储形式: “位” ( bit) :计算机内存储器的最小存储单位,用于存放二进制数 0 或 1; “字节” (byte) :由 8 个二进制位组成; “字” (word) :由若干个字节组成(随机器而不同,如 16 位机,即 16 位二进制作为一个字) ,用于存放 一条机器指令或一个数据。 在 C 中一个 int 整数通常用 2 个字节存放:其中最高位(最左边的一位)用来存放整数的符号(0 表示正 整数) 。

//长整数 //无符号长整数

2. 实型(浮点型)常量(两种形式) (P22) 十进制形式:由数字和小数点组成。小数点的左右至少一边要有数字。 如:21.5 ,.25,4.0,4. ,等都是合法的。 科学科学记数法(指数计数法) :由尾数、e 或 E 和指数部分组成,E 的两边都至少
要有一位数且 E 的右边只允许是整数形式。

如:3.0E+5,4E-5,.4E-5,4.E-2
而下列数据在 C 中是不合法的实型数据:

等都是合法的;

4.0E .E+4 0.35E2.4 E-2

(E 的右边没有数字) (小数点的两边都没有数字) (E 的右边即指数部分不是整数) (E 的左边没有数字)

注:实型数据存在有精确度问题: float 型提供 6 位有效数字; (Visual C++6.0) double 型提供 15 位有效数字; (Visual C++6.0)

在 C++中,一个实型数据没有任何说明,表示 double 型。 要表示 float 型数,则必须在实数后加上 f 或 F。
8

例如:

26.7f 26.7

//float 型 //double 型(默认表示)

二、字符型常量(P23) 1.普通字符常量 字符常量是由一对单引号括起来的一个单一字符。 如: ‘A’ , ‘S’ , ‘*’ 如: cout<<‘a‘; 2. 转义字符常量
除以上形式的字符常量外,C++中还允许使用一种特殊形式的字符常量。即以“\“开头的字符序列。 如: ‘\n’代表一个换行符,见 P24 表 2.2

等,在内存中占一个字节。

转义字符的含义是:将反斜杠“\“后面的字符转变成另 外的意义 3. 字符数据在内存中的存储形式及其使用方法 一个字符型数据通常在内存中占用一个字节, 用来存储该 字符对应的 ASCII 码值(无符号整数) 。
例如:

字符‘A’的 ASCII 码值为 65,在计算机内部的存储形式如下图所示: 0
再例如:

1

0

0

0

0

0

1

字符‘5’的 ASCII 码值为 53,在计算机内部的存储形式如下图所示 0 0 1 1 0 1 0 1

C++中的字符型数据与整型数据之间可以通用,其中间转 换在于:ASCII 字值。
9

例 2.1 将字符赋给整型变量 #include <iostream> using namespace std; int main ( ) {

int i,j; i='A'; j='B'; cout<<i<<' '<<j<<'\n'; return 0;
} : 65 66 例 2.2 字符型数据与整数进行算术运算 #include <iostream> using namespace std; int main() { char c1,c2;
运行结果

cout<<‖请输入两个小写字母:‖; cin>>c1>>c2; c1=c1-32; c2=c2-32;
10

cout<<c1<<' '<<c2<<endl;
return 0; }
运行结果:

AB
注:实现大小写字母的转换

4.字符串常量 (P26) 字符串常量是由一对双引号括起来的字符序列。 例如: “How do you do?” “I am a student.” “hello” 字符常量和字符串常量是不同的。 在 C++中, 字符串常量 总是以‘\0’结束。
例:一个字符串“HELLO” ,则他在内存中的表示为连续 6 个内存单元。 H E L L O ‘\0’

说明:一个字符占一个内存单元,含有一个字符的字符串占有 2 个内存单 元,其中,第二个内存单元存放\0 结束符。 (因此, “0”与‘0’是不同的) 分析如下字符串的输出: cout<<”abc\\\n”<<endl; cout<<”I say:”Thank you!\”\n”;
\\ abc\ \\ I say:‖Thank you!‖

cout<<‖I say:\‖Thank you!\‖‖
三、符号常量(P27)
11

C++允许用定义一个符号名的方法来代表一个常量 案例 2.3 计算圆面积和周长

#include<iostream> using namespace std; #define PI 3.14159 int main() { double r,s,l; r=5.0; s= PI *r*r; l=2* PI *r; cout<<‖s=‖<<s<<‖ retuen 0; }
注意:在#define 命令行后面不加分号。

―<<l=‖<<l<<endl;

定义“符号名常量”的意义: 便于对程序的阅读、 维护与修改。

2.3 变量(P27)
一、变量的概念 变量是指程序在运行过程中,其值可以被改变的量。每个变
量由一个变量名惟一标识,同时,每个变量又具有一个特定的数据类型。不同类型的变量在内存中占有存 储单元的个数不同。变量的值可以通过赋值的方式获得和改变。 分析 P27 图 2.6 理解变量名与变量值的概念。

12

二、变量名命名
变量名的命名要遵守以下规则:

? 不能是 C++保留字。 ? 第一个字符必须是字母或下划线,中间不能有空格。 ? 变量名除了使用 26 个英文大小写字母和数字外, 只能使用下划线。 ? 一般不要超过 32 个字符。 ? 变量名不要与 C++的库函数名、类名和对象名相同。 ? 符合标识符的命名规则,并且避免使用关键字;? ? 见名知义、提高可读性;?
例如, 合法的变量名: 不合法的变量名:

a123

c3b ¥50

file_1 a<b 3x

J.Agate

注:C++对大小写是敏感的,即 DATE 与 date 被认为是两个不同的变量名。 注:标识符是指由字母(a~z,A~Z) 、数字(0~9)和下划线(_)组成,并且第一个字符必须为字母或下 划线开头的一系列字符。其作用是用来表示:变量名、符号名、函数名、文件名、数组名等。

三、变量定义和说明(P28) C++规定,任何变量在使用之前一定要定义或说明其数据 类型, 以便为其分配相应数量的存储单元, 用来存放相应的值。
变量定义的一般格式为: 例如:

变量类型

变量名表列;

int x,y,sum; float a,b,aver;
13

char name,ch;
注:多个同一类型的变量可以在一行中定义,中间用逗号隔开,也可以分别定义

例如: 和

int a,b,c;

//定义 3 个整型变量 a,b,c

int a; int b; int c;
四、变量初始化

//定义整型变量 a

//定义整型变量 b
//定义整型变量 c

二者等价。注:关于变量说明语句的位置 C 与 C++有所区别。

C++允许在变量定义的同时为其赋初值(初始化)
例如:

int a=3; float b=3.4;

分析如下程序段的结果:

int a=3,b; cout<<a<<‖ ―<<b<<endl;
五、常变量(*C++新增)(只读变量)(P30) 1.const 的一般形式

const
例如:

数据类型名 常变量名=表达式;
float PI=3.14;

const

比较如下两段程序,分析 define 的不安全性
14

int a=1; #define t1 a+a //预定义 #define t2 t1-t1 cout<<"t2 is "<<t2<<endl; 输出: t2 is 2
用 const 替代 define

int a=1; const t1=a+a; //常变量定义语句 const t2=t1-t1; cout<<"t2 is "<<t2<<endl; 输出: t2 is 0
说明:常变量与符号常量的区别

2.4

C++运算符及表达式 (P32)
运算是对数据进行加工的过程,用来表示各种不同运算的符号称为运

算符。参加运算的数据称为运算量、运算对象或操作数。用运算符把运
算量连接起来的式子称为运算表达式,简称表达式。
注: C++语言的运算符按其在表达式中与运算对象的关系(连接运算对象的个数)可分为: ? ? ? 单目运算(一元运算符,只需一个操作数) 双目运算(二元运算符,需两个操作数) 三目运算(三元运算符,需三个操作数)

一、算术运算符和算术表达式
15

(P32) 1.基本算术运算符 基本算术运算符除了负值运算符外都是双目运算符, 即是 指两个运算量之间的运算。取负值运算符是单目运算符。 ???+ ??? ? ? ?
说明: (加法运算符,或正值运算符,如 1+2,+3) (减法运算符,或负值运算符,如 1-2,-3)

* / %

(乘法运算符,如 1*2) (除法运算符,如 1/2)
(模运算符或称求余运算符,如 7%3=1)

①关于除法运算:两个整数相除的结果仍为整数。
例如:7/4 的结果值为 1,舍去小数部分。 如果参加运算的两个数中有一个为实数,则结果是 double 型。

②关于求余运算:关于求余运算也叫模运算,求余运算符两侧的运 算量必须都是整型,其结果值是两数相除所得的余数。一般情况下,
所得余数与被除数符号相同。 例如:7%4=3

,10%5=0 ,-8%5=-3

,8%-5=-3

③关于实型数运算: 在 C++中, 所有实型数的运算均以双精度 方式进行(若是单精度数,则在尾数部分补 0,使之转化为双精度数) 2.自增、自减运算符 (P33)

自增、自减运算符是单目运算符,即仅对一个运算量施加运算,运算 结果仍赋予该运算量。参加运算的运算量必须是变量。
16

运 算 符 ++ -说明:









等 价 于 x=x+1 x=x-1

加1 减1

x++ 或 ++x x- - 或 - -x

从表中可以看出,自增、自减运算符可以用在运算量之前(如:++a 或—a,称为前置运算) ,也可放 在其后(如 a++或 a--,称为后置运算) 。

对一个变量实行前置运算或后置运算,其运算结果是一样的,即都使 变量的值加 1 或减 1。但当前置运算或后置运算出现在一个表达式中时, 这两种运算的用法是不同的,其区别表现为:前置运算 (++a
或—a)是变量的

值首先加 1 或减 1,然后再以该变量变化后的值参加其他运算。

例如:比较以下两段程序 x=4; y=6; z=y-(++x) ; ( a)
案例 2.4 观察自增、自减运算符

x=4; y=6; z=y-(x++) ; ( b)

#include<iostream> using namespace std; int main() { int a=0,b=0; a++;
17

b--; cout<<a<<‖,‖<<b<<endl; cout<<a++<<‖,‖<<b--<<endl; cout<<++a<<‖,‖<<--b<<endl; return 0; }
运行情况: 1,-1 1,-1 3,-3

3.算术表达式及算术运算符的优先级、结合规律
用算术运算符、圆括号将运算对象(或称做操作数)连接起来的符合 C++语法规则的式子,称为 C++ 算术表达式。其中运算对象可以是常量、变量、函数等。

优先级:是指当一个表达式中如果有多个运算符时,则计算是有先后次序的,这种计算的先后次序称
为相应运算符的优先级。

结合性:是指当一个运算对象两侧的运算符的优先级别相同时,进行运算(处理)的结合性,按“从
右向左”的顺序运算。称为右结合性;按“从左向右”的顺序运算。称为左结合性。

算术运算符的优先级和结合性 运 算 种 类 结 合 性 优 先 级 高

++,--,-(取负) *,/,% +,-

从右向左 从左向右 从左向右



在算术表达式中,若包含不同优先级的运算符,则按运算符的优
18

先级别由高到低进行;如表达式中运算符的优先级别相同时,则按运算符 的结合方向(结合性)进行。
C++语言中表达式的书写与数学中表达式的书写形式是有区别的,在使用时要注意以下几点:

①C++表达式中的乘号不能省略。
例如:

数学式 b2-4ac
例如:

相应的 C 表达式为:

b*b-4*a*c

②C++表达式中只能使用系统允许的标识符。 数学式 ∏r2 相应的 C 表达式为:3.14159*r*r

③C++表达式中的内容必须书写在同一行,不允许有分子分母 形式,必要时要利用圆括号保证运算的顺序。
例如:

数学式

a+b c+d

相应的 C++表达式为: (a+b)/(c+d)

④C++表达式不允许使用方括号和花括号,只能使用圆括号帮 助限定运算顺序。可以使用多层圆括号,但左右括号必须配对,运算时从内层圆括号开始,
由内向外依次计算表达式的值。

二、赋值运算符与赋值表达式(P36) 1.赋值运算
赋值符号“=”就是赋值运算符,由赋值运算符组成的表达式称做赋值表达式。

其一般形式为:

变量名=表达式
赋值的含义是:将其右侧的表达式求出结果值存放入以左侧变量
19

名为标识的存储单元中。
例如:

int i; i=3*(4+5)
//i 的值变为 27

说明:

①赋值运算符的左边必须是变量, 右边的表达式可以是单一的 常量、变量、表达式和函数调用语句。 例如:下面都是合法的赋值表达式 x=12 y=x+30 z=func() ②赋值符号“=”不等同于数学中使用的等号,它没有相等的 含义。

例如:

x=x+1

是合法的赋值表达式,其含义是取出变量 x 中的值加 1 后,再存入变量 x 中去

③赋值运算符的结合性是从右至左的,因此,C++程序中可以 出现连续赋值的情况。
例如,下面的赋值是合法的:

int i,j,k; i=j=k=10; a=b=3+2

//i,j,k 都赋值为 10

相当于: i= (j= (k=10) ) 相当于: a=(b=3+2)

④在进行赋值运算时,当赋值运算符两边的数据类型不同时, 将由系统进行自动类型转换。转换的原则是:赋值运算符右边 的数据类型转换成左边的变量类型。 若右边是实型类型转换成
20

整数型时,去掉小数部分;若右边是双精度型转换成单精度型 时,则进行四舍五入处理。
例如:

int i=1.2*3;

//结果为 3,而不是 3.6

阅读 P36~37 理解在赋值过程中的类型转换注意事项

例 2.5 将有符号数据传送给无符号变量(P37)

#include <iostream> using namespace std; int main() { unsigned short a; \\定义 a 为无符号的短整型变量 short int b=-1; \\定义 b 为短整型变量 a=b; cout<<"a="<<a<<endl; return 0; } 运行结果:65535
2.复合赋值运算符(P38)
为了简化程序并提高编译效率。C++允许在赋值运算符“=”之前加上其他运算符,以构成复合赋值 运算符。

其一般形式为:

变量 双目运算符=表达式
等价于:

变量=变量双目运算符 表达式
例如:
21

i+=5 x*=y+8
一共有 10 种,即:

等价于 等价于

i=i+5 x=x*(y+8)

C++规定,所有双目运算符都可以与赋值运算符一起组合成复合运算符。

+=(加赋值) , -=(减赋值) , *=(乘赋值) , /=(除赋值) , %=(取模赋值) ,
算术复合赋值运算符 运 算 += -= *= /= %= 符 名 称 例 子 等 价 x=x+y x=x-y x=x*y x=x/y x=x%y 于

加赋值 减赋值 乘赋值 除赋值 取模赋值

x+=y x-=y x*=y x/=y x%=y

说明:复合赋值运算符在应用时,要注意将右边的表达式看成

是一个整体参加运算。 例如: x*=y+1 例如: 等价于 x=x*(y+1) 而不是 x=x*y+1

int a=12; a+=a; 表示 a=(a+a)=(12+12)=24; 例如:int a=12; a+=a-=a*=a;
22

表示:a=a*a

a=a-a a=a+a

//a=12*12=144 //a=144-144=0 //a=0+0=0

三、逗号运算符与逗号表达式(P40)
逗号运算符即“, ” ,可以用于将若干个表达式连接起来构成一个逗号表达式。

其一般形式为:

表达式 1,表达式 2,??,表达式 n
求解过程为: 自左至右,先求解表达式 1,再求解表达式 2,?,最后求解表达式 n。 表达式 n 的值即为整个逗号表达式的值。

例如:

3+4,9-5

逗号运算符在所有运算符中的优先级别最低,且具有从左 至右的结合性。他起到了把若干个表达式串联起来的作用,所以又称为
“顺序求值运算符”

a=3*4,a*5,a+10 或 (a=3*4,a*5),a+10 又例如: x=10-5,10/5 与 x=(10-5,10/5)
例如:
需要注意的是, 并不是在任何地方出现的逗号都是作为逗号运算符。 很多情况下, 逗号仅作为分隔符, 如变量之间、函数之间等都是用逗号作为分隔符。

例如: int x,y,z 2.6 类型转换 一.自动类型转换(P33)
当混合数据类型出现在同一个表达式(特别时算术表达式)中时,C++就会自动地将不同类型的数据 转换成同一类型,然后再进行计算。转换的规则如下图所示:

23




说明:

double long unsigned int

float

chat,shot

①图中横向向左的箭头表示必定的转换,即在运算之前 char 和 short 类
型的数据必须先转换成 double 类型(即使示两个 short 类型的数据相加, 也要先转换成 int 类型,然后再进行计算,结果为 int 类型)

②图中纵向的箭头表示当参加运算的数据为不同类型时才进行的转 换,转换的方向为由低向高级。 ③纵向箭头的方向仅表示数据类型级别的高低,不表示需要逐级转换。
例如:

int i; double x,y; i=4.6 x=0.96; y=x+i;

因 i 的类型(int)的级别低于 x 的类型(double)的级别,C++会自动将 i 的类型直接转换为 double (而不是先转换成 unsigned,再转换成 double)

混合数据类型的表达式按照上述规律进行类型转换后, 方可进行计算, 其结果的数据类型与较高级别的类型一致。
此外,在赋值语句中,赋值号(=)右边的类型会转换成左边的类型,其结果也是左边的类型。 需要注意的是,当左边变量的数据类型比右边表达式的值的类型级别高时(如,int 型转换成 float 型 或 float 型转换成 double 型) ,这种转换并不增加精度或准确度,但是改变值的表示形式;反过来,当右 边表达式的值的类型比左边变量的类型级别高时,这种转换时将右边的数据截取低位所需的长度,这种类
24

型转换会丢失高位字节,因此可能引起精度降低或出现错误结果。

二、强制类型转换(显式类型转换)(P35)
在 C++中,可以在任何表达式中用一个叫做类转换(cast)的形式来 强制对数据进行类转换。 强制类型转换的一般形式为:

(类型名)表达式
类型的显式转换可以将―表达式‖转换成适当的类型。

\\C 格式类型名(表达式 )

\\C++新增格式其中:―类型名‖可以是 C++中的任何合法的数据类型,例如 float、int 等。通过
例如:

double f=3.6; int n=(int)f;

这样 n 为 3。 需要注意的时,无论时自动类型转换还是强制类型转换,仅仅是为了 本次运算或赋值的需要而对变量 (结果值) 的数据长度进行一时性的转换, 但并不改变变量类型的说明对该变量指定的数据类型。

例 2.6 强制类型转换 (P36 例 2.4)

#include <iostream> using namespace std; int main() { float x; int i; x=3.6; i=(int)x;
25

cout<<"x="<<x<<",i="<<i<<endl; return 0; }
运行结果:

x=3.6 ,i=3
作业: P41~42 3,4,5,6,7

第三章 程序设计初步
3.1 面向过程的程序设计和算法
3.1.1 算法的概念
一个程序应包括对解决问题所需要的数据的描述和对数据处理的描 述。 1.对数据的描述,即数据结构。 2.对数据处理的描述,即计算机算法。
算法是为解决一个问题而采取的方法和步骤,是程序的灵魂。为此,著名计算机科学家沃思 (Nikiklaus Wirth)提出一个经典公式:

数据结构 + 算法 = 程序
案例 3.1
问题分析:

输入三个数,求其最大值。

设 num1,num2,num3 存放 3 个数,max 存放其最大值。
26

为求其最大值, 就必须对 3 个数进行比较, 可按如下步骤去做: ①输入 3 个数 num1,num2,num3; ②先把第一个数 num1 的值赋给 max; ③将第 2 个数 num2 与 max 比较,如果 num2>max,则把第 2 个数 num2 的值赋给 max(否则不做任何工作) ④将第 3 个数 num3 与 max 比较,如果 num3>max,则把第 3 个数 num3 的值赋给 max(否则不做任何工作) ⑤输出 max 的值,即最大值。
从案例中可以看出,首先分析问题,然后寻找一种实现这个问题所要完成功能的方法,这种方法的具 体化就称为算法。因此可以说:

算法是由一套明确的规则组成的一些步骤,

他指定了操作顺序并通过有限个步骤将问题解决、得出结果。

3.1.2 算法的特性
一个算法应具有以下 5 个特性:

(1)有穷性
一个算法必须总是在执行有限个操作步骤和可以接受的时间内完成其 执行过程。

(2)确定性
算法中的每一步都必须有明确的含义,不允许存在二义性。

(3)有效性
算法中描述的每一步操作都应该能有效地执行,并最终得到确定的结 果。

(4)输入
27

一个算法有零个或多个输入数据。

(5)输出
一个算法有 1 个或多个输出数据。

3.1.2 算法的表示方法(P46)
算法的表示方法很多,常见的有:自然语言、传统流程图、N-S 结构图、伪代码、PAD 图等。

(1)用自然语言表示
自然语言就是人们日常使用的语言,可以是中文、英文等。用自然语言表示的算法通俗易懂,但一般 篇幅冗长,表达上往往不易准确,容易引起理解上的“歧义性” 。所以,一般用于算法较简单的情况。

(2)用传统流程图表示
传统流程图是用规定的一组符号、流程线和文字说明来表示各种操作算法的表示方法。传统流程图常 用的符号如图 3.1 所示

案例 3.1 用传统流程图描述的算法如下图所示。

28

(3)用 N-S 结构图表示
N-S 结构图的目标是开发一种不破坏结构化基本构成元素的过程设计表示。其主要特点是:完全

取消了流程线,不允许有随意的控制流,全部算法写在一个矩形框内,该
29

矩形框以三种基本结构(顺序、分支、循环)描述符号为基础符合而成。

案例 3.1 用 N-S 结构图描述如下

(4)用伪代码表示
伪代码是一种介于自然语言和计算机语言之间的文字和符号来描述算法。伪代码的表现形式比较灵活 自由,没有严谨的语法格式。

案例 3.1 用伪代码描述如下

input num1,num2,num3 num1→max if num2>max then num2 →max if num3>max then num3 →max print max

3.2 C++程序和语句
一 C++程序的组成 (P47)
30

预处理命令 声明部分 函数 二、C++的语句概述 (P48)
一条完整的语句必须以分号“;”结束。C++程序语句有如下几类:

(1)说明语句用来说明变量的类型和初值。如:float

a,b,c;

int

sum=0;

(2)表达式语句
由一个表达式构成一个语句,用以描述算术运算、逻辑运算、或产生某种特定动作,在任何表达式最 后加一个分号就构成了一个语句。

如:

c=a+b c=a+b;
(3)程序控制语句

/*赋值表达式*/ /*赋值表达式语句*/

注:掌握表达式语句的用法,关键在于要正确理解有关表达式的内容。

用来描述语句的执行条件与执行顺序的语。C++的控制语句有 9 种,如下所示。其语句中的括号( ) 表示其中是条件,~表示内嵌的语句

if () ~ switch for

else

条件(分支)语句 多分支选择语句 循环结构语句 循结构环语句 循环结构语句 结束本次循环语句 中止执行 switch 或循环语句
31

() ~ () ~ while ()

while do ~ break

continue

goto return
例如: { c=a; a=b; b=c; } (5)函数调用语句

转移语句 从函数返回语句(4)复合语句

复合语句是由一对花括号{ }括起来的一组语句。如果要在只执行一条语句的地方执行多条语句,那么 这多条语句要用一对花括号{ }括起来构成一条复合语句。

//实现 a,b 两个变量值的交换

函数调用语句是由一次函数调用加一个分号而构成的一个语句。

例如: max(x,y); (6)空语句
空语句不进行任何操作,它仅由一个分号“;”构成。通常用在应该放置语句而又不需要执行任何动作 的地方,例如:



3.3 赋值语句 (P49~50)
赋值语句是由赋值表达式加上一个分号构成的。最简单的一种形式为:

变量=表达式;
例如:

rad=14.5; cr=2*3.14*rad;
说明:

/*将实型数赋给变量 rad*/ /*将表达式 2*3.14*rad 的值赋给变量 cir*/

“=”是赋值符号,赋值符号的右边是由常量、变量、运算符和函数组成的表达式。 因赋值语句是由赋值表达式加上一个分号构成,所以下面是合法的赋值语句:
32

i++; x+=2; j--;
注:在程序设计中,赋值语句不仅用于为变量进行赋值,同时还大量用于运算处理。

3.4 C++的输入与输出(P50~57)
3.4.1 输入流与输出流的基本操作
在 C++中,将数据从一个对象到另一个对象的流动抽象为“流“,如:每次输入或输出都可以看做是 数据流。数据的输入与输出时通过 I/O 流来实现的。

1.输出操作
标准输出流 cout 与流插入运算符 << 联用,可实现一般的屏幕数据输出。

一般格式如下:

cout<<表达式<<表达式??
说明:

(1)在输出语句中,可以串联多个插入运算符,输出多个数据项。 例如:

cout<<‖hello\n‖; cout<<‖how are you?‖; cout<<‖My name is Alice‖; cout<<endl;
可写成: cout<<‖hello\n‖<<‖how are you?‖<<‖My name is Alice‖<<endl; 或:

cout<<‖hello\n‖
33

<<‖how are you?‖ <<‖My name is Alice‖ <<endl;
注:中间的行尾没有分号结尾

( 2) 在插入运算符后面可以是任意复杂的表达式, 系统将自动计算出 它们的值,并传给输入符。 例如:

cout<<“3+4=“<<3+4;
2.输入操作
标准输入流 cin 与流提取符 “>>”联用,可实现一般的键盘输入。

一般格式如下:

cin >>变量 1>>变量 2>> ??
说明:

①在输入语句中,提取符可以连续写多个,每个后面跟一个变量。 例如:

int a,b; cin>>a>>b;

②用户在输入多个数据时,各数据之间应用空格分隔。 (P53)

3.4.2 在输入流与输出流中使用控制符
C++提供的预定义的操作符见 P53 表 3.1 说明:

(1)C++中所有不带形参的操作符都定义在头文件 iostream 中,带 形参的操作符定义在头文件 iomanip.h 中; ( 2) 在进行输入输出时, 操作符必须嵌入到输入或输出键中用来控制
34

输入输出格式。 案例 3.2 操作符的使用 #include<iostream> #include<iomanip> using namespace std; int main() {
cout<<setw(10)<<123<<567<<endl; cout<<123<<setiosflags(ios::scientific)<<setw(20)<<123.456789<<endl; cout<<123<<setw(10)<<hex<<123<<endl; cout<<123<<setw(10)<<oct<<123<<endl; cout<<123<<setw(10)<<dec<<123<<endl;
cout<<resetiosflags(ios::scientific)<<setprecision(4)<<123.456789<<endl;

cout<<setiosflags(ios::left)<<setfill('#')<<setw(8)<<123<<endl; cout<<resetiosflags(ios::left)<<setfill('$')<<setw(8)<<456<<endl; return 0;

}

案例 3.3 各行小数点对齐 P53 例 3.1 #include <iostream>
35

#include <iomanip> using namespace std; int main() { double a=123.456,b=3.14159,c=-3214.67; cout<<setiosflags(ios::fixed)<<setiosflags(ios::right)<<setprecision(2); cout<<setw(10)<<a<<endl; cout<<setw(10)<<b<<endl; cout<<setw(10)<<c<<endl; return 0; }

3.4.3 用 getchar 和 putchar 函数实现字符的输入和输出
1. 字符输出 putchar 函数
putchar()函数的功能是用于将一个字符输出到显示器上显示。

putchar()函数的一般调用形式为:

putchar(c) ;
即把变量 c 的值输出到显示器上,这里的 c 可以是字符型或整型变量,也可以是一个转义字符。

案例 3.4 putchar()函数应用举例 1
36

#include <iostream> using namespace std;

int main() { char a,b,c,d; a='g'; b='o'; c=111; d='d'; putchar(a); putchar(b); putchar(c); putchar(d); return 0; } 运行情况如下: good
说明:putchar()函数只能用于单个字符的输出,并且一次只能输出一个字符。

2. 字符输入 grtchar 函数 getchar()函数的一般调用形式为:

c= getchar();
案例 3.5

getchar()函数应用举例 P56 例 3.3
37

#include <iostream> using namespace std; int main() { char c; c=getchar(); putchar(c+32); putchar('\n'); return 0; } 运行情况如下: A ↙ a
说明:getchar()函数只能用于单个字符的输入,且一次只能输入一个字符 /*接收用户从键盘上输入的一个字符*/

/*输出字符变量 c+32 后的值*/

3.4.4 用 scanf 和 printf 函数实现输入和输出 (P57)
38

C++保留了 C 的由标准库函数 printf() ,scanf()来实现输入/输出操作的方法。

一、printf()格式输出函数
格式输出函数 printf()的功能是按指定的格式向显示器输出一个或多个任意类型的数据。

printf()函数的一般调用形式为:

printf( “格式控制”[,输出项表]) ;
例如:

printf( “hello” ) ; printf( “The area is :%f\n“,area) ;
说明:

①格式控制。格式控制的两边必须用引号,
其中的内容可以包含

:普通字符、格式说明符和转义字符

(a)普通字符:即需要原样输出的字符信息。 (b)格式说明符:用%开头后面跟有一个字母,它规定了输出项的输 出形式。格式说明符在个数和类型上应与输出项匹配。
常用的格式说明符见下表。

39

案例 3.6 printf 输出形式举例 1

#include <iostream> using namespace std; int main()
{ int num1,num2; float r1,r2,re; char ch; num1=65;
40

num2=-3; r1=234.5; r2=18.75; re=r1+r2; ch='A'; printf("%d %c %d %o %f %c %d", num1,num1,num2,num2,re,ch,ch); printf("%s\n","Very good"); return 0; }
运行情况:

说明:
整型变量可以以字符的形式输出,而字符变量也可以整数的形式输出,ASCII 码是他们之间的桥梁。 负数在计算机内存中是以补码的形式存放。

变量 num2 的值为-3,-3 的补码为:
1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1

用八进制表示即:177775,所以变量 num2 以%o 的格式输出时,显示 177775。

41

(c)附加格式字符()

字母 l,h







l 用于长整型整数,h 用于短整型或无符号短整型整数,可以加在格 式字符 d,o,x,u 前面

m (代表一个正整数) 数据的输出宽度 n (代表一个正整数) 对实数,表示输出小数位的位数;对字符串,表示截取的字符个数 输出的数字或字符向左靠齐

案例 3.7 printf 输出形式举例 2

#include <iostream> using namespace std; int main() { int num1=123; long num2=1234567; float re=123.4567; printf("%d,%6d,%-6d,%2d\n", num1,num1,num1,num1); printf("%ld,%8ld,%4ld\n", num2,num2,num2);
42

printf("%f,%10f,%10.2f,%-10.2f\n", re,re,re,re); printf("%s,%10.5s,%-10.5s\n", "student","student","student"); } 运行情况如下:

②输出项表。
输出项表中可以有多个输出项,各项之间用逗号分隔。 注:Printf()函数在使用时要注意以下几点: (a)Printf()函数可以输出常量、变量和表达式的值。但格式控制中的格式说明符必须按从左到右的 顺序,与输出项表中的每个数据一一对应,否则会出错。 (b)类型转换字符紧跟在“%”后面时作为类型转换字符,否则将作为普通字符处理(即原样输出) 。

例如:
printf( “c=%c,f=%f\n”,c,f)
43 中的第一个 c 和 f 都是普通字符。

二、数据输入函数(scanf)
格式输入函数 scanf()的功能是用来从外部输入设备(通常是键盘) ,向程序中的变量输入一个或 多个任意类型的数据。

1.scanf()函数的一般调用形式为:

scanf( “格式控制” ,输入项表) ; 例如: scanf( “%d%f” ,&x,&y) ; 说明:
①格式控制。格式控制的两边必须用引号,其中的内容可以由格式说明符和普通字符组成。
(a)普通字符。普通字符在输入数据时,必须在对应位置上原样输入这些字符。
例如:

scanf ( “character:%c,real:%f” , &x,&y) ;
函数中的: “character:” 、 “real: ”和“, ”都是普通字符,则在实际运行时输入:

character:w,real:12.5 ↙
(b)格式说明符。scanf()中的格式说明符的使用与 printf()函数相似,必须用%开头
后面跟一个字母(也可在其中间增加附加字符) ,它规定了输入项对应的输入数据格式。同样格式说明符 要在个数和类型上与输入项相匹配。 scanf()函数常用的格式说明符及附加字符见下表:

scanf()函数格式说明符
格式说明符 输 入 内 容

%d

十进制整数
44

%o %x %c %s

八进制整数 十六进制整数 单个字符 输入一个字符串,输入时以非空白字符开始,以第一个空白 字符结束。 (字符串送到一个字符数组中)

%f %e

实数。可以用小数形式或指数形式输入 同%f,e 与 f 可以相互替换 scanf()函数附加格式说明符

附加说明字符 l h 域宽 m *





用于输入长型数据:%ld,%lo,%lx 等 用于输入短整型数据:%hd 等 指定输入数据所占的列数 表示本输入数据在读入后不赋给相应的变量

②输入项表。 输入项表中是要输入数据的变量的存储单元地址。 “ &”是地址运算符, “&x”
表示变量 x 在内存中的地址。

2. scanf 函数在使用时, 从键盘输入数据要注意以 下几点:
(a)scanf 函数没有计算功能,因此输入的数据只能是常量, 而不可以是表达式。

例如:

scanf( “%d%d%d” ,&x,&y,&z);

表示要输入 3 个十进制整数,可按以下方式输入:

12 34 56 ↙
45



12 ↙ 34 56 ↙ 例如: scanf( “%c%c” ,&c1,&c2);
表示要输入两个字符型数据,按以下方式输入:

ab ↙
则字符 a 符给变量 c1,字符 b 符给变量 c2。

(b)输入格式中,除格式说明符之外的普通字符应原样输入。

例如: scanf( “x=%d,y=%d,z=%d” ,&x,&y,&z);
应使用以下形式输入:

x=12,y=34,z=56 ↙
(c)由于 scanf()函数本身不具有显示提示信息功能,为 改善人—机交互性,在设计输入操作时,一般先用 printf() 函数输出一个提示信息,然后再用 scanf()函数进行数据输 入。

例如: printf ( “ Enter width and height : ” ) scanf( “%f,%f” ,&width,&height)
3.5 顺序结构程序设计
在顺序结构程序中, 程序的执行是按照各语句出现的先后
46

次序,顺序执行的,并且每个语句都会被执行到。

例如:已知某个三角形的底和高,计算其面积。 问题分析: 设:h 表示三角形的高,w 表示三角形的底, 则三角形面积为: area=w*h/2

解决该问题的算法用传统流程图描述如下:从图中可以看出,顺序结构程序通常由三部分组成:

①输入数据: ②进行处理: ③输出结果:
案例 3.8 编程实现输入某个三角形的底和高,计 算其面积。
47

#include <iostream> using namespace std; int main() { float w,h,area; cout<<"Enter width and height:"; cin>>w>>h; area=w*h/2.0; cout<<”The area is :"<<area<<endl; return 0; } 运行结果为: Enter width and height:2.5,4↙ The area is :5.000000
案例 3.9 输入一个 double 类型的数,使该数保留 小数点后两位,对第三位小数进行四舍五入。
48

#include <iostream> using namespace std; int main() { double x; cout<<"Enter x: "; cin>>x; cout<<"(1) x="<<x<<endl; x=x*100; x=x+0.5; x=(int)x; x=x/100; cout<<"(2) x="<<x<<endl; return 0; }
3.6 分支(选择)结构程序设计
49

3.6.1 分支结构的设计思想
顺序结构程序的流程方向永远是自上而下顺序执行的。但在实际应用中常常需要根据不同的条件(即 情况) 。执行不同的程序流程(即进行不同的处理) ,即形成了所谓的“分支”结构。

案例 3.10 货运公司对旅客托运行李计算收费。按规定,托运 行李不超过 30kg 时,每千克收取运费 0.15 元,如超过 30kg, 超过的部分按每千克 0.25 元收费。

问题分析: 设行李质量为:w(kg) ,运费为:f(元) 。
根据题意可得运费的计算公式为:

其算法如下图所示:

从图中可以看出,分支结构程序的设计要考虑两个方面的问题:

①判断条件。 ②实现分支结构语句的构成及选择。 3.6.2 实现分支结构判断条件的构成
50

一、关系运算符与关系表达式(P59) 1.关系运算符及其优先顺序

说明:
①关系运算符的优先级别与其他种类运算符相比,低于算术运算符,但高于赋值运算符。

例如: c<a+b c=a>b 2.关系表达式
用关系运算符将两个表达式连接起来,表示关系运算的表达式称为关系表达式。

等效于 等效于

c<(a+b) c=(a>b)

②关系运算符>=,<=,= =,!=在书写时,不要用空格将其分开,否则会产生语法错误。

例如:

a>b ,

a+b>=9.7 ,

x!=y

关系表达式的运算结果只有两种情况:当关系成立时,则表达式的结果值为 1(表示“真” ) ;当关系 不成立时,则表达式的结果值为 0(表示“假” ) 。这里的 0 和 1 都看成是整型量,可以进行整型量所允许 的各种操作。

例如:

a=(b>c)
51

当 b 的值时 10,c 的值为 6 时,a 的值 1;而当 b 的值时 5,c 的值为 7 时,a 的值 0;

二、逻辑常量和逻辑变量
C++新增了逻辑型数据。其中: 逻辑型常量表示为:true,flase 逻辑型变量表示为:bool 例如:
或0

bool

f1, f2;

注:可对 f1, f2 取值 true 或 flase; 表示“真”或“假” 亦可取值 0 或非 0 数值,但其内存中只存放 1

说明: 1. 逻辑型变量在内存中分配一个字节,用于存放 1 或 0 2.逻辑型数据可参加算术运算

例如: int a=2; bool f1=true; ; a=a+true+f1; cout<<a

输出结果: 4

三、逻辑运算符与逻辑表达式(P61)
52

1.逻辑运算符极其优先顺序 逻辑运算符

说明: ①逻辑运算符“&&”和“||”是双目运算符,而“! ”是单目运算符; ②逻辑运算符的优先级与其他种类的运算符相比,其优先关系从高到低如下所示:

! (非) 例如:

算术运算

关系运算

&&(与)

||(或)

赋值运算

x=a<b&&c<=d

相当于:

x=(a<b)&&(c<=d)

此外, “&&”和“||”的结合性是“自左向右” ,而“! ”是“自右向左“

逻辑运算的“真值表”

从表中可以看出逻辑运算符的运算规则是: &&:当且仅当两个运算量的值均为非 0 时,其运算结果值为 1,其余情况均为 0。
53

|| :当且仅当两个运算量的值均为 0 时,其运算结果值为 0,其余情况均为 1。 ! :当运算量的值为 0 时,运算结果值为 1;当运算量的值为 1 时,运算结果值为 0。

例如:

若 x=5 则: (x>=0)&&(x<10) (x<=-1)||(x>10)
2.逻辑表达式

的值为 1 的值为 0

用逻辑运算符将运算量连接起来的表达式称为逻辑表达式。 逻辑表达式的值是一个逻辑值, 即 “真 “或 “假” 。这里的运算量通常是关系表达式或逻辑量。

例如: 表示“三门课成绩均为及格“的逻辑表达式为:

(math>=60)&&(phys>=60)&&(engl>=60)
表示“三门课成绩中至少有一门不及格“的逻辑表达式为:

(math<60) || (phys<60) || (engl<60)
需要注意的是,在逻辑表达式的求解过程中,并不是所有的逻辑运算符都被执行,只是在必须执行下 一逻辑运算符才能求出表达式的解时,才执行该运算符。

例如:

a&&b&&c,
当 a 为 0 时,就不再判断或计算 b 和 c 的值,因为此时整个逻辑表达式的值已经可以确定为 0;

a || b || c,
当 a 为 1 时,就不再判断或计算 b 和 c 的值,因为此时整个逻辑表达式的值已经可以确定为 1;

3.6.3 实现分支结构程序设计的语句 一、 if 语句
54

1.if 语句的简单形式

if (表达式) 语句

语句的执行过程: 先判断或计算表达式的值,若结果为“真“ (非 0) ,则执行指定的语句,否则跳过所给出的语句,接 着执行下面的语句。

例 3.11 根据输入的学生成绩对其进行判断处理:如果成绩 及格(假定 60 分是及格分数线) ,则输出“Passed“ (及格) ; 否则,不做任何输出。

程序如下:

#include <iostream> using namespace std; int main() { int score; cout<<"Enter a score:"; cin>>score;
55

if (score>=60) cout<<”\nPassed\n"; return 0; }
2.If 语句的标准形式

if (表达式) 语句 1 else 语句 2
语句的执行过程:





假 语句 1

表达式 语句 2

先判断或计算表达式的值,若结果为“真“ (非 0) ,则执行语句 1,否则执行语句 2。

例 3.12 将例 3.11 改为:如果成绩及格,则输出“Passed“; 否则输出”Failed“。

程序如下:

#include <iostream> using namespace std; int main() { int score; cout<<"Enter a score:"; cin>>score; if (score>=60) cout<<"\nPassed\n";
56

else cout<<"\nFailed\n"; return 0; }
3.If 语句的嵌套形式
所谓 if 语句的嵌套形式是指在 if 语句中又包含了一个或多个 if 语句。 if 语句嵌套的目的是为了解决 多路分支处理问题。

(1)在 if 子句中嵌套具有 else 子句的 if 语句

if (表达式 1) if (表达式 2) 语句 1 else 语句 2 else 语句 3
(2)在 if 子句中嵌套不含 else 字句的 if 语句

if (表达式 1) { if (表达式 2) 语句 1 } else 语句 2
注意:在 if 字句中的一对花括号不可省略。 (C 规定,else 字句总是与前面最近的不带 else 的 if 配对)
57

问题:在此嵌套的 if 语句中,什么条件下将执行语句 1。

(3)在 else 字句中嵌套 if 语句 形式一: 嵌套 if 语句带有 else 形式二: 嵌套 if 语句不带有 else

if (表达式 1) 语句 1 else if (表达式 2) 语句 2 else 语句 3

if (表达式 1) 语句 1 else if (表达式 2) 语句 2

一种较为规范的嵌套的 if~else 结构形式:

if (表达式 1) 语句 1 else if (表达式 2) 语句 2 else if (表达式 3) ?? else if (表达式 n) 语句 n else
58

语句 n+1

例 3. 13 输入一个学生的成绩, 当成绩≥90 时, 输出 “Very good “;当 80≤成绩<90 时,输出“Good“;当 60≤成绩<80 时,输出“Passed” ;当成绩<60 时,输出“Failed” 。 问题分析:
根据学生成绩分别落入不同的分数段(4 种) ,而输出不同的评语。这是一个具有 4 路分支的问题。

程序如下:

#include <iostream> using namespace std; int main()

{
int score; cout<<"Enter a score:"; cin>>score; if (score>=90)
59

cout<<"Very good\n"; else if (score>=80) cout<<"Good\n"; else if (score>=60) cout<<"Passed\n"; else cout<<"Failed\n"; return 0;

}
关于 if 语句,有以下几点需加以说明: ①if 语句后面的表达式一般为关系表达式或逻辑表达式,但也可以是任意的数值类型(整型、实型、 字符型、指针型数据)

例如: if (5) cout<<“finished!\n” ;
由于系统对 if 语句的处理流程是:先对表达式的值进行判断,若为非 0,则按“真“处理;若为 0, 则按”假“处理。所以上述 if 语句是合法的。 ②else 字句不能作为单独的语句使用,它必须是 if 语句的一部分,与 if 配对使用。 ③在 if 或 else 后面可以只包含一个语句,也可以有多个操作语句,这时要用花括号{}将这多个语句括 起来作为一个复合语句使用。

例如:if (a>b) {
曾配对的 if 配对。

t=a; a=b ; b=t;

}

④在 if 语句的嵌套中,要注意 if 和 else 的配对关系。从最内层开始,else 总是与它上面最近的且未

4.条件运算符与条件表达式
60

例如:求 x 的绝对值 if (x>=0) y=x; else y=-x;
用条件运算符处理为:

y=(x>=0)? x:-x
/*如果(x>0)条件为“真“ (非 0) ,则 y=x,否则 y=-x*/ 其中: “? : ”是条件运算符,它是 C 中惟一的三目运输符。由它与运算量 x>=0,x, -x 一起构成的 表达式(x>=0)?x:-x 称为“条件表达式” 。

条件表达式的一般形式为:

表达式 1?表达式 2:表达式 3
其运算规则为:该表达式 1 为“真” (非 0) ,则求解表达式 2 的值,即作为整个条件表达式的值;否则 求解表达式 3 的值,作为整个条件表达式的值。 如下图所示



条件表达式在使用时要注意以下几点: ①条件运算符的优先级高于赋值运算符,但低于关系运算符和算术运算符。

61

例如:
相当于

y=x>0 ? x+1 : x*x/2 y=(x>0 ? (x+1) : (x*x/2) x>0?1:x<0?-1:0 x>0?1: (x<0?-1:0) x>y? 1:1.5

②条件运算符具有右结合性,并允许嵌套使用。

例如:
相当于

③在条件表达式种, 当表达式 2 于表达式 3 的类型不同时, 条件表达式值的类型为二者中较高的类型。

例如:

条件表达式的值为:1.0

二、switch 语句()
switch 语句的一般形式为:

switch (表达式) { case 常量表达式 1:语句组 1; case 常量表达式 2:语句组 2; ? case 常量表达式 n:语句组 n; [default:语句组 n+1;] }
switch 语句的执行过程为: 先计算表达式的值。然后顺次同 case 后的常量表达式的值比较,找到相等的常量表达式 i,则执行该 常量表达式冒号后的语句组 i。在执行过程中,若遇到 break 语句,则跳出 switch 结构,将程序流程转向 switch 结构外的下一条语句执行;若没有 break 语句,则从该语句组为入口,依次执行其后的所有冒号后 面的语句。如果 switch 语句后面的表达式的值找不到匹配的常量表达式的值,此时要考虑是否有 default 可选项,若有,则执行 default 后面的语句组直到结束;否则什么也不执行。
62

例 3.14 用 switch 语句实现例 3.13

#include <iostream> using namespace std; int main() { int score,mark; cout<<"Enter a score:"; cin>>score; mark=-1; if (score>=0 && score<=100) mark=score/10; switch (mark) { case 10: case 9:cout<<"Very good\n";break; case 8:cout<<"Good\n";break; case 7: case 6:cout<<"Passed\n";break; case 5: case 4: case 3: case 2: case 1: case 0:cout<<"Failed\n";break;
63

default:cout<<"Enter error!\n"; } }
switch 结构使用时要注意以下几点: ①switch 后面表达式的类型,一般为整型、字符型或枚举类型; ②每个 case 后面常量表达式的值必须互不相同,即不允许对表达式的同一个值有两种或两种以上的 处理方案。 ③尽管各个 case 和 default 出现的次序不影响程序的执行结果,但是把 default 放在最后是一种良好 的程序设计习惯; ④多个 case 可共有一组执行语句,如例 5。5 中的:

case 10: case 9:cout<<“Very good。\n”:break;
当 mark 的值为 10 或 9 时,都执行 printf(“Very good。\n”);break;语句。 ⑤Case 后面的常量表达式仅起到语句标号的作用,并不进行条件判断。系统一旦找到标号,就从此 标号开始执行下去,不再进行判断。 ⑥Switch 语句又称为开关语句。 当仅需执行一个开关时, 则在该 case 后面的语句中必须包含一个 break 语句,让其执行后跳出 Switch 语句,否则会一直执行到最后,或遇到下一个 case 中的 break 语句为止。

例如,将上例改为:

? case 9:cout<<“Very good.\ n ―; case 8:cout<<“Good.\ n ―;break ; ?
则当输入成绩 95 时,程序的执行结果为:

Very good. Good.
⑦当 case 后面包含一条以上的执行语句时,可以用花括号括起来,系统会自动识别并顺序执行所有
64

语句。 ⑧Default 是可选项。但良好的程序设计习惯是,在每个 Switch 语句中,写上一条 Default 语句来集 中处理例外情况,从而防止一些条件没有被测试到。

3.6.4 分支结构程序设计举例
例 3.15 对例 3.10 进行编程

#include <iostream> using namespace std; int main()

{
float w, f; cout<<"Enter the weight:"; cin>>w; if (w<=30) f=0.15*w; else f=30*0.15+(w-30)*0.25; cout<<"Collect fees:"<<f<<endl; return 0;

}
例 3.16 有一函数:编一程序,输入一个 x 的值,输出 y 的 值。 -1 y= 0 (x<0) (x=0 )
65

1

(x>0)

程序一:用简单的 if 语句实现;

#include <iostream> using namespace std; int main() { int x,y; cout<<"Enter the x:"; cin>>x; if (x>0) y=1; if (x==0) y=0; if (x<0) y=-1;
cout<<"x=”<<x<<”,”<<”y=”<<y<<endl;

return 0; }
程序二:采用内层 if 嵌在外层的 if 后面的结构。

#include <iostream> using namespace std; int main()

{

int x,y; cout<<"Enter the x:"; cin>>x;
66

if (x<=0) if (x==0) y=0; else y=-1; else y=1;
cout<<"x=”<<x<<”,”<<”y=”<<y<<endl;

return 0;

}
程序三:用内层 if 嵌在外层的 else 部分,即 else if 结构。

#include <iostream> using namespace std; int main()

{

int x,y; cout<<"Enter the x:"; cin>>x; if (x<0) y=-1; else if (x>0) y=1;
67

else y=0;
cout<<"x=”<<x<<”,”<<”y=”<<y<<endl;

return 0;

}
请考虑下面的程序是否正确?为什么?

例 3.17 某商店售货,按购买货物的款数多少分别给予不同的 优惠折扣: 购货不足 250 元的,没有折扣; 购货满 250 元,不足 500 元的,折扣 5%; 购货满 500 元,不足 1000 元的,折扣 7。5%; 购货满 1000 元,不足 2000 元的,折扣 10%; 购货满 2000 元,折扣 15%;

问题分析: 设购货款为 m,折扣为 d,根据题意有: 0 (m<250) 5% (250≤m<500) d= 7.5% (500≤m<1000) 10% (1000≤m<2000) 15% (2000≤m)
方法一:用嵌套的 if 结构实现,如图所示:
68

#include <iostream> using namespace std; int main()

{

float m,d,amount; cout<<"Enter your money for buying:"; cin>>m; if (m<250) d=0; else if (m<500) d=5; else if (m<1000) d=7.5; else if (m<2000) d=10; else d=15;
69

amount=m*(1-d/100.0); cout<<"amount="<<amount<<endl; return 0;

}
方法二、用 switch 结构实现。

设置 mark 为标记变量: mark=m/250 ,
根据 mark 的值而确定相应的折扣。

#include <iostream> using namespace std; int main()

{

float m,d,amount; int mark; cout<<"Enter your money for buying:"; cin>>m; mark=m/250; switch (mark) { case 0:d=0;break; case 1:d=5;break; case 2: case 3:d=7.5;break;
70

case 4: case 5: case 6: case 7:d=10;break; default:d=15; } amount=m*(1-d/100.0); cout<<"amount="<<amount<<endl; return 0;
}
例 3.18 编一程序将以英寸为单位的长度,转换为以厘米为单 位的长度;或者反之,从厘米转换为英寸。 问题分析: 已知;1 英寸=2.54 厘米 因为要求两种单位可以互相转换, 所以,设置一个变量 select, 用于选择,select=1 表示将英寸转换为厘米,select=2 表示将 厘米转换为英寸。

#include <iostream> using namespace std; int main()

{ int select;
float leng,r=2.54;
71

cout<<"Please choose (1:inch to cm;2:cm to inch):";

cin>>select; cout<<"Enter the leng:"; cin>>leng; if (select==1)
cout<<leng<<“inch=”<<leng*r<<”cm”<<endl;

else if (select==2)
cout<<leng<<“cm =”<<leng/r<<”inch”<<endl;

return 0;
}
另一方法是用 switch 结构实现。

#include <iostream> using namespace std; int main()

{ int select;
float leng,r=2.54;
cout<<"Please choose (1:inch to cm;2:cm to inch):";

cin>>select; cout<<"Enter the leng:"; cin>>leng; switch (select) {
case 1: cout<<leng<<“inch=”<<leng*r<<”cm”<<endl;;break;
72

case 2: cout<<leng<<“cm =”<<leng/r<<”inch”<<endl;break;

default: cout<<"Enter error!\n"; } return 0;

}
例 3.19 编写程序,判段某一年是否为闰年 p70 例 3.8

#include <iostream> using namespace std; int main() { int year; bool leap; cout<<"please enter year:"; cin>>year; if (year%4==0) { if(year%100==0) { if (year%400==0) leap=true; else leap=false; } else
73

leap=true; } else leap=false; if (leap) cout<<year<<" is "; else cout<<year<<" is not "; cout<<" a leap year."<<endl; return 0; } 3.7 循环结构程序设计
3.7.1 循环结构的程序设计思想
例 3.20 将 3.12 改为从键盘上输入 30 名学生的成绩,对其进 行处理。 如果成绩及格, 则输出 “Passed” ; 否则输出 “Failed” 。
问题分析:
每个学生成绩的处理流程都是一样的,30 名学生成绩的处理无非是对每个学生成绩处理流程进行 30 次的重复,而每次只需输入不同的学生成绩即可。 因此,该问题的求解算法是:只需在例 3.12 的基础上加一个循环处理。设一个变量 n 用来累计已处 理完的学生成绩的个数,当处理完 30 个成绩后,程序结束。

#include <iostream> using namespace std;
74

int main() { int score; int n=0; while (n<30) { n=n+1; cout<<"Enter a score:"; cin>>score; if (score>=60) cout<<"\nPassed\n"; else cout<<"\nFailed\n"; } return 0; }
循环结构程序设计要考虑两个方面的问题: ①循环继续的条件。 ②循环体。 循环结构程序的设计就是要: 正确描述循环继续的条件并 针对问题分析出其规律,利用循环控制语句进行处理。

3.7.2 实现循环结构的语句 一、while 语句(P73)
while 语句用于构成“当型”循环结构。其流程如下图所示: 程序形式:
75

while (表达式) { 循环体语句 }

while 循环结构的执行过程是:首先计算表达式(循环继续的条件)的值,当结果为:真“ (非 0) ” , 则执行循环体语句;然后再计算表达式的值,重复上述过程,直到表达式的值为“假(0) ”时结束循环, 流程控制转到循环结构的下一语句。 利用 while 语句对例 5.1 实现编程。

例 3.21 从键盘上输入 10 个整数,求其累加和。 问题分析:
这是一个重复累加的问题。从键盘上输入一个整数,进行一次累加,再输入一个整数,再进行一次累 加??直至 10 个整数全部输入并累加完毕。这里

循环的继续条件是:10 个数未输

入累加完毕,而每次重复的工作为:输入数据、进行累加。 设:x 为欲累加的数据; sum 为累加和变量,用于累加求和; i 为循环控制变量,用于控制循环的次数(即构成循环继续的条件) 。
其算法表示如下图所示


76

例 3.21 程序如下:

#include <iostream> using namespace std; int main() { int i,sum,x; i=0;sum=0;

//循环控制变量 i、累加变量 sum 赋初值

while (i<10) //循环继续的条件 { cout<<"Enter a data:"; cin>>x; //输入累加的数据 i++; //循环控制变量递增 sum=sum+x; //进行累加求和 }
cout<<"sum="<<sum<<endl; return 0;
//输出计算结果

}
77

使用 while 循环结构应注意以下几点: ①while 循环结构的特点是“先判断,后执行“。如果表达式的值一开始就为“假”则循环体一次也 不执行。 ②循环体中,如果包含一个以上的语句,则应用花括号括起来。 ③循环体内一定要有改变循环继续条件的语句, 使得循环趋向于结束, 否则循环将无休止地进行下去, 即形成“循环”如上例中的语句:i++。 ④为使循环能够正确开始运行,还要做好循环前的准备工作。如上例中的语句 i=1 和 sum=0 ,分别给 循环控制变量初始化和对累加求和单元清零。

二、for 语句
程序形式:

for (表达式 1;表达式 2;表达式 3) 循环体语句
for 循环结构的执行过程如图:

78

例 3.22 用 for 循环实现例 3.21

#include <iostream> using namespace std; int main() { int i,sum,x;

for(i=0,sum=0;i<10;i++) { cout<<"Enter a data:"; cin>>x; sum=sum+x; }
79

cout<<"sum="<<sum<<endl; return 0;

}
使用 for 循环结构应注意以下几点:
①for 循环结构也具有“先判断,后执行”的特点。 for 循环结构相当于如下形式的 while 结构:

表达式 1; while(表达式 2) { 循环体 表达式 3; }
②从语法上看,for 的 3 个成分都是表达式,他们之间都以分号“; ”隔开。表达式 1 和表达式 3 通常是赋 值表达式或函数调用,有时也可以是逗号表达式,一般用来实现对循环控制变量初始化和循环控制变量增 (减)值。表达式 2 通常是关系表达式或逻辑表达式,但也可以是数值表达式或字符表达式,是用来表示 循环继续的条件,只要其值为非零,就可执行循环体。

例如:

for(i=1,sum=0;i<=100;i++,i++) sum+=i;
其中,表达式 1 与表达式 3 都是逗号表达式。 此外,for 的 3 个表达式还允许部分或全部省略。当省略表达式 1 时,应该在进入 for 循环结构之前有适 当的给循环控制变量初始化的语句;当省略表达式 3 时,应该在循环体内含有改变循环控制变量的值的语 句;当表达式 2 省略时,应该在循环体内设置相应的语句来结束循环,否则循环将无休止地继续下去(因 为循环继续的条件被认为总为“真” ) 。 ③由于 for 循环结构书写形式灵活多样,如果在 3 个表达式中过多地加入与循环控制无关的内容,容易降
80

低可读性。因此,通常使用一种更为简单明了的 for 循环结构形式,即为:

for(循环控制变量赋初值;循环条件;循环控制变量增(减)值)

循环体语句
例如,将例 3.22 中的 for 循环结构改为:

sum=0; for (i=1;i<=10;i++) { ?? }
例 3.23 输入整数 n,求 n ! 问题分析:
这是一个“连乘”的问题。为得到连乘的积,程序中需要有:

①用来存放连乘积的变量(fac) ,其初值为 1; ②控制连乘个数的循环控制变量(i) ,其初值为 1,终值为 n,每次增 量为 1; ③每次要连乘的乘数,由于其恰好与循环控制变量(i)的值相吻合,因此可用循环控制变量
的值代替。

程序如下:

#include <iostream> using namespace std; int main() { int n,i,fac; cout<<"Please enter n:";
81

cin>>n; fac=1;

for(i=1;i<=n;i++) fac=fac*i;
cout<<n<<”!=”<<fac<<endl; return 0; }
说明:上例中的 for 循环结构还可以改为以下几种形式。

形式 1(省略表达式 1) :

?? i=1; for ( ; i<=n; i++) fac=fac*i; ??
形式 2(省略表达式 3) : ??

for ( i=1; i<=n; ) { fac=fac*i; i++; } ??
形式 3(循环体为空语句) :
82

?? for (i=1;i<=n; fac=fac*i,i++) ; ?? 三、do~while 语句
程序形式:

do { 循环体语句 } while(表达式) ;
do~while 循环结构的执行过程如图所示:

例 3.24 用 do~while 循环结构实现例 3.21

#include <iostream> using namespace std; int main() { int i,sum,x; i=0;sum=0;
83

do { cout<<"Enter a data:"; cin>>x; sum=sum+x; i++; } while(i<10); cout<<"sum="<<sum<<endl; return 0;

}
使用 do~while 循环结构应注意以下几点: ①do~while 循环结构的特点是“先执行,后判断” ,因此无论循环继续的条件是否成立,循环体中的语句 至少被执行一次。这是他与 while 循环结构的本质区别。 ②如果循环体包含一个以上的语句,则也应该用花括号括起来,以复合语句的形式出现。 ③循环体内一定要有改变循环条件的语句,使得循环趋向于结束。

3.8 循环嵌套的概念及实现
循环嵌套是指:

在一个循环体内又包含了另一个完整的循环结构。

3 种循环不仅可以自身嵌套,而且还可以互相嵌套。

例 3.25 编程输出以下形式的乘法“九九表”
1*1=1 2*1=2 ?? 9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 ?? 1*2=2 2*2=4 1*3=3 2*3=6 1*4=4 2*4=8 1*5=5 2*5=10 1*6=6 2*6=12 ?? ??

问题分析:
84

首先观察第 1 行乘法表的变化规律:

被乘数为 1 不变,而乘数从 1 变化到 9,每次增量为 1。
因此,构造如下循环即可实现第 1 行乘法表的输出:

for (j=1;j<=9;j++) cout<<1<<―*‖<<j<<‖=‖<<1*j<<‖ ―;
再观察第 2 行乘法表的变化规律: 与第 1 行惟一不同的是被乘数为 2,而处理过程完全一样。 因此,只需将被乘数改为 2,对上述循环再执行一次即可。 同理,第 3 行,第 4 行,??,只需让被乘数从 1 变化到 9 对上述循环执行 9 次即可。 因此,在上述循环的外面再加上一个循环(即构成双重循环) ,即可得所求的乘法“九九表” 。

for (j=1;j<=9;j++) cout<<1<<―*‖<<j<<‖=‖<<1*j<<‖ ―;
cout<<endl;

for (j=1;j<=9;j++) cout<<2<<―*‖<<j<<‖=‖<<2*j<<‖ ―;
cout<<endl;

…. for (j=1;j<=9;j++) cout<<9<<―*‖<<j<<‖=‖<<9*j<<‖ ―;
cout<<endl;
程序如下:

#include <iostream> #include <iomanip> using namespace std;
85

int main() { int i,j; for(i=1;i<=9;i++)

//i 作为外循环控制变量控制被乘数变化

{
for(j=1;j<=9;j++) cout<<endl;
// j 作为内循环控制变量控制乘数变化
//i*j 即为两个数的乘积

cout<<i<<―*‖<<j<<‖=‖<<i*j<<‖ ―;
//换行

}
return 0; }
双重循环的执行过程是: 先执行外循环,当外循环控制变量 i 取初值 1 后,执行内循环,在内循环 j 从 1 变化到 9 的过程中,i 始终不变,直到内循环执行完毕,到了外循环,i 才变为 2,而后再执行内循环,j 又从 1 变化到 9??如 此下去,直到外循环控制变量 i 超过终值,整个双重循环才执行完毕。

例 3.26 全班有 30 名学生,每名学生考 8 门课。要求分别统 计出每名学生各门课的平均成绩。 问题分析:
首先考虑一名学生各门课的平均成绩。设置循环控制变量 i 控制课程数,其变化从 1 到 8,每次增量 为 1。算法表示如下图 1。

86

每个学生的处理过程是一样的,因此,只需对上述流程重复执行 30 遍(即形成双重循环,每遍输入 不同学生的各门课成绩) 。设置循环控制变量 j 控制学生人数,其变化从 1 到 30,每次增量为 1。算法表 示如下图 2。

程序如下:

#include <iostream> using namespace std; int main() { int i,j,score,sum; float aver; j=1; while(j<=30) { sum=0;

for(i=1;i<=8;i++)
{ cout<<"Enter NO.‖<<j<<‖the score‖<<i; cin>>score; //输入第 j 名学生第 i 门课程的成绩
87

sum=sum+score;

//累计第 j 名学生的总成绩

}
aver=sum/8.0;
j++; }
return 0;
//计算第 j 名学生的平均成绩

cout<<"NO.‖<<j<<‖aver=‖<<aver<<endl;//输出第 j 名学生的平均成绩

}
考虑以下两个问题: 程序中的变量 sum,为什么要赋初值 0 ?其位置如何?

如果对该问题进一步提问:统计出全班的总平均成绩?

#include <iostream> using namespace std; int main() { int i,j,score,sum; float aver,total,total_aver;

total=0; j=1; while(j<=30) { sum=0; for(i=1;i<=8;i++)
{ cout<<"Enter NO.‖<<j<<‖the score‖<<i; cin>>score; //输入第 j 名学生第 i 门课程的成绩 sum=sum+score; //累计第 j 名学生的总成绩
88

}

aver=sum/8.0;
cout<<"NO.‖<<j<<‖aver=‖<<aver<<endl;

j++;
total=total+aver;

} total_aver=total/30.0;
cout<<"Class total_aver is :"<<total_aver<<endl;

return 0; }
使用循环嵌套结构要注意以下几点: ①外层循环应“完全包含“内层循环,不能发生交叉。 ②嵌套的循环控制变量一般不应同名,以免造成混乱。 ③嵌套的循环要注意正确使用“缩进式“书写格式来明确嵌套循环的层次关系,以增加程序的可读性。

3.9 循环结构程序设计举例
例 3.27 输入 10 个整数,求出其中的最大值与最小值。
问题分析:

int x,max,i; cin>>x; max=x; for(i=1;i<=9;i++) { cin>>x; if(x>max) max=x;
89

} cout<<‖max=‖<<max<<endl; 设输入数为 x,最大值为 max,最小值为 min。
首先输入第 1 个数并作为 max 与 min 的初值,然后每输入一个数,都将其与 max 和 min 比较。如果 他大于 max,则用他替代原来的 max 的值;如果他小于 min,则用他替代原来的 min 的值。如此重复下 去,max 始终存放的是当前已输入数的最大值,min 始终存放的是当前已输入数的最小值。直至第 10 个 数输入完并比较完后,max 就是最大值,min 就是最小值。

算法表示如图:

#include <iostream> using namespace std; int main()
90

{
int i; int x,max,min; cout<<"please input the first number:"; cin>>x;

max=min=x; for(i=2;i<=10;i++)
{ cout<<"please input the next number:"; cin>>x;

if(x>max) max=x; else if (x<min) min=x;

}
cout<<"max=”<<max<<”,min="<<min<<endl; return 0;

}
例 3.28 利用格里高利公式求∏:

??

直到最后一项的绝对值小于 10-7 为止 问题分析:
91

设置一个符号变量 sign 来控制每次要累加的数据的符号。

#include <iostream> #include <iomanip> #include <cmath> using namespace std; int main() { int sign=1; double n=1,t=1,pi=0; while((fabs(t)) > 1e-7) { pi=pi+t; n=n+2; sign =- sign; t= sign/n; } pi=pi*4;
cout<<"pi="<<setiosflags(ios::fixed)<<setprecision(6)<<pi<<endl;

return 0; } 例 3.29 对求全班平均成绩问题进行一般化处理。即要求
程序在每次运行时能够处理任意个数的成绩。
问题分析:
由于要求程序能够处理任意个数的成绩,程序循环的次数是不确定的。因此可以采取一个专门的值来 指示数据输入的结束,这个值就称为“标记值”或称为“信号值” 。用户将所有要处理的正常数据键入以 后,键入该“ 标记值” (用于表示已输入完最后一个处理数据) ,此时,程序接收到这个“标记值” ,即终 止循环。
92

#include <iostream> using namespace std; int main()

{

int n,score,sum; float average; sum=0; n=0; cout<<"Enter score,-2 to end:"; cin>>score; while(score!=-2) { sum=sum+score;
n=n+1; cout<<"Enter score,-2 to end:"; cin>>score;

} if (n!=0) { average=(float)sum/n;
cout<"Class average is "<<average<<endl;

} else
cout<<"NO score were entered."<<endl;

return 0; }
程序说明: ①由于考试成绩通常是非负数据,所以本例可用“-1”作为“标记值” ;
93

②由于不能被 0 除,所以在进行求平均成绩之前要进行测试,以保证程序正确运行; ③在请求键入数据的提示信息中,明确地把标记值告诉用户,是一种良好的程序设计习惯。

for(n=3;n<=100;n++) { for(i=2;i<=n/2;i++) if( n%i==0) { cout<<‖no‖<<endl; return 0; } cout<<‖yes‖<<endl; return 0; 例 5. 30 输入一个整数 n(n≥3) ,判断是否为素数(质数) 。
问题分析:
数学方法已证明:若要判断一个整数 n 否为素数,只需用 2~√n 各数去除 n,如果都除不尽,n 就是 素数;只要有一次除尽了,n 就不是素数。 设置一个开关变量 flag,用于标识是否除尽。Flag 初值为 1( “真” ,一旦某一次除尽了就将其置为 0 ( “假” ) ,从而终止循环。当循环结束时,若 flag 为“真” ,就表明 n 是素数。 程序如下:

#include <iostream>

#include<cmath>
using namespace std; int main()

{

int n,i; bool flag; cout<<"Enter a integer:"; cin>>n;
94

i=2; flag=true; while(i<(int)sqrt(n)&&flag) if (n%i==0) flag=false; else i++; if (flag)
cout<<n<<"is prime number."<<endl;

else
cout<<n<<"is not prime number.‖ <<endl;

retuen 0; }
例 3.31 输出如下形式的图案。 ******** ******** ******** ******** ******** ******** ******** ********
95

问题分析:
这是一个 6 行 8 列的星形矩阵。 对于这类图案的输出关键是找出其规律, 理解控制变量所代表的实际意义。

分析语句:cout<<“*” ;的功能;
对该语句重复若干次其结果是:

********?? 程序如下: #include <iostream> using namespace std; int main()

{ int i,j; for(i=1;i<=8;i++) { for(j=1;j<=8;j++) cout<<"*"; cout<<endl; } return 0; }
总结:
通过上述例题可以看出,所谓循环就是在循环条件为“真”时,让计算机反复执行一组指令,直到循 环条件为“假”时终止。 实际应用中用到的大多数循环通常分为两类:一类是次数确定的循环,一类是次数不确定的循环。 次数确定的循环通常采用计数器的方式控制循环。循环控制变量用来控制循环的次数,循环控制变量 要有:初始值、每次变化的增量及控制循环是否终止的终值和测试条件。 次数不确定的循环通常采用“标记值”的方式控制循环。 “标记值”表示获取数据的结束, “标记值” 是在所有合法的数据项都提供给程序后的键入值。 “标记值”必须不同于正常的数据项,以免发生混淆。 无论是用计数器控制循环,还是用标记值控制循环,在实现过程中,都要注意使开发的程序具有通用 性。
96

3 种循环的比较:
①3 种循环都可以用来处理同一问题,一般情况下他们可以互相代替。 ②do~while 循环类似于 while 循环, 不同之处是他们执行循环体和计算表达式的先后顺序不同。 此外, 从流程图可以看出,do~while 循环至少要执行一次循环体,而 while 和 for 循环在进入循环体之前,首先 要判断循环条件的表达式,如果条件不成立,则循环体一次也不执行就结束循环流程,所以,这两种循环 可能执行零次或若干次。 ③while 和 do~while 循环,在 while 后面指定循环条件,在循环体中包含应重复执行的操作语句。而 for 循环可以在表达式 3 中包含使循环趋于结束的操作, 甚至可以将循环体中的操作全部放到表达式 3 中。 ④用 while 和 do~while 循环时,循环变量初始化的操作应在 while 和 do~while 之前完成。而 for 语句 可以在表达式 1 中实现循环变量的初始化。

3.10 其他语句
一、break 语句(间断语句)
break 语句的功能是使执行从包含他的最内层循环或开关语句中跳出, 转到 switch 结构或循环结构外 的下一语句执行。这将导致包含他的最内层循环或 switch 语句的终止。

break 语句的一般形式: break; 例 3.32 计算 r=1 到 r=10 的圆的面积,直到其面积大于 100 为止。

#include <iostream> using namespace std; int main()

{

int r; float pi=3.14159; float area; for(r=1;r<=10;r++) { area=pi*r*r; if(area>100) break; cout<<"r=‖<<r<<endl; cout<<‖area is ―<<area<<endl;
97

} return 0;
}
程序说明: 从 for 循环可以看到:当 area>100 时,执行 break 语句,循环将提前结束,即不再执行其余的几次循环。 使用 break 语句应注意以下几点: (P70) ①break 语句只能用于 switch 结构或循环结构中。在循环结构中应用时,一般要有 if 语句配合使用。 ②在嵌套的循环结构中使用时,break 语句只能跳出 (或终止) 包含他的最内层循环, 而不能同时跳出 (或 终止)多层循环。

二、continue(接续语句)
continue 语句的作用是结束本次循环,使得包含他的循环开始下一次循环。

continue 语句的一般形式为:

continue;
例 3.33 输出 100~200 范围内不能被 5 整除的数。
算法表示如图:
n=100 假 n<=200 真 真 N%5=0 假 输出 n 执行 continue

n=n+1

#include <iostream> using namespace std; int main()
98

{

int n; for(n=100;n<=200;n++) { if (n%5==0) continue; cout<<n<<‘\t‘; } return 0;

}
使用 continue 语句时要注意以下几点: ①continue 语句只能用于循环结构中,通常也要有 if 语句配合使用。 ②continue 语句和 break 语句虽然都实现了程序执行方向的无条件转移,但他们的区别是:continue 语句只能结束本次循环,而不是终止整个循环的执行;break 语句则是立即结束整个循环的过程,不再进 行条件判断。 例如;以 for 循环为例。

for(表达式 1;表达式 2;表达式 3)for(表达式 1;表达式 2;表达式 3)

{ ? break; ? }

{ ? continue; ? }

表达式 1 假 表达式 2 真 ? break ? 真

表达式 1 假 表达式 2

? continue ?

表达式 3

99

表达式 3

三、goto(转向语句)
goto 语句为无条件转向语句,其功能是:把程序控制转移到标号指定的语句处,使程序从指定的标号 处的语句开始继续执行。

goto 语句的一般形式为:

goto 标号; ?? 标号:语句;
说明:标号是由用户命名的标识符,其后要跟一个冒号。标号的命名规则与变量名相同,其作用识用 来表示 goto 的目标。标号可以用在任何语句前面,但必须与引用他的 goto 语句在同一个函数中。

例 3.34 用 if 语句和 goto 语句构成的循环实现例 3.21 #include <iostream> using namespace std; int main() { int i,sum,x; i=1;sum=0; loop: if (i>10) goto end; cout<<"Enter a data:"; cin>>x; sum=sum+x; i++; goto loop; end:cout<<"sum="<<sum<<endl; return 0; }
一般而言,goto 语句的用途有两种: ①与 if 语句一起构成循环结构; ②从循环体中跳到循环体外。
100

第四章 函数 学习要点: ? 函数的定义 ? 形参与实参 ? 函数的调用 ? 常用库函数 学习目标: ? 理解函数的概念及建立函数的意义 ? 掌握标准库函数的调用 ? 掌握自定义函数的定义和调用 ? 理解并掌握函数与被调函数之间的数据传递方 式

101

4.1 概述
一、函数的概念
通常把一个较大的应用程序分解为若干个程序模块,每一个程序模块用来实现一个特定的功能,在 C 中将这些程序模块称为函数。





功能模块 1

功能模块 2

。 。 。

功能模块 n

服务模块 1

服务模块 2

。 。 。

服务模块 n

1.什么叫函数 完成特定功能的一段程序。 2.引入函数的意义 实现模块化的程序设计。 不仅可以提高程序的可读性、易维护性等,还可
以节约内存和避免重复性编程。

二、函数的分类(P90) 1.从用户角度划分:标准函数(库函数)和用户(自)定义函数。 标准函数:如 sqrt() ,abs()等 用户定义函数:例题中的 max() 2.从函数的形式上划分:无参函数和有参函数。 无参函数:在调用时,外界不需要传递数据。即主调函数不需要给被调函数传递一组值; 有参函数:在调用时,外界需要传递数据。即主调函数需要给被调函数传递一组值; 三、两点说明
1.每个 C 程序程序必须从 mian()函数开始执行,并最终在 mian()函数中执行结束; 2.所有函数都是平行的(没有定义的嵌套,但有调用的嵌套) 。
102

4.2 函数的定义
4.2.1 无参函数定义的一般形式 函数值类型 函数名() {
声明部分 执行部分
//类型说明 //执行语句

} 例 4.1 分析如下程序。 #include <iostream> using namespace std; void p_star( )

// 自定义无参函数

{
cout<<"* * * * * * * * * * * *\n"; } void message( ) // 自定义无参函数 { cout<<" Welcome,students!\n"; } void main() { p_star();
103

message(); p_star(); } 4.2.2 有参函数定义的一般形式
函数值类型 函数名(类型名 形参 1,类型名 形参 2,?)
/ /函数首部

{
说明部分 执行部分
// 函数体

} 例 4.2 编写程序计算组合数: C(n,k)=n!/(k! (n-k) ! ) 问题分析:
由于在该程序中多次遇到阶乘问题,因此可将阶乘的求解设计成函数,以便多次调用,从而避免了重 复性编程。

int fac(int m) { int i,s=1; for(i=1;i<=m;i++) s*=i; return(s); } #include <iostream>
104

using namespace std; int fac(int m) { int i,s=1; for(i=1;i<=m;i++) s*=i; return(s); } int main() { int n , k , c; cout<<"Please input (n,k):"; cin>>n>>k; cout<<‖C(n,k)=‖<<c<<endl;; } 4.2.3 说明 函数首部: 是函数的接口部分。其中:函数值类型规定了函数返回值的数据类型;函数名是函数
的标志,要符合标识符命名规则且在同一程序中,函数名必须唯一。此外,若在函数首部省略了函数返回 值的类型,C 则默认为函数值类型为 int 型。 // 自定义函数

//输入 n,k 的值

c=fac(n)/(fac(k)*fac(n-k));//3 次调用函数 fac,求 n! , k! , (n-k) !

形参数列表:为外界(即主调函数)要传给本函数的数据。 函数体: 由声明部分和执行部分构成。其中声明部分是对函数内使用的变量类型等进行定义和声明;
执行部分是实现函数功能的语句序列。

105

4.3 函数参数和函数的值(P91)
4.3.1 形参与实参的概念
函数定义中的参数称为形参,函数调用中的参数称为实参。 其作用是:实现函数之间的数据传递。 例 4.3 利用自定义函数求两个整数中的较大数。(P91 例 4.2) #include <iostream> using namespace std;

int max(int x,int y) { int z; z=x>y?x:y; return(z); }
int main() { int a,b,c;

//指定形参 x,y

cout<<"please enter two integer numbers:"; cin>>a>>b; c=max(a,b); cout<<"max="<<c<<endl; return 0; } 1.关于形参的说明
106

//a,b 为实参

①形参在函数定义中并不占用内存空间, 他们只是表示上的一 种形式,仅当该函数被调用时,才给形参分配存储单元。此时形
参的值为主调函数中对应实参传递给的数据。被调函数执行完后,又将释放形参所占用的存储单元;

②形参在函数定义中必须进行类型说明;
注:形参仅是形式上的,取什么名字于程序的结果毫无妨。

2.关于实参的说明 ①实参是传值的。实参可以是常量、变量或表达式, 但在函数调用
时,他必是可求的值。在执行函数调用时,先计算每个实参的值,然后把值传给对应的形参;

②实参在类型、个数、顺序上要与形参一一对应,否则会产生意想不
到的结果



③函数调用时发生的数据传递是单向的。即每次调用时,实参的值就会传递
给形参,但形参的变化不会影响到实参。

例 4.4 交换两个变量的值。 问题分析:原本希望通过调用 swap()函数来交换变量 x 和 y 的值,但形参 a 和 b 的变化并没
有影响到实参 x 和 y。为什么?

#include <iostream> using namespace std; void swap(int a,int b) { int tmp; cout<<"a=‖<<a<<‖, b="<<b<<endl;; tmp=a;a=b;b=tmp; cout<<"a=‖<<a<<‖, b="<<b<<endl;;

}
107

int main() { int x=20,y=-40; cout<<‖x=‖<<x<<‖,y=‖<<y<<endl; swap(x,y); cout<<‖x=‖<<x<<‖,y=‖<<y<<endl; return 0; }

4.4 函数的调用与返回值(P94)
一、函数的调用 1.函数的调用方式 函数调用的一般形式为: 函数名(实参表) 或 函数名( ) 说明:
①函数的调用既可作为一个值出现在表达式中,也可作为一条单独语句;

例如:有如下一个名为 add 的函数:

double add(double a,double b) { double s;
108

s=a+b; return s; }
则可有以下调用方式

: y=add(2,4);

//表达式调用



for(y=0,i=1;i<=5;i++) y=add( y, i) ;
再例如,例 6.8 中的

: swap(x,y);
主调函数

//独立语句调用

②无论是有参函数调用,还是无参函数调用,括号()不能省略; ③函数的调用过程: 被调函数

首先将主调函数中实参的值传递给被调函数中对应的形参(如果是有参函数)然后将控制权交给被调 函数,再执行被调函数的函数体,当被调函数执行完毕后或者带给主调函数一个返回值或者不带返回值, 最后将控制权重新交给主调函数。

例 4.5

对例 4.4 进一步修改为:求三个整数中的最大数。

#include <iostream> using namespace std;

int max(int x,int y) { int z; z=x>y?x:y;

//指定形参 x,y

109

return(z); }
int main() {

int a,b,c; cout<<"please input three number a,b,c:"; cin>>a>>b>>c; cout<<‖Max is :"<<max(a,max(b,c) )<<endl;; return 0;

}

2.函数调用时的语法要求
(1)调用函数时,函数名必须与所调用的函数名字保持一致; (2)实参的个数及类型要与形参的个数及类型一致; (3)C 规定:函数必须先定义,后调用(函数返回值为 int 与 char 类型的函数除外) ; (4)在 C 中,函数可以直接或间接的调用自己(即递归调用) ( 第 6.7 节)

二.函数的返回值
函数是完成特定功能的程序段,主调函数通过函数调用完成一定的功能,有时调用函数的目的就是为 了得到一个计算结果,这就是函数的返回值。

return 语句的一般形式: return [(表达式)] 或 return [()]
说明:

①return 语句有两个作用: 一是退出被调函数立即将控制权交 给主调函数; 二是回送一个函数值, 即函数的返回值是通过被调函数中的 return
语句得到的。

②return 语句的执行过程是:先计算表达式的值,再将计算结
110

果返给主调函数。
如例 4.4 中的 max 函数可改为:

int max(int x,int y) { return(x>y?x:y); }

//指定形参 x,y

③return 语句中表达式的类型应与函数定义中的函数类型相 容。若函数定义中没有指名函数类型,则系统自动处理为整型。若 return 语句中表达式的类型与函数
类型不一致,则系统自动将表达式的值转换成函数类型后再传给主调函数,即函数类型决定了返回值的类 型。

④若函数不带返回值,此时,用 void 来定义函数类型,以明 确表明该函数是无返回值的,从而可提高程序的正确性。

三、函数的声明(P95)
1、函数声明的意义
函数声明的目的是为了

使编译系统在编译阶段对函数的调用进行合

法性检查。判断形参与实参的类型及个数是否一致。若没有声明函数就直接使用,那么,只有在
运行时才会发现实参与形参不匹配的错误,就需要重新调试程序从而加大了工作量。

2、函数声明的方式 函数类型 函数名(参数类型 1,参数类型 2,?)
函数名(参数类型 1,参数名 1,参数类型 2,参数名 2?)


函数类型

例 4.6 对被调函数作声明

(P95)

#include <iostream>
111

using namespace std; int main() { float add(float,float); /*函数声明*/ float a,b,c; cout<<"please enter a,b:"; cin>>a>>b; c=add(a,b); cout<<"sum="<<c<<endl; return 0; }

float add(float x,float y) { float z; z=x+y; return (z); }
注:当被调函数的定义出现在主调函数之前可省略对函数的声明

112

4.5 内置函数 (P97)
一、内置函数的定义及引入的目的 inline 返回值类型 函数名称 (参数类型 参数名称。 。 。 ) { 函数体 }
引入内联函数的目的是:

为了提高程序的运行效率。

例 4.7 内联函数的使用 #include<iostream> using namespace std; inline double circle(double r) { { return 3.1416*r*r; for(int i=1;i<=3;i++) cout<<"r= "<<i<<" return 0; } 二、几点说明
①内置函数必须先定义(不是声明) ,而后再使用; ②内置函数体内一般不能有循环语句和开关语句; ③在类结构中所以在类说明体内定义的函数都是内置函数; ④使用内置函数是一种用空间换时间的措施, 一般适用于较短的函数。
113

}

int main() area="<<circle(i)<<endl;

4.6 函数的重载 (P99)
一、函数重载的含义
C++允许创建多个名称相同的函数,称为函数重载。这些同名函数的参数表必须有所区别,这种区别 可以是参数类型,也可以是参数个数或两方面兼有。

例 4.8 参数类型不同的重载函数 求 3 个数中的最大数(分别考虑整数、实数、长整数的情况

#include<iostream> using namespace std; int max(int a,int b,int c) { if(b>a) a=b; if(c>a) a=c; return a; } float max(float a,float b,float c) { if(b>a) a=b; if(c>a) a=c; return a; } long max(long a,long b,long c) { if(b>a) a=b; if(c>a) a=c; return a; }
114

int main() { int a,b,c;float d,e,f;long g,h,i; cin>>a>>b>>c; cin>>d>>e>>f; cin>>g>>h>>i; int m; m=max(a,b,c); cout<<"max-i="<<m<<endl; float n; n=max(d,e,f); cout<<"max-f="<<n<<endl; long p; p=max(g,h,i); cout<<"max-l="<<p<<endl; return 0; }
例 4.9 参数个数不同的重载函数

#include<iostream> using namespace std; int add(int x,int y) { return x+y; } int add(int x,int y,int z) { return x+y+z; }
115

int main() { int a=3,b=4,c=5; cout<<a<<'+'<<b<<'='<<add(a,b)<<endl;
cout<<a<<'+'<<b<<'+'<<c<<'='<<add(a,b,c)<<endl;

return 0; }
二、说明
(1)返回类型不在参数匹配检查之列; (2)在函数调用时,如果给出的实参和形参不相符,C++的编译器将 会自动做类型转换; (不提倡) (3)让重载执行不同的功能,是不好的编程风格。同名函数应具有相 同的功能。如果定义一个 abs()函数而返回的却是一个数的平方根, 则该程序的可读性将受到破坏。

116

4.7 函数的模板 (P102)
一、模板的概念
模板是 C++语言中代码重用的一种实现方法。 使用模板可以实现用同一代码实现一组相关函数或一组 相关类。 由于 C++的程序结构主要是由函数和类构成的,因此,模板也具有两种不同的形式:函数模板和类模 板。根据模板用户可构造模板函数和模板类。 模 板 (函数模板和类模板) 实例化 模板函数 实例化 模板类 实例化 对 象

二、函数模板的说明 所谓函数模板是指:建立一个通用的函数,其函数类型和 函数形参类型不具体指定。用一个虚拟的类型来代表。 函数模板说明的一般形式: template < typelate 类型参数> 返回类型 函数名(模板形参表) { } 或: template < class 类型参数> 返回类型 函数名(模板形参表)
117

//通用函数定义

函数体;

//通用函数定义

{ }

函数体;

例 4.9 见 P102 例 4.7

#include<iostream> using namespace std; template < typelate T> //模板声明 T max(T a,T b,T c) //定义通用函数 { if(b>a) a=b; if(c>a) a=c; return a; } int main() { int a1=4,a2=5,a3=8,a; float b1=2.3,b2=4.5,b3=1.1, b ; long c1=234561,c2=897766,c3=7877777, c ; a=max(a1,a2,a3); b=max(b1,b2,b3); c=max(c1,c2,c3); cout<<"max-a="<<a<<endl; cout<<"max-b"<<b<<endl; cout<<"max-c="<<c<<endl; return 0; }
118

说明:
1. 关键字 typename 指定了函数模板的类型参数,表示“任何预定义的数据类型或用户自定 义类型” 。在使用函数模板时,typename(或 class)后面的类型参数要用实际的数据类型替 代它。 2.函数模板代表的是一类函数,它不是一个实实在在的函数,编译系统并不产生任何代码, 只有当将其类型参数 T 实例化为某一确定的(数据类型如 int 等), 编译系统便生成一个重载函 数,该函数的函数体与函数模板的函数体相同。该重载函数称为模板函数。

“将函数模板的类型参数 T 实例化的参数称为模板实参, 用模板实参实例化的函数称为模板函数” 。 例 4.10 定义一个求绝对值的函数模板

#include<iostream> using namespace std; template<typename T> T abs(T x) { return x<0?-x:x; } int main() { int n=-5; double d=-5.5; cout<<abs(n)<<endl; cout<<abs(d)<<endl; return 0; }

119

分析:
编译器从调用 abs()时实际参数的类型,推导出函数模板的类型参数,例如,调用表达式 abs(n) 由于实际参数 n 为 int 型,所以推导出模板中类型参数 T 为 int。 当类型参数的含义确定后,编译器将以函数模板为样板,生成一个函数:

int abs(int x) { return x<0? –x:x;
说明:
(1)函数模板代表了一类函数,模板函数表示某一具体的函数;

}

(2)函数模板是定义重载函数的一种工具,一个函数模板是为一种原型函数生成一个模板函数,不同原 型的模板函数是重载的,这样就使得一个函数只需编码一次就能用于某个范围不同类型的对象上,因此, 可以说函数模板是提供一组重载函数的样板。

例 4.11 有两个类型参数的函数模板

#include<iostream> using namespace std; template<typename type1,typename type2> void fun(type1 x,type2 y) { cout<<x<<' '<<y<<endl; } int main() { fun(10,"hao"); fun(0.123,10l); return 0;
120

} 4.8 有默认参数的函数 (P103)
一、引入带有缺省参数值的函数的意义 C++允许在函数定义时,为一个或多个形参指定缺省值, 则在函数调用时,若缺省了其中的某些实参,C++会自动地以 缺省值作为相应的参数值。 例如: int init(int x=5,int y=0); //等价于 x=100,y=80 //等价于 x=25,y=10 //等价于 x=5,y=10 则允许有如下调用: init(100,80); init(25); init( );

例 4.12 求 2 个或 3 个正整数中的最大数,用带有默认参数的 函数实现。 (P104 例 4.8)

#include <iostream> using namespace std; int main() { int max(int a,int b,int c=0);
121

//函数声明

int a,b,c; cin>>a>>b>>c; cout<<"max(a,b,c)="<<max(a,b,c)<<endl; cout<<"max(a,b)="<<max(a,b)<<endl; return 0; } int max(int a,int b,int c) { if(b>a) a=b; if(c>a) a=c; return a; }

2. 几点说明
(1)在函数原型中,所以取缺省值的参数都必须出现在不取缺省值的参数的右 边; 例: int fun(int I,int k,int j=5);

(2)在函数调用时,若某个参数省略,则其后的参数,皆应省略而采用缺省值。 (3) 一个函数不能既作为重载函数, 又作为有默认参数的函数, 以避免出现 “二 义性” 。

122

4.9 函数的嵌套调用 (P105)
在一个函数的调用过程中又调用了其他函数 例 4.13 计算:1!+2!+3!+ ?? +10!

#include <iostream> using namespace std; long fac(int p) { long t=1, j; for(j=1;j<=p;j++) t=t*j; return t; } long sum(int n) { long k,s=0; for(k=1;k<=n;k++) s=s+fac(k); retuen s; } void main() { long add; add=sum(10); cout<<―add=‖<<add<<endl; }
123

例 4.14 编写函数 isprime(int a)用来判断自变 量 a 是否为素数,若是素数,函数返回 1,否则返 回 0。

#include <iostream> #include<math.h> using namespace std;

int isprime(int); //函数声明 void main() { int x; cout<<"enter a integer number: "; cin>>x; if(isprime(x)) cout<<x<<‖ is prime"<<endl; else cout<<x<<‖ is not prime"<<endl; } int isprime(int a) { int i; for(i=2;i<=sqrt((double)a);i++) if(a%i==0) return 0; return 1; }

124

例 4.15 编写函数,验证任意偶数为两个素数之和 并输出这两个素数。

#include <iostream> #include<math.h> using namespace std;

int isprime(int); void even(int);

//函数声明 //函数声明

void main() { int a; cout<<"enter a even number: "; cin>>a; if(a%2==0) even(a); else
cout<<a<<‖ isn't even number"<<endl;
}

isprime(int a) { int i; for(i=2;i<=sqrt((double)a) ; i++) if(a%i==0) return 0;
125

return 1; }
void even(int x) { int i; for(i=2;i<=x/2;i++)

if ( isprime(i) && isprime(x-i) )
{ } } 例 4.16 编写函数 sum(int n)用以求 ∑ f( x ) (x=0~n) ,和数作为函数值返回。 这里: f(x)=x2+1 cout<< x <<"=‖<< i <<‖+‖<<x-i<<endl; break ;

#include <iostream> using namespace std;

int sum(int); int f(int); int main() { int a,b; cout<<"enter a integer number: "; cin>>a;
126

b=sum(a); cout<<"a=‖<<a<<‖, sum="<<b<<endl; return 0; } f(int x) { return x*x+1; sum(int n) { int x,s=0; for(x=0;x<=n;x++) s+=f(x); return s;
}

}

127

4.10 函数的递归调用 (P109) 一、函数递归调用的定义
一个函数在他的函数体内直接或间接地调用他自身, 称为 递归调用。

f 函数

f1 函数

f2 函数

调用 f 函数

调用 f2 函数

调用 f1 函数

直接调用

间接调用

二、一个问题可以采用递归方法解决的必要条件 为:
(1)可以把要解决的问题转化为一个新的问题,而这个新的 问题的解法仍与原来的解法相同, 只是所处理的对象有规律地 递增或递减; (2)可以应用这个转化过程使问题得到解决; (3)必定要有一个明确的结束递归的条件。

三、递归调用的过程
从设计的角度考虑,递归算法涉及到两个问题:

一是递归的公式, 一是递

归的终止条件。递归过程可以表述为:

if(递归终结条件) return (终结条件下的值)
128

else return(递归公式)
例 4.17 用递归法计算 n! ,用公式表示为:

n!=n×(n-1) 1!=1
(P111 例 4.11)

(n≥2) (n=0,1)

#include <iostream> using namespace std; long power(int); //函数声明 int main() { int n; long y; cout<<"please input an integer:"; cin>>n; y=power(n); cout<<n<<"!="<<y<<endl; return 0; } long power(int n)
129

{ long f; if(n<0) { cout<<"n<0,data error!"<<endl; f=-1; } else if (n==0||n==1) f=1; else f=power(n-1)*n; return f; }
main() 调用 power(5) 输出 120 power(5) 5* 调 用 power (4) 120 输出 120 power(4) 4* 调 用 power (3) 24 输出 120 power(3) 3* 调 用 power (2) 6 输出 120 power(2) 2* 调 用 power (1) 2 输出 120 power(1)

1

例 4.18 p86 习题: 猴子吃桃子的问题 (用递归函数)

#include <iostream> using namespace std;
int ab(int n) { if(n==10) return 1; else return 2*(ab(n+1)+1) ; } int main()
130

{ int total; total=ab(1); cout<<‖ total=‖<<total<<endl; return 0; }
注:ab(n+1)=ab(n)/2-1

131

4.11 常用库函数(补充)
一、学习库函数应从以下几个方法学习 ? 了解所需函数的功能; ? 了解函数的原型即声明形式; ? 了解使用该函数所需要包含的头文件。 二、标准库函数的调用 对库函数的一般调用形式: 函数名(参数表) 1.出现在表达式中 4 例如:计算: y=x +6 可使用语句: y=pow(x,4)+6; 2.作为独立的语句完成某种操作

sort(x,y);
三、常用库函数 1.常用数学函数(包含在头文件:cmath.h 中) (1)取绝对值函数 函数原型:

int abs(int x) double fabs(double x)

等价于:|x|

例如:输入任意一个整数,求其绝对值。 cin>>n;
132

cout<<abs(n);
(2)指数函数与对数函数 函数原型:

double exp(double x) double log(double x) double log10(double x)
(3)开方运算 函数原型:

等价于:ex 等价于:ln x 等价于:lg x

double sqrt(double x);
(4)任意底与幂的乘方运算 函数原型:

等价于:√x

double pow(double x,double y); 等价于:xy
(5)三角函数 函数原型: (正弦、余弦、正切) double cos(double x) 等价于:cos(x) double sin(double x) 等价于:sin(x) double tan(double x) 等价于:tg(x)
说明:函数参数 x 的单位是弧度。

函数原型: (反正弦、反余弦、反正切) double acos(double x) double asin(double x) double atan(double x)
说明:函数的返回值弧度值。
133

4.12 局部变量与全局变量(P112)
一、变量的作用域 变量的作用域,即指变量的合法使用范围。 变量的作用域与定义变量的位置相关。在函数 内部(或复合语句内部)定义的变量称为局部变量 (内部变量) ;在函数外任意位置定义的变量称为 全局变量(外部变量) 。 局部变量的作用域是定义他的函数内或复合 语句内,也即是说,一个函数内定义的局部变量不 能被其他函数所引用。
说明: 局部变量的特性有助于实现信息隐蔽,即使不同的函数定义了同名的局部变量,也不会相互影响。

例 4.19 分析如下程序的运行结果

#include <iostream> using namespace std; int main() { int i=1,j=3; cout<<i++<<‖,‖; { int i=0; i+=j*2; cout<<i<<‖,‖<<j<<‖,‖;
134

} cout<<i<<‖,‖<<j<<endl; }
运行结果: 1,6,3,2,3
注:阅读 P113 中的说明:

二、全局变量的作用域 全局变量的作用域是从定义他的位置开始,直 至他所在的源程序文件的结束。 例 4.20 分析如下程序的运行结果

#include <iostream> using namespace std;
int sum; void fun() { int sum=20 ; cout<<"** fun }

**"<<sum<<endl;

void main()
{ cout<<‖sum=‖<<sum<<endl; sum=10;
135

cout<<‖sum=‖<<sum<<endl; fun(); cout<<‖sum=‖<<sum<<endl; }
说明: (1)当全局变量和函数中的局部变量同名时,则在该函数中,此全局变量被屏 蔽; (2)不提倡过多使用全局变量。 (3)一般约定,全局变量的第一个字母大写。

例 4.21 对例 4.4 修订:交换两个变量的值 #include <iostream> using namespace std; int x=20,y=-40; void swap( ) { int tmp; tmp=x;x=y;y=tmp;

}
int main() { cout<<‖x=‖<<x<<‖,y=‖<<y<<endl; swap(); cout<<‖x=‖<<x<<‖,y=‖<<y<<endl;
136

return 0; }
注意: 全局变量的使用增加了函数之间数据传递的途径,在全局变量的作用域内 的任何函数都能引用该全局变量,一个函数对全局变量的修改,能影响到其他 应用该变量的函数; 此外,全局变量的使用也会使得函数的通用性降低,从结构化程序设计方 法的角度考虑,函数应是完成单一功能的程序段,过多使用全局变量,会使函 数之间的依赖性增加、耦合性高。

注:阅读 P114 中的说明:

4.13 变量的存储类别(P115)
变量的存储类别,是用来说明变量的存储位 置,变量的存储类别决定着变量的生存期。所谓生 存期是指变量在内存或寄存器中存在时间的长短 在 C++中的存储类型有: auto:自动 extern:外部 static:静态 register:寄存器
137

一、动态存储方式与静态存储方式 C++程序运行时占用的内存空间一般分为 3 部 分:
程序区 静态存储区 动态存储区

程序运行期间数据分别存放在静态存储区和 动态存储区,其中静态存储区用来存放程序运行期 间需占用固定存储单元的变量,如全局变量和静态 类别的局部变量;动态存储区用来存放不需要长期 占用内存单元,可根据需要动态地分配和回收空间 的内部变量,如局部变量、函数形参与函数调用时 的返回地址等。 (1)动态存储类别的变量 当进入他的函数或复合语句时被分配存储空 间,当离开时所占内存空间被释放。动态存储类别 是一种节省内存的存储方式,他在需要时被建立, 不需要时被撤消。动态存储类别有两种方式:auto 类型的变量被存放在内存的动态存储区; register 类型的变量被存放于寄存器中。 (2)静态存储类别的变量 在源程序编译时被分配空间,从程序开始执
138

行,一直占用固定的存储空间,直至程序结束,才 会释放所占用的内存空间。静态存储类别的变量可 以用 static、extern 说明。 二、自动(auto)变量 当局部变量在定义时,如果没有指定存储类或 使用了自动(auto)说明符,系统将该局部变量视 为: auto 类别。 auto 类别的变量被分配在内存的动 态存储区,其特点为:每当程序执行进入函数体(或复
合语句)时,系统自动为 auto 类别的变量分配其存储单元; 而退出时马上释放这些存储单元。
注:关键字 auto 可以省略

三、静态存储类的局部变量 用 static 来说明一个局部变量时,该变量称为 静态局部变量。 静态局部变量具有以下特点:
(1)静态局部变量在程序运行期间,占有永久性存储单元, 即使退出函数,其值仍然保留。即,静态局部变量的生存期将 一直延长到整个程序运行结束; (2)静态局部变量的初值在程序编译时赋予,对未赋初值的 静态局部变量,程序编译时默认为 0。

例 4.22 P117 例 4.12 静态局部变量的值
139

#include <iostream> using namespace std; int f(int a) { auto int b=0; static int c=3; b=b+1; c=c+1; return a+b+c; } int main() { int a=2,i; for(i=0;i<3;i++) cout<<f(a)<<" "; cout<<endl; return 0; } 分析运行结果: 1.关于静态变量的说明:阅读 P118 2.什么情况下使用静态变量? 3.建议如无必要,不要多用静态变量.为什么?
140

例 4.23 P118 例 4.13 利用静态局部变量计算 1~5 的阶乘值 #include <iostream> using namespace std; int fac(int); int main() { int i; for(i=1;i<=5;i++) cout<<i<<"!="<<fac(i)<<endl; return 0; } int fac(int n) { static int f=1; f=f*n; return f; } 四、寄存器(register)变量
寄存器变量也是自动类变量,其区别在于:编译程序将寄 存器变量的值存储在 CPU 的寄存器中,而系统对寄存器的访 问要比访问内存的速度快。因此,当程序对运行速度有较高要
141

求时,可以把那些频繁引用的少数变量,存放在寄存器中将有 助于提高程序的运行速度。

例:4.24 建立一个 power 函数用于计算 xn #include <iostream> using namespace std; int power(int x,register int n) { register int p; for(p=1;n;n--) p=p*x; return p; } int main() { int s ; s=power(5,3); cout<<s<<endl; } 几点说明:
(1)CPU 中的寄存器数目有限; (2)寄存器变量没有地址,因此不能对他进行求地址运算; (3)寄存器变量的说明最好放在如复合语句中,以便用完后 即释放,以提高其利用率。
142

(4)目前许多优化的编译系统会自动识别使用频繁的变量, 而后自动将其存放在寄存器中。

五、用 extern 说明符扩展全局变量的作用域 1.在同一编译单位内用 extern 说明符来扩展全局 变量的作用域
当全局变量定义在后,使用他函数在前时,应该在引用他 的函数中用 extern 对其进行说明,其目的是告诉系统,该全 局变量的作用域从 extern 说明处起延伸到该函数的末尾。

例:4.25 P120 例 4.14 用 extern 对外部变量提前引 用声明,扩展其作用域。 #include <iostream> using namespace std; int max(int,int); int main() { extern int a,b; cout<<max(a,b)<<endl; return 0; } int a=15,b=-7; int max(int x,int y) { int z; z=x>y?x:y;
143

return z; } 2.在不同编译单位内用 extern 说明符来扩展全局 变量的作用域
当一个程序是由多个编译单位组成, 并且在每个文件中均 需引用同一个全局变量时, 可在其中的一个文件中定义全局变 量,而在其他用到这些全局变量的文件中用 extern 对其进行 说明,使其作用域延伸到该文件中。

六、用 static 声明静态全局(外部)变量 (P121)
用 static 声明一个静态全局变量的目的在于限制该全局 变量只可在本编译单位的使用,而不能被其他编译单位所引 用。

4.14 变量属性小结
研读 P122~124

4.15 内部函数和外部函数(P125)
一个 C 程序可以包含多个函数, 这些函数又可能分布在多 个文件中。 函数的定义是独立的, 而函数之间存在着调用关系。 根据能否被其他源文件所调用, 可将函数分为内部函数和 外部函数
144

一、用 static 说明函数(内部函数) 在定义一个函数时,若加上说明符 static,则 该函数称为静态函数或内部函数。 静态函数的特征:只限于本编译单位中的其他 函数调用 二、用 extern 说明函数(外部函数) 在定义一个函数时,若省略或加上说明符 extern,则该函数称为外部函数。 外部函数的特征:可以被其他编译单位中的函 数调用。
注:在需要调用其他编译单位的外部函数的文件中,要用 extern 声明所用函数是外部函数。

例:4.26 P125 例 4.15 关于外部函数的应用 //file1.cpp #include <iostream> using namespace std; int main() { extern int max(int,int); int a,b; cin>>a>>b; cout<<max(a,b)<<endl;
145

return 0; } //file2.cpp int max(int x,int y) { int z; z=x>y?x:y; return z; }

4.16 关于变量的声明和定义(P124)
1. 理解声明与定义的区别; 2. 何时需要定义?何时需要声明?

146

4.17 预处理命令(P127)
C++中预处理命令的作用是: 告诉编译系统在对源程

序编译之前应该做什么。 正确地使用编译预处理功能可
有效底提高程序的开发效率。

编译预处理命令有三种:文件包含、宏定义和 条件编译。为了和程序语句区别,编译预处理命令 以#号开头(前面没有空格)且占用一个单独的书 写行,命令尾不使用分号作为结束符。 一、 宏定义 #define(P127) 所谓宏定义就是 用一些比较容易理解或具有 物理意义的符号代替另一些数据或文本,其意义在 于:不仅可提高程序的易读性,还便于程序的维护 和修改。 1.不代参数的宏定义
就是用一个指定的标识符(即宏名)来代表一个字符串。

宏定义的一般形式为: #define 标识符 字符串 例:4.27 定义宏表示圆周率常数 #include <iostream> using namespace std; #define PI 3.14159
147

void main() { float c; c=2*PI*3.0; cout<<"c="<<c<<endl; } 例:4.28 定义宏表示代码行 #include <iostream> using namespace std; #define PR cout<<endl; void main() { cout<<"*********"; PR cout<<"*********"; } 说明:
(1)宏名习惯上一般用大写字母表示,以区别于变量名; (2)宏定义是用宏名代替一个字符串,他只是做简单的替换, 不做语法检查;

例如:

#define

PI

3.i4i159 。

只要当编译系统在编译已被宏代换的源程序时,才会检查出错误

(3)宏定义不同于 C 语句,不能在末尾加分号; (4)在宏定义命令中,可以使用已经定义过的宏名,即宏定
148

义可以层层代换。

例:4.29 分析如下程序结果 #include <iostream> using namespace std; #define A 40 #define B1 (A+20) #define B2 A+20 #define C1 B1*A #define C2 B2*A void main() { cout<<"c1="<<C1<<endl; cout<<"c2="<<C2<<endl; } 分析:置换后: cout<<‖c1=”<<(40+20)*40)<<end; cout<<‖c1=”<<(40+20*40)<<endl;
(5)同一宏名不能重复定义;

2.带参数的宏定义
带参数的宏定义是更高级的宏定义, 不仅要进行字符串替 换,同时还要进行参数替换。

一般形式为:
149

#define 宏名(参数表) 字符串 例如: #define POWER(x) ( ( x) *( x) ) 其中,POWER 是宏名,x 是形参。 例:4.30 分析程序 #include <iostream> using namespace std; #define POWER(x) ((x)*(x)) void main() { int a=4,b=6,c; c=POWER(a+b); cout<<"c="<<c<<endl; }
分析:在程序编译时,进行宏展开即为:

c=( (a+b)*(a+b) )
若定义为:

#define
则宏展开为:

POWER(x)

x*x

c=a+b*a+b
*带参数的宏与函数比较 ①在使用形式和特性上与函数相似,但本质不同:
150

②函数的调用是在程序运行时处理的,而宏的代换是在编译之前进行的; ③函数调用时需先求出实参表达式的值,然后代入形参,而使用带参数的 宏只是进行简单的字符替换。例如上例中的 POWER(a+b)在替换时并 不先求 a+b 的值,而只是将实参 a+b 代替形参 x; ④函数调用时存在着从实参向形参的传递数据的过程,而带参数的宏不存 在这种值的传递,也没有返回值的概念; ⑤函数调用时,对使用的实参有一定的数据类型的限制,即一般要求实参 与形参类型一致,而带参数的宏的实参可以是任意类型的数据; ⑥使用函数调用会占用较多的运行时间,而宏替换只占编译时间。

3. 取消宏定义 #undef 宏名。 例如: #define PI main() … #undef PI 3.14

二、文件包含处理 (P128)
文件包含处理#include 的作用是将已定义好的头文件包 含到代码文件中。

编译预处理中的文件包含通常有以下两种形式: 形式一:#include〈文件名〉
151

形式二:#include“文件名” 例如: #include〈iostream.h〉 #include〈cmath〉

文件包含的功能是:
在编译源程序之前,用指定文件中(如 iostream.h)的 内容取代该预处理命令。即是从磁盘中读取该文件,然后把他 写入源程序中预处理命令#include 的位置上,使他成为源程 序的一部分,然后和源程序一起作为一个整体进行编译。
f1.c # include〈f2.c〉 包含 A B B A f2.c f1.c

说明:
(1)形式一通常用于系统头文件的嵌入,形式二用于用户创 建的某个代码文件的嵌入; (2)通常,在开发较大的 C++程序时,会将一些常用的宏定 义、结构类型定义、函数说明语句等由多个开发员共用的一些
152

信息统统放在一个文件中,该文件的后缀通常为 .h(h 表示 header,用 .c 也可以) ,称为标题文件或头文件。每个程序 员都可以用一个#include 命令将这个头文件包含在自己的文 件加以使用,这样可以提供一种标准化手段,即每个程序员都 使用具有相同值的相同定义。此外使每个程序员节省时间开 销,减少错误的发生。

案例:分析如下程序 用户自定义头文件:format.h #define PRINTD(d) printf("integer out:%d\n",d); #define PRINTF(f) printf("float out:%f\n",f); #define PRINTS(s) printf("string out:%s\n",s); #include<stdio.h> #include<conio.h> #include"format.h" 关于#include 命令的几点说明:
①一个#include 命令只能指定一个被包含文件,若要包含多 个文件,需多次使用#include 命令; ②#include 命令可以嵌套使用;

例如:在程序 f1.c 中有如下行:
153

#include “f2.c” 而在文件 f2.c 中又有如下行: #include “f3.c” 则等价于在文件 f1.c 中包含如下行: #include “f2.c” #include “f3.c” 注意以上两个命令的顺序。
③#include 两种命令的区别在于:当用“ 〈 〉 ”包围文件时, 其意义是指示编译系统按系统设定的标准方式搜索文件; 而用 双引号包围文件时,系统先在源文件(如 f1.c)所在目录中 搜索文件, 若找不到, 再按系统设定的标准方式搜索其他目录。

第五章 数
5.1 数组的概念
在解决实际问题时,往往会需要



处理一批具有相同的数据类型
154

并且关系密切的变量。
例如:对一个班的学生成绩进行处理,计算其个人平均成绩、学科平均成绩,个人名次排序等。 数组是具有一定顺序关系的若干变量的集合体,组成数组的变量成为该数组的元素变量,简称元素。 在 C++中,数组的元素变量用数组名后面跟上带有方括号[ ]的下标表示。

如:a[10],data[20],s[30],b[5][6];
其中带有一个方括号的称为一维数组,带有两个以上方括号的称为二维数组、三维数组等,统称为多 维数组。方括号中的下标用来表示元素在数组中的位置。 数组在内存中连续分配一片存储单元

见 P134 图 5.1

a[0]

a[1]

a[2]

a[3]

a[4]

a[5]

a[6]

a[7]

2000

2002

2004

2006

2008

2010

2012

2014

5.2 一维数组的定义和引用 一、一维数组的定义 1.一维数组的定义格式: 类型标识符 数组名 [ 常量表达式 ] 例如: int data[20]
155

表明定义了一个名字叫 data,长度为 20 的整型一维数组,即该数组有 20 个整数类型的元素,可以用

来存储 20 个整数类型的数据。

2.说明:
①数组名的命名应符合标识符的命名规则; ②数组名后面方括号内的数据是数组的长度,也即是数组元素的个数,它可以是常量, 也可以是常量表达式,但必须是整型。不能是变量或变量表达式(即不允许作动态定义) 。 ③C 编译系统为数组分配连续的存储单元,数组元素的相对次序由其下标来表示。下标 从 0 开始。

a[0]

a[1]

a[2]

a[3]

a[4]

a[5]

a[6]

a[7]

一般的,含有 n 个元素的数组,其下标范围实 0~(n-1) ④相同类型的数组,可以放在一个说明行中,数组之间用逗号分隔。

二、一维数组的初始化 如:
说明:
①将数组元素的初值放在一对花括号中,所赋初值的类型必须与定义数组的类型一致,各个初值之间 用逗号分隔;系统将按初值的顺序,顺次给数组元素赋值; ②所赋初值的个数不能超过数组元素的个数(数组的长度) ,但可以少于数组元素的个数,此时相当 于给数组的前一部分元素赋值,而后面的元素由系统自动地赋值为 0;

int s[5]={ 0,1,2,3,4 }

例如: int a[5]={1,2,3} 相当于:a[0]=1,a[1]=2,a[2]=3,a[3]=0,a[4]=0,
③若给数组的所有元素赋初值,可以省略数组的长度,

例如: int ar[ ]={ 3,2,4,6,8} 相当于: int ar[5]={3,2,4,6,8}
④若在数组定义之后,再初始化数组,则不能成组赋值,只能一次给一个元素赋值。

例如:

int w[4]; w[4]={23,2,34,5}

是错误的赋值方式。

三、一维数组的引用
数组必须先定义,然后再使用。C++规定,数组整体不能参加数据处理,即不能向数组整体赋值,数
156

组作为一个整体也不能参加各种运算,

参加数据处理和运算的只能是

数组元素。 数组元素的表示形式为: 数组名 [下标]
其中,下标可以是整数类型的常量、变量或表达式。

例 5.1 输入 10 个整数,并按其逆序输出。 #include <iostream> using namespace std; int main() { int i,a[10]; for (i=0;i<10;i++) { cout<<"please input ―<< i+1<<‖data:"; cin>>a[i]; } for (i=9;i>=0;i--) cout<<a[i]<<‖ ―; cout<<endl; return 0; } 例 5.2 编写程序,输入 10 个整数,求出其中的最 大值与最小值并输出。 #include <iostream> using namespace std;
157

int main() { int x[10], i, max, min; cout<<"please enter"; for(i=0;i<10;i++) cin>x[i]; max=min=x[0]; for(i=1;i<10;i++) { if(x[i]>max) max=x[i]; if(x[i]<min) min=x[i]; } cout<<"max=‖<<max<<endl; cout<<‖min="<<min<<endl; return 0; }
说明: ①一个数组元素就是一个变量,他的使用规则与同类型的普通变量相同。 ②定义数组时数组名后面的方括号中的内容和引用数组元素时数组名后面的方括号中的内容的含义是不 同的,前者是数组的长度,而后者是元素的下标。 ③在 C 程序运行时,编译系统不检查数组元素的下标是否越界,若下标越界,可能会发生严重的后果。

例 5.3 编写程序, 输入 10 个整数, 计算其平均值并 输出其中高于平均值的数据。 #include <iostream> using namespace std; int main()
158

{

int x[10], i, aver , sum=0; cout<<"please enter numbers"; for(i=0;i<10;i++) { cin>>x[i]; sum=sum+x[i]; } aver=sum/10; cout<<"aver="<<aver; for(i=0;i<10;i++) if(x[i]>=aver) cout<<i<<‖ ―<<x[i]<<endl; return 0;

}
例 5.4 用数组求解 Fibonacci 数列问题 #include <iostream> #include <iomanip> using namespace std;

int main() { int i; int f[20]={1,1}; for(i=2;i<20;i++) f[i]=f[i-2]+f[i-1];
159

for(i=0;i<20;i++) { if(i%5==0) cout<<endl; cout<<setw(8)<<f[i]; } cout<<endl; return 0;
} 例 5. 5 排序的基本方法一: 比较交换排序法(按从小到大排序)

基本思想: a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] 第一步:寻找最小值,并且将其存放在 a[0]中;
将 a[0] 分别与 a[1], a[2], a[3]…………..a[9] 比较

for(j=1;j<10;j++) if(a[0]>a[j]) { t=a[0]; a[0]=a[j]; a[j]=t ; } 第二步:在剩余的 9 个数中寻找最小值,并且将其 存放在 a[1]中; for(j=2;j<10;j++) if(a[1]>a[j]) { t=a[1]; a[1]=a[j]; a[j]=t ; } 。 。 。 。 。 。 。 。 #include <iostream> using namespace std; int main()
160

{

int a[10]; int i, j, t; for(i=0;i<10;i++) { cout<<"input the ―<< i+1<<‖ data :"; cin>>a[i]; } cout<<"the array is :"<<endl; for(i=0;i<10;i++) cout<<a[i]<<‖ ―; cout<<endl; for(i=0;i<9;i++) for(j=i+1;j<10;j++) if(a[i]>a[j]) { t=a[i];a[i]=a[j];a[j]=t; cout<<"the sorted array is :"<<endl; for(i=0;i<10;i++) cout<<a[i]<<‖ ―; cout<<endl; return 0; }

}

例 5.6 排序的基本方法二:比较选择交换排序法
说明:该方法与上一种方法比较,减少了交换的次数(注意:比较次数没有减少)

#include<stdio.h>
161

void main() { int a[10], min, mt; int i ,j; for(i=0;i<10;i++) { cout<<"input the ―<< i+1<<‖ data :"; cin>>a[i]; } cout<<"the array is :"<<endl; for(i=0;i<10;i++) cout<<a[i]<<‖ ―; cout<<endl; for(i=0;i<9;i++) { min=i; for(j=i+1;j<10;j++) if(a[min]>a[j]) min=j; { mt=a[i]; a[i]=a[min]; a[min]=mt; } } cout<<"the sorted array is :"<<endl; for(i=0;i<10;i++) cout<<a[i]<<‖ ―; cout<<endl; return 0; }
162

例 5.7 起泡(冒泡)排序法 基本思想:将相邻的两个数 a[0]和 a[1]比较,按要求将这两个数排好序,再将 a[1]和 a[2]比
较。 。 。 。 。依次处理,直到将最后两个相邻的数比较并处理完毕。这时最大的数已换到最后一个数了。这是 第一轮的比较和处理。每进行一轮,把剩下的数中最大的一个移到最后位置。共进行若干轮。直至最大的 数“沉底” ,最小的数“上浮” 。

#include <iostream> using namespace std; int main() { int a[10]; int i,j,t; cout<<"input 10 numbers :"<<endl; for (i=0;i<10;i++) cin>>a[i]; cout<<endl;

for (j=0;j<9;j++) for(i=0;i<9-j;i++) if (a[i]>a[i+1]) { t=a[i];a[i]=a[i+1];a[i+1]=t; }
cout<<"the sorted numbers :"<<endl; for(i=0;i<10;i++)
163

cout<<a[i]<<" "; cout<<endl; return 0; }

5.3 二维数组的定义和引用(P139) 一、二维数组的定义 1.二维数组引入的意义 平面坐标 、二维表格、矩阵 2. 二维数组定义的一般形式
类型说明符 数组名 [常量表达式][ 常量表达式];

例如: 说明:

float a[3][4],s[5][10];

①在 C++中,二维数组中元素在内存中的排列顺序是:
164

按行存放。 a[0][0],a[0][1],a[0][2],a[0][3],a[1][0],a[1][1],a[1][2], ……
②二维数组中,数组名的命名、数据类型的定义方式、数组长 度与类型的选取与一维数组相同; ③数组元素的个数就是两维长度之积;

二、二维数组的初始化(P140~141)
1.分行给二维数组赋初值

例如:
初值。

int a[2][3]={{1,2,3},{4,5,6}};

2.将所有数据写在一个花括号内,按数组排列顺序对各元素赋

例如: 例如

int a[2][3]={1,2,3,4,5,6}; c[4][4]={{1,2,3,4},{4,5,6},{7,8}};

3.部分元素赋初值,则剩余的元素自动赋初值为 0; 4.如果对全部元素都赋初值,则可省略数组第一维的长度,但 应分行赋初值。

例如:

int a[][3]={{1,2,3},{},{4}};

此时,编译系统会根据赋初值的情况,自动得到第一维的长度,上例,编译系统分析出第一维的长度为 3。 注意:若是在定义二维数组后,再给其元素赋值,则需要逐个赋值,不能成组赋值。

三、二维数组元素的引用
二维数组元素的引用方式:

数组名[下标 1] [下标 2]
165

例如: int a[6][3]; 合法引用: a[0][2], a[3][0], a[2+3][1], a[i][j] 不合法引用: a[2][3], a[1.2][2], a[6][0]
说明:

(其中,i,j 为整型变量)

①二维数组的下标范围和一维数组类似,可以是整型的变量、常量、表达式。 ②二维数组元素的表示方式不能写成 b[1,2]等,并且两个下标之间不能有空格。

四、二维数组应用举例 例 5.8 通过键盘给 2*3 的数组输入数据。 第一行:1,2,3。 第二行:10,20,30。 然后按行输出此二维数组。 #include <iostream> using namespace std; int main() { int a[2][3], i, j; cout<<―enter data by line :‖<<endl; for(i=0;i<2;i++) for(j=0;j<3;j++) cin>>a[i][j]; cout<<―output a-arraydata :‖<<endl;
166

for(i=0;i<2;i++) { for(j=0;j<3;j++) cout<<a[i][j]; cout<<endl; } return 0; }

例 5.9 有一个 3*4 矩阵,编一程序求全部元素的平 均值。并把高出平均值的元素的值以及他们所在的 行号和列号打印出来。 69 88 90 50 70 82 96 100 60 92 2 66 #include <iostream> using namespace std; int main() {
int arr[3][4]={{69,88,90,50},{70,82,96,100},{60,90,2,66}};

int i,j; float aver,sum=0; for(i=0;i<3;i++)
167

for(j=0;j<4;j++) sum=sum+arr[i][j]; aver=sum/(3*4); cout<<"aver="<<aver<<endl; cout<<"value row column:"<<endl; for(i=0;i<3;i++) for(j=0;j<4;j++) if(arr[i][j]>aver) cout<<arr[i][j]<<‖,‖<<i<<‖,‖<<j<<endl; return 0; } 例 5.10 有一个 3*4 的矩阵, 求出其中值最大的那个 元素的值及其所在行号和列号。 1 2 3 4 9 8 7 6 -10 10 –5 2 #include <iostream> using namespace std; int main() { int i,j,row=0,colum=0,max;
168

int a[3][4]={{1,2,3,4},{9,8,7,6},{-10,10,-5,2}}; max=a[0][0]; for(i=0;i<=2;i++) for(j=0;j<=3;j++) if(a[i][j]>max) { max=a[i][j]; row=i; colum=j; } cout<<"max=‖<<max<<endl; cout<<"row=‖<<row<<endl; cout<<"colum=‖<<colum<<endl; return 0; } 例 5.11 某班有 6 个学生,每个学生有 5 门成绩。编 一程序,统计每个学生的平均成绩和每门课的平均 成绩。
学生序号 语文成绩 数学成绩 英语成绩 物理成绩 化学成绩

1 2 3

68 88 60

89 99 68

78 77 65
169

98 80 40

90 86 50

4 5 6

65 80 90

68 65 98

80 56 67

90 70 85

78 88 74

问题分析:定义数组: score[6][5]用于存放学生各课的成绩; saver[6] 用于存放每个学生的平均成绩; taver[5] 用于存放每课的平均成绩; #include <iostream> #include <iomanip> using namespace std; int main() { int score[6][5]={{68,89,78,98,90}, {87,99,77,80,86}, {60,68,65,40,50}, {65,68,80,90,78}, {80,65,56,70,88}, {90,60,67,85,74}}; int saver[6],taver[5]; int i,j,sum; for(i=0;i<6;i++)
170

{

sum=0; for(j=0;j<5;j++) sum=sum+score[i][j]; saver[i]=sum/5;

} for(j=0;j<5;j++) { sum=0; for(i=0;i<6;i++) sum=sum+score[i][j]; taver[j]=sum/6; } cout<<endl;
cout<<"No. chinese math english physics chemistry aver"<<endl;

for(i=0;i<6;i++) { cout<<setw(3)<<i+1; for(j=0;j<5;j++) cout<<setw(8)<<score[i][j]; cout<<setw(8)<<saver[i]<<endl; } cout<<" aver"; for(j=0;j<5;j++) cout<<setw(7)<<taver[j]; cout<<endl;
171

return 0; } 例 5.12 输出以下的扬辉三角形 (要求打印出 10 行) 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 。 。 。 。 。 。 #include <iostream> #include <iomanip> using namespace std; int main() { int i, j, a[11][11]; for(i=1;i<11;i++) { a[i][i]=1; a[i][1]=1; } for(i=3;i<11;i++) for(j=2;j<=i-1;j++) a[i][j]=a[i-1][j-1]+a[i-1][j]; for(i=1;i<11;i++)
172

{

for(j=1;j<=i;j++) cout<<setw(6)<<a[i][j]; cout<<endl;

} cout<<endl; return 0; }

5.4 字符数组(P148) 一、字符数组的定义和初始化 所谓字符数组是指数组元素为字符型的数组, 每个数组元素存放一个字符。
注:字符数组的定义、引用、初始化方式和普通数组类似。

一维字符数组的定义形式为: char 数组名[数组长度]; 例如:
173

char arrc[10];
表示定义了一个长度为 10(数组元素为 10 个)的一维字符数组



说明:
①字符数组的引用也是通过数组名和下标来表示的。 如: arrc[0]=‘I‘;arrc[1]=‘ ?;arrc[2]=‘a‘;arrc[3]=‘m‘; arrc[4]=‘ ?;arrc[5]=‘h‘;arrc[6]=‘a‘;arrc[7]=‘p‘; arrc[8]=‘p‘;arrc[9]=‘y‘; ②字符数组的初始化方式与其他数组一样, 可以在定义时初始 化,也可以在定义之后,逐个给数组元素赋值,数组元素被赋 的值应是字符型常量或变量。

如:上例可改为: char arrc[10]={?I‘,‘ ?, ‘a‘,‘m‘,‘ ‘,‘h‘,‘a‘,‘p‘,‘p‘,‘y‘};
同样,如果花括号中提供的初值个数(即字符的个数)大于数组的长度,则按语法错误处理,如果初 值个数小于数组长度, 则只将这些字符赋给数组中前面的元素, 而其余的元素自动赋值为空字符 (即 ‘\0’ ) ; 如果提供的初值个数恰与预定的数组长度相同,则在定义时可以省略数组长度,系统回自动根据初值的个 数确定数组长度。

二、字符数组的赋值与引用
与普通数组一样,只能对单个字符数组元素进行赋值,而不能用赋值语句对整个字符数组进行赋值。

例 5. 13 从键盘输入一行字符, 存放在字符数组中, 然后逆序输出。 #include <iostream>
174

using namespace std; void main() { char a[80],c; int k=0,j; cout<<"\nplease input the chars:"<<endl; cin>>c; while(c!='\n') { a[k++]=c; cin>>c; } for(j=k-1;j>=0;j--) cout<<a[j]; cout<<endl;

} 三、字符串和字符串结束标志(P150)
字符串即是一连串的字符,在 C 中,字符串常量是用加双引号的形式表示。

在 C 中,实际上没有字符串这种数据类型,而 是将字符串是作为一个整体对待的数列,存放在字 符数组中。 需要注意的是:无论是在内存中存储字符串常量,还是用字符数组存储字符串, 编译系统 在处理字符串时,都会自动在字符串的最后一个字 符之后加上‘\0’作为结束标志。也即是对于含有
175

n 个字符的字符串在内存中占 n+1 个字节的存储空 间(其中;第 n+1 个字节用来存放字符串结束标志 ‘\0’ 。 例如: “” : 表示空串,在内存中占 1 个字节,存放空字符‘\0’ ; “ a” :表示含有一个字母 a 的字符串,在内存中占 2 个字节(即字母 a 和空字符‘\0’ ) ; ‘ a’ :表示字符 a,在内存中占 1 个字节;
四、通过赋初值的方式给一维字符数组赋字符串常量

1.定义字符数组的同时,用字符串常量对字符数 组初始化; 例如: char a[ ]={“I am happy”}; 或 char a[ ]=“I am happy” ; 相当于:
char a[ ]={‘I’ , ‘ ’ , ‘a’ , ‘m’ , ‘ ’ , ‘ h’ , ‘a’ , ‘p ’ , ‘p’ , ‘y’ , ‘\0’};
注:数组 a 的长度是 11。

例如:char c[10]={“hello”}; h e l l o \0 \0 \0 \0 \0

2.注意事项
(1)字符数组本身并不要求他的最后一个字符为‘\0’ ,
也即下面的赋值是合法的:

char ar[10]={?I‘,‘ ?, ‘a‘,‘m‘,‘ ‘,‘h‘,‘a‘,‘p‘,‘p‘,‘y‘}
176

但在实际应用中, 由于系统对字符串常量处理时自动加一个 ‘\0’ 。 因此,为了使处理方法一致,便于测定字符串的实际长度,以及在程 序中作相应的处理,通常在对字符数组赋值时,人为地

加上一个‘\0’ ,即: char ar[10]={?I‘,‘ ?, ‘a‘,‘m‘,‘ ‘,‘h‘,‘a‘,‘p‘,‘p‘,‘y‘,‘\0‘}
(2)若在字符数组定义之后再初始化,不能整体赋值,此时, 只能给每个元素逐个赋值。

例如: char mark[10]; mark=‖Cprogram‖; /*不合法*/ 例如: char str1[10]=‖computer‖,srt2[10]; str2=str1; /*不合法*/ 五、字符数组的输入与输出(P151) 方法一:逐个字符的输入与输出 例 5.13 方法 2:将整个字符串一次输入或输出。 例如: char str[20]; cin>>str; cour<<str;
177

注意:P152. 说明: (1)在 C 中通过 printf 和 scanf 函数实现: char str[20]; scanf(―%s‖,str); printf(―%s‖,str);
注:在输入字符串时,当遇到空格或回车时,即认为字符串结束。

(2)在 C 中通过 gets 和 puts 函数实现: char str[20]; gets(str); puts(str);
注:在输入字符串时,用回车键确认表示字符串结束。

六、字符串处理函数(P152) 为了简化程序设计的复杂度, C 与 C++提供了 大量的字符串处理函数。这些函数的使用,要包括 头文件:string.h 或 cstring 1.字符串连接函数 strcat() 函数一般形式为: strcat(字符数组 1,字符串 2)
178

其功能: 将字符串 2 连接到字符数组 1 中的字符串之 后,并且将连接后的新串存放于字符数组 1 中。 例如: char str1[20]={―Good ‖},str2 [ ]={―morning‖}; strcat(str1,str2); cout<<str1;
说明: ①字符数组 1 是已定义的足够大的字符数组,连接时,去掉字符数组 1 中的结束标志‘\0’ , 再把字符串 2 连接到其后,新串最后保留一个‘\0’ 。 ②字符串 2 可以是字符数组名或字符串常量。

2.字符串的复制函数 strcpy() 函数的一般形式: strcpy(字符数组 1 ,字符串 2) 目标字符数组 源字符串 其功能是:将字符串 2 复制到字符数组 1 中去。 例如: char str1[10],str2 [ ]={“Hello”}; strcpy(str1,str2) ; 执行后,str1 的状态如下:
179

H

e

l

l

o ?\0‘

说明:
①“字符数组 1“必须定义的足够大,以便可以容纳被复制的字符串; ②“字符数组 1”必须写成数组名形式,而“字符串 2”可以是字符数组名,也可以是一个字 符串常量。

如上例也可写为:

strcpy(str1, “Hello” ) ;

③不能用赋值语句将一个字符串常量或字符数组直接给一个字符数组。

如下面是不合法的: str1={“Hello”}; str2=str1;
④可以用 strcpy 函数将字符串 2 中前面若干字符复制到字符数组 1 中;

例如: strcpy(str1,str2,3) ; 其功能是: 将 str2 中前 3 各字符复制到 str1 中, 然 后再加一个‘\0’ 3. 字符串比较函数 strcmp() 函数的一般形式: strcmp(字符串 1,字符串 2) 功能:比较两个字符串的大小。 其中:字符串 1、字符串 2 可以是字符串常量或已 赋值的字符数组。 比较规则:对两个字符串自左至右逐个字符相比(按 ASCII 码值大小比较) ,直到
出现不同的字符或遇到‘\0’为止。如全部字符相同,则认为相符;若出现不相同的字符,
180

则以第一个不相同的字符的比较结果为准。

函数返回值为: 0 两个字符串完全相同; 〉0 字符串 1〉字符串 2; 〈0 字符串 1〈字符串 2; 说明: 对字符串的比较,不能用以下形式: if (str1==str2) cout<<―yes‖; 正确: if (strcmp(str1,str2)==0) cout<<―yes‖; 4. 测试字符串长度函数 strlen() 函数的一般形式: strlen(字符数组) 功能是:求字符数组中存放的字符串长度。 例如: char str[10]={―Hello‖}; cout<<strlen(str); 其输出结果为:5
说明: 函数值为字符串中的实际长度,不包括‘\0’在内;

也可以直接测试字符串常量的长度。
181

如:

strlen( “Hello” )

七、字符串应用举例 例 5.14 有 3 个字符串,要求找出其中最大者。 #include <iostream> #include < cstring> using namespace std; void main() { char string[20],str1[20],str2[20],str3[20]; cout<<"please input string:"; gets(str1); gets(str2); gets(str3);
if (strcmp(str1,str2)>0) else strcpy(string,str2); strcpy(string,str3); if (strcmp(str3,string)>0) strcpy(string,str1);

cout<<"the max string is:"<<string<<endl; } 例 5. 15 输入一个由字母组成的字符串, 再分别以 大写字母和小写字母形式输出该字符串。 #include <iostream>
182

#include < cstring> using namespace std; void main() { char c[60]; gets(c); cout<<endl; k=0; while(c[k]!='\0') { if (c[k]>='a' &&c[k]<='z') putchar(c[k]-32); else putchar(c[k]); k++; } cout<<endl; k=0; while(c[k]!='\0')
183

int k;

cout<<"please input the string:";

{

if (c[k]>='A' &&c[k]<='Z') putchar(c[k]+32); else putchar(c[k]); k++;

}

}
例 5.16 不用 strcat 函数实现将两个字符串连接
//不用函数 strcat 实现其功能

#include <iostream> #include < cstring> using namespace std; void main() { char s1[80], s2[80]; int i=0, j=0; cout<<"Please input a string1:"; gets(s1); cout<<"Please input a string2:"; gets(s2);
184

while(s1[i]!='\0') i++; while(s2[j]!='\0') s1[i++]=s2[j++]; s1[i]='\0'; cout<<" the new string is :"<<s1; } 例 5.17 删除某一个字符串中某个特定字符。 问题分析:将要保留的字符逐个复制一遍。 #include <iostream> #include < cstring> using namespace std; void main()

{

char a[]="this is a string"; char c='i'; int i,j=0; for(i=0;a[i]!='\0';i++) if(a[i]!=c) a[j++]=a[i]; a[j]='\0';
185

//欲删除的字符

cout<<a<<endl; }
例 5.18 输入 10 个字符串,输出其中的最大者。 #include <iostream> #include < cstring> using namespace std; void main()

{

int i; char max[20],str[10][20]; gets(str[0]); strcpy(max,str[0]); for(i=1;i<10;i++) { gets(str[i]); if (strcmp(max,str[i])<0) strcpy(max,str[i]);
186

} puts(max); }
例5 . 19输入5个国家的名称, 按字母顺序排列输出。 #include <iostream> #include < cstring> using namespace std; void main() { char st[20],cs[5][20]; int i,j,p; cout<<"input country's name:"; for (i=0;i<5;i++) gets (cs[i]); for (i=0;i<5;i++) { p=i; strcpy(st,cs[i]); for (j=i+1;j<5;j++) if (strcmp(cs[j],st)<0) { p=j; strcpy(st,cs[j]); }
187

if (p!=i) { strcpy(st,cs[i]); strcpy(cs[i],cs[p]); strcpy(cs[p],st); } puts(cs[i]); } }

5.5 C++ 处 理 字 符 串 的 方 法 — 字 符 串 类 与 字 符 串 变 量
(P156)
在 C 中用字符数组的方式存储、处理字符串的方法存在着一定的缺陷,因此在 C++中引入了字符串类 型,可通过类型变量的定义来实现对字符串的方便处理。

c++允许其标准库中声明的一个字符串类定义一个字符串 变量。

一、字符串变量的定义和引用
1.定义字符串变量
188

定义字符串变量的一般格式: string 或: 例如: string str1; string str2=‖program‖; 注意: 引用 string 类的功能,必须加载头文件#include<string> 2.对字符串变量的赋值 对字符串变量的赋值的一般格式: 字符串变量=字符串常量或字符串变量 例如: string str1,str2; str1=‖program‖; str2=str1; 问题:字符串变量 str1、str2 的所占的存储空间为多少? 3.字符串变量的输入输出 cout<<字符串变量; cin>>字符串变量;
//定义 str1 为字符串变量 //定义 str2 字符串变量,同时对其初始化

字符串名; 字符串名=初始化值;

string

二、字符串变量的运算(P157)
(1)用赋值运算符实现字符串复制 字符串变量 1=字符串变量 2
189

例如: str1=str2 (2)用加法运算符实现字符串连接 例如: string str1=‖C++‖; string str2=‖program‖; string str3; str3=str1+str2; (3)用关系运算符实现字符串比较 string str1,str2; str1=‖zheng‖;str2=‖wang‖; cout<<(str1>str2)<<endl;
//等价于 strcpy(str1,str2)

三、字符串数组(P158)
string 字符串数组名[字符串数组长度] 例如: string name[4]={―zhang‖,‖wang‖,‖li‖,‖zhao‖};
//定义一个字符串数组 name,长度为 4(包含 4 个字符串) ,并初始化

问题: (1)name 数组的存储格式; (2)数组元素 name[1]中存放的内容; 要求阅读 p158 页中的说明(1),(2),(3),(4)

四、字符串运算举例(P159)
例 5.20 输入 3 个字符串,按字母大小顺序输出
190

#include<iostream> #include<string> using namespace std; int main() { string str1,str2,str3,temp; cout<<‖please input three strings:‖; cin>>str1>>str2>>str3; if(str2>str3) { temp=str2;str2=str3;str3=temp;}
//使串 2<=串 3

if(str1<=str2) cout<<str1<<‖,‖<<str2<<‖,‖<<str3<<endl; else if(str1<=str3) cout<<str2<<‖,‖<<str1<<‖,‖<<str3<<endl; else } cout<<str2<<‖,‖<<str3<‖,‖<<str1<<endl; return 0;

例 5.21(P159 例 5.12)一个班有 n 个学生,将每个学生的姓 名、学号在计算机中存储,而后按姓名查询其相关资料,若找 到此人,则将其姓名和学号输出,若没找到,则输出“查无此 人” 。

#include <iostream> #include <string> using namespace std; string name[50],num[50]; //定义 name 姓名(全局) ,num 学号(全局)
191

int n; // 定义学生个数(全局) int main() { void input_data(); // 数据输入函数声明 void search(string find_name); // 查询函数声明 string find_name; // 定义查询变量 cout<<"please input number of this class:"; cin>>n; // 输入学生个数 input_data(); //调用输入函数输入学生记录 cout<<"please input name you want find:"; cin>>find_name; // 输入欲查找的姓名 search(find_name); // 调用查询函数进行查找处理 return 0; } void input_data() { int i; for (i=0;i<n;i++) { cout<<"input name and number of student "<<i+1<<":"; cin>>name[i]>>num[i];} } void search(string find_name)
192

{

int i; bool flag=false; for(i=0;i<n;i++) if(name[i]==find_name) { cout<<name[i]<<" "<<num[i]<<endl;flag=true;break; if(flag==false) cout<<"can't find this name";

}

}

第六章 指
6.1 指针的基本概念(P164) 一、地址 1.内存单元的地址



内存单元的基本单位是字节,为了方便对内存的访问,每一个内存单元都有一个编号,这个编号就称 为内存单元的地址。

2.内存单元的内容
内存单元中存放的数据即是内存单元的内容。

例:int i=9,j=6,k=5;

193

说明: 每当在程序中定义了变量,C 编译系统就会根据变量的不同类型,在内存中为其分配相应字节数目的 存储空间。把变量在内存中所占存储单元的首地址,称为该变量的地址(Address) 。把变量在内存中所占 存储单元中存放的数据,称为该变量的内容。而在计算机内存中,对变量值的存取实质上是通过地址进行 的。

例 6.1 观察地址 #include <iostream> using namespace std; int main()

{

int x=55; cout<<"x="<<x<<endl; cout<<"x addres is :="<<&x<<endl; return 0;

}
3. “直接访问”与“间接访问”
? ? 按变量名存取变量值的方式称为“直接访问” 。 按变量地址的存放单元存取变量值的方式称为“间接访问” 。
194

例如:

(1) (直接访问)

(2) (间接访问)

二、指针与指针变量 1.指针 一个变量的地址称为该变量的“指针“。
说明:由于通过地址可以找到所需的变量单元,也即是说,地址“指向“该变量单元,因此,在 C++中,将地址形象化地称为”指针“。

如:2000 是变量 i 的指针。 2.指针变量 一种用来存放另一个变量地址值的特殊变量, .................... 其值是内存单元的地址。 ........... 如:i_pointer 所谓变量的指针就是变量的地址,而指针变量 是用来存放变量的地址。 i_pointer i
2000 9

2000
在指针变量与他所指向的变量之间存在着一种联系。
195

三、指针变量的定义 (P166)
指针变量也是变量,他具有变量的所有特性。如:在内存中占据一定的存储空间,遵循“先定义,后 使用”的原则等,但指针变量作为一种特殊的变量,他的内容只能是地址,而不能是数据。

1.指针变量定义的一般形式 类型标识符 *指针变量名 例如: int *pointer_1, *pointer_2; float *pointer_3; char *pointer_4; 2.说明
①“*“表示该变量为指针变量(在定义语句中) ; ②指针变量具有“基类型” ,基类型不同的指针变量不能混合使用; ③指针变量在内存中所占的存储空间是一样的(此点与数据类型说明不同) 。

例如:

int *pc; char *px;

pc、px 为两个指针变量,分别为指向整型变量和实型变量的指针,作为 pc、px 本身在内存中所占的 存储空间都是一样的。

四、指针变量的赋值与引用(P166~169) 1.指针运算符 ① & :取地址运算符; ② * :指针运算符(或称“间接访问“运算符) 说明:
①“&” 其功能是求出运算量的地址,他要求运算量必须是变量,而 不能是表达式、常量等。
196

例如: int x=5,*p;

p=&x;
表示把变量 x 的地址赋给指针变量 p (不改变 x 的值) 。 假设,变量 x 的值为 10,其在内存中的地址为 3000,则执行上述语句后,p 的值为:3000 注意: 在给指针变量赋地址值时,必须要确保指针变量的基类型与所赋地址值中存放的变量保持类型一致。

int *p; char ch; 则语句: p=&ch
例如:

//是错误的



②“*” 其功能与“&”相反,用于返回一个指针所指对象的内容。 他要求运算对象必须是已被正确初始化或已指向某一确定内存单元的指针 变量。

例如:int * p1,*p2,i=0,j=1; p1=&i; p2=&j; 则 j=*p1 等价于: j=i; i=*p1+3 等价于: i=i+3; 2.指针的引用 #include <iostream> using namespace std; int main() { int a=10,b; int *p;
197

// (即 j 的值变为 0)

例 6.2 通过指针变量的修改来改变被指示变量的值。

p=&a; b=a;
cout<<"a=‖<<a<<‖,b=‖<<b<<‖,*p="<<*p<<endl;

*p+=10;
cout<<"a=‖<<a<<‖,b=‖<<b<<‖,*p="<<*p<<endl;

b+=10;
cout<<"a=‖<<a<<‖,b=‖<<b<<‖,*p="<<*p<<endl;

a=a+10;
cout<<"a=‖<<a<<‖,b=‖<<b<<‖,*p="<<*p<<endl;

return 0; }
例 6.3 对比指针变量值的改变与指针变量指向地址内容的改变。

#include <iostream> using namespace std; int main() { int a=10,b=20,c=30,d=40;

int *p1=&a; int *p2=&b; int *p3=&c; int *p4=&d;
cout<<"a=‖<<a<<‖,b=‖<<b<<‖,*p1=‖<<*p1<<‖,*p2="<<*p2<<endl; cout<<"c=‖<<c<<‖,d=‖<<d<<‖,*p3=‖<<*p3<<‖,*p4="<<*p4<<endl;

p1=p2;
198

*p3=*p4;
cout<<"a=‖<<a<<‖,b=‖<<b<<‖,*p1=‖<<*p1<<‖,*p2="<<*p2<<endl; cout<<"c=‖<<c<<‖,d=‖<<d<<‖,*p3=‖<<*p3<<‖,*p4="<<*p4<<endl;

return 0; }
例 6.4 通过指针变量交换两个变量的值(cex6_41,cex6_42)
/* ctex7_41 */

#include <iostream> using namespace std; int main()

{ int a=10,b=20; int *p1=&a; int *p2=&b; int t;
cout<<"a=‖<<a<<‖,b=‖<<b<<‖,*p1=‖<<*p1<<‖,*p2="<<*p2<<endl;

{
}
/*

t=*p1; *p1=*p2 ; *p2=t; }

printf("\nNow a=%d,b=%d,*p1=%d,*p2=%d",a,b,*p1,*p2);

ctex7_42

*/

#include <iostream> using namespace std; int main()
199

{ int a=10,b=20; int *p1=&a; int *p2=&b; int *t;
cout<<"a=‖<<a<<‖,b=‖<<b<<‖,*p1=‖<<*p1<<‖,*p2="<<*p2<<endl;

{
}

t=p1; p1=p2; p2=t;

}

cout<<"a=‖<<a<<‖,b=‖<<b<<‖,*p1=‖<<*p1<<‖,*p2="<<*p2<<endl;

五、空指针

(P193)

1.空指针的含义 所谓“空指针”是指:指针变量不指向任何变量或数据。 一般而言,
“空指针”在以下二种情况下出现: ①定义了一个指针变量,既没有进行初始化,也没有对其进行赋值; ②用一个宏定义 NULL 为其指针变量赋值。

2.良好的建议:
当定义了一个指针变量,但暂时又不马上使用时,可为他赋一个 NULL 值(即空值) ,以明确表示该 指针变量目前不指向任何一个存储单元。

例如:p=NULL ;
注意:

(p 为指针变量)

①NULL 是系统在头文件中定义的预定义标识符; ②NULL 的拼写必须采用大写字母。
200

六、指针的运算(P193) 1.算术运算
当指针指向一串连续的存储单元时,可以对指针变量进行加、减一个整数的运算;对于指向同一连续 存储单元的两个指针变量可以进行相减运算;除此之外,不可以对指针变量做任何其他算术运算。

例如:
设在内存中开辟了如图所示的 5 个连续的、 存放整型数据的存储单元, 且已经定义了指针变量 p 和 q, 并使 p 指向值为 10 的存储单元。

执行: p=p+3;

执行:q=p-2;

说明:
201

对指针变量进行加、减一个整数时,数字 1 并不代表一个字节,而是指向一个存储单元的长度。至于 一个存储单元的长度是多少字节,则视指针变量的基类型而定。

如:p 是 int 型, p 是 float 型, p 是 double 型, 2.比较运算

则 1 个单元长度是 2 个字节;(vc++6.0 是 4 个字节) 则 1 个单元长度是 4 个字节; 则 1 个单元长度是 8 个字节;等等。

两个指针变量间进行比较,实质上就是两个地址间的比较。

如:p==q ;

表明两个指针变量指向同一个变量。

通常情况下, 只有当两个或多个指针变量指向同一连续存储空间时, 指针变量间的比较操作才有意义。

6.2 指针与函数
指针与函数有三种关系:①指针可以作为函数参数,②函数的返回值可以是指针,③指针可以指向函 数。

一、函数参数为指针变量(P170)
使用指针变量作为函数参数的主要目的之一是:

实现实参与形参按地址传递。

回顾第四章题:

例 4.4 交换两个变量的值。 问题分析:原本希望通过调用 swap()函数来交换变量 x 和 y 的值,但形参 a 和 b 的变化并没
有影响到实参 x 和 y。为什么?

#include <iostream>
202

using namespace std; void swap(int a,int b) { int tmp; cout<<"a=‖<<a<<‖, b="<<b<<endl;; tmp=a;a=b;b=tmp; cout<<"a=‖<<a<<‖, b="<<b<<endl;;

}
int main() { int x=20,y=-40; cout<<‖x=‖<<x<<‖,y=‖<<y<<endl; swap(x,y); cout<<‖x=‖<<x<<‖,y=‖<<y<<endl; return 0; } 例 6.5 利用函数实现两个变量值的交换。 #include <iostream> using namespace std;

void swap(int *a,int *b) { int tmp;
203

cout<<"a=‖<<*a<<‖, b="<<*b<<endl; tmp=*a;*a=*b;*b=tmp; cout<<"a=‖<<*a<<‖, b="<<*b<<endl; } int main() { int x=20,y=-40; cout<<"x=‖<<*x<<‖, y="<<*y<<endl; swap(&x,&y); cout<<"x=‖<<*x<<‖, y="<<*y<<endl; return 0; }
问题:若对例 6.5 修改为如下程序,分析其运行结果。 #include <iostream> using namespace std;

void swap(int *a,int *b) { int *tmp; cout<<"a=‖<<*a<<‖, b="<<*b<<endl; tmp=a;a=b;b=tmp; cout<<"a=‖<<*a<<‖, b="<<*b<<endl; }
204

void main() { int x=20,y=-40; cout<<"x=‖<<*x<<‖, y="<<*y<<endl; swap(&x,&y); cout<<"x=‖<<*x<<‖, y="<<*y<<endl; }

二、函数返回地址值(P188)
函数值的类型既可以简单数据类型,还可以是指针类型。

定义返回指针函数的一般形式: 类型名 *函数名(形参表) { 函数体 } 调用返回指针的函数的赋值语句一般形式: 指针变量=函数名;
表示把函数的地址赋给指针变量,即指针变量指向函数。

案例 6.6 #include <iostream>
205

using namespace std;

int *fun(int *a,int *b) { if(*a>*b) return a; return b; } void main() { int *p,i,j; cout<<"enter two number:"; cin>>i>>j; p=fun(&i,&j);
cout<<"i=‖<<i<<‖, j=‖<<j<<‖,*p=‖<<*p<<endl;

}
三、指向函数的指针变量(P186) 1.引入指向函数的指针变量的意义
C++语言规定:函数名代表该函数的首地址,因此可通过指向该函数的指针变量调用该函数

2.指向函数的指针变量的定义 类型名 (*指针变量名) (函数形参表) ; 例如: int (*p) (int,int) ;
表示 p 为指向返回值为 int 型函数的指针变量。

例 6.7 用指向函数的指针调用函数的方法 #include <iostream>
206

using namespace std; int max(int a,int b) { return( (a>b)?a:b); }

void main() { int (*p)(int,int); //定义指向函数的指针变量 int x,y,z; p=max; //p 指向函数 max cout<<―please input a&b:‖; cin>>a>>b; z=(*p)(x,y); //等价于:z=max(x,y); cout<<―max=‖<<z<<endl; }
6.3 指针与数组 一、一维数组和数组元素的地址关系(P175)
C++规定,数组名代表数组元素的首地址,也即:是一个指向该 数组第一个元素的首地址。

例如:int st[20]; 则:
st+1 表示数组元素 st[1]的地址, (即 st+1 的值就是&st[1]);
207

st+2 表示数组元素 st[2]的地址, (即 st+2 的值就是&st[2]);

。 。 。
st+i 表示数组元素 st[ i ]的地址, (即 st+i 的值就是&st[ i ]);

因此: * st 等价于 *(&st[i]) *(st+1) 等价于 st[1]; 。 。 。 *(st+i) 等价于 st[i]; 说明: ①st+i 相当于进行
其中 d 是一个数组元素所占的字节数。

也即是: st[0];

st+i*d 的运算,

②在引用一维数组第 i 个元素时有两种方法: st[i] 和 *(st+i) 例 6.8 分别用下标法和指针法访问数组 #include <iostream> using namespace std; void main() { int w [5]={10,20,30,40,50}; int i; for(i=0;i<5;i++) cout<<w[i]<<‖ ―; //下标法
208

cout<<endl; for(i=0;i<5;i++) cout<<*(w+i)<<‖ cout<<endl; }

―;

//指针法

二、通过指针变量或带下标的指针变量引用一维数组元素

1.通过指针变量引用一维数组元素
由于数组名代表数组元素的首地址,而计算机为数组分配一片连续的存储单元,因此

通过指针变量利用“间接访问运算符”可达到 引用数组元素的目的。 指向数组元素的指针变量定义的一般形式: 类型名 *标识符 例如: int x[10],*p; p=x;
即:将数组 x 的首地址赋给指针变量 p,即表示指针变量 p 指向数组 x

则:

p+1 等价于 。 。 。 。 。 。 p+i 等价于 类推: *p 等价于 *(p+1) 等价于 。 。 。 。 ,
209

x+1, x+i。 x[0], x[1],

*(p+i) *(p+i)

等价于

x[i]。

因此,当一个指针变量 p 指向数组 a 的首地址时,访问数组的第 i 个元素 a[i],又有一种的方式 :

例 6.9 可将上例改为通过指针变量引用一维数组元素

#include <iostream> using namespace std; void main() { int w [5]={10,20,30,40,50},*p=w; int i; for(i=0;i<5;i++) cout<<w[i]<<‖ ―; //下标法 cout<<endl; for(i=0;i<5;i++) cout<<*(w+i)<<‖ ―; //地址法 cout<<endl; for(i=0;i<5;i++) cout<<*(p+i)<<‖ ―; //指针变量法 cout<<endl; } 2. 通过带下标的指针变量引用一维数组元素
210

假设有以下定义语句

int i; p=s; 由于 s[i] 可以用表达式 *(s+1) 表示, 则:*(p+i)也可以用 p[i]表示, 即:通过带下标的指针变量可以引用一维数组元素。
C++规定,当一个指针变量指向一个数组时,这个指针变量在程序中就可以以数组名的身份出现,即 可以带下标。因此,若一个指针变量 p 指向一个数组 a 的首地址时,则访问数组的第 i 个元素 a[i],就可 以又有一种方式:

: *p, s[10],

p[i] 例 6.9 将上例改为通过带下标的指针变量引用一维 数组元素 #include <iostream> using namespace std; void main() { int w [5]={10,20,30,40,50},*p=w; int i; for(i=0;i<5;i++) cout<<w[i]<<‖ ―; //下标法 cout<<endl; for(i=0;i<5;i++) cout<<*(w+i)<<‖ ―; //地址法
211

cout<<endl; for(i=0;i<5;i++) cout<<*(p+i)<<‖ ―; //指针变量法 cout<<endl; for(i=0;i<5;i++) cout<<p[i]<<‖ ―; //带下标的指针变量法 cout<<endl; } 注意:在机器内部,对一维数组的访问,实质上就 是按 *(a+i)的方式访问 三、二维数组和数组元素的地址关系(P180) 1、二维数组和数组元素的地址(P180~183)
系统对二维数组的存放是按行顺序进行的。C++将二维数组的行列下标在定义中用两个括号分开,其 目的是:把二维数组当作一维数组。

例如: int a[3][4]; 其存储形式为:

可看成是:3 个具有 4 个元素的一维数组。即:

a[0]-----a[0][0],a[0][1],a[0][2],a[0][3];
212

a[1]-----a[1][0],a[1][1],a[1][2],a[1][3]; a[2]-----a[2][0],a[2][1],a[2][2],a[2][3]; 数组名 a 表示二维数组的地址,即第 0 行地址; a+1 表示二维数组第 1 行地址; a+2 表示二维数组第 2 行地址; 根据 C++ 规定:数组名代表数组的地址, 因此: a[0] 代表第 0 行的首地址: a[0]+1 是第 0 行第 1 列元素的地址, a[0]+j 是第 0 行第 j 列元素的地址, 即&a[0][j]。 a[1] 代表第 1 行的首地址: a[1]+1 是第 1 行第 1 列元素的地址, a[1]+j 是第 1 行第 j 列元素的地址, 即&a[1][j]。 2、通过地址来引用二维数组元素 C++规定,无论 a 是多少维数组,根据书写形式: a[0] 等价于 *(a+0) ; a[1] 等价于 *(a+1) ; 。 。 。 。 。 a[i] 等价于 *(a+i) ; 故:要引用 a[i][j] ,用地址法表示为: *(a[i]+j) ,也即是 *(*(a+i)+j) 例 6.10 分析如下程序运行结果 #include <iostream>
213

#include <iomanip> using namespace std; void main() { int i,j;
int a[3][4]={{1,2,3,4},{10,20,30,40},{100,200,300,400}};

for(i=0;i<3;i++) cout<<a+i<<‖ ‖; cout<<endl; for(i=0;i<3;i++) cout<<a[i]<<‖ ―; cout<<endl; for(i=0;i<3;i++) cout<<*(a+i)<<‖ ―; cout<<endl<<endl;

//每行的首地址

//每行的首地址

//每行的首地址

i=1; for(j=0;j<4;j++) cout<<a[i]+j<<‖ ―; //第 1 行各元素的地址 cout<<endl; i=2; for(j=0;j<4;j++) cout<<*(a+i)+j<<‖ ―; //第 2 行各元素的地址 cout<<endl;
214

for(i=0;i<3;i++) { for(j=0;j<4;j++) cout<<setw(7)<<a[i][j]; cout<<endl; } for(i=0;i<3;i++) { for(j=0;j<4;j++) cout<<setw(7)<<*(*(a+i)+j); cout<<endl; } }

//输出所有元素的值

215

三、通过建立一个行指针来引用二维数组(P182) (*指向由 m 个元素组成的一维数组的指针变量)
从逻辑上看二维数组是由相同类型的一维数组作为元素而构成的一维数 组。由于内存是一维空间,因此二维数组在内存中的表示是将二维空间上的数 据依照某种顺序映射到内存,在 C++语言中,是按从上到下、从左到右的次序 (行序)来实现这种映射的。

所谓行指针变量就是用来存放“行”地址的变 量,即行指针变量是指向一维数组的指针变量,其 定义形式如下: 类型名 (*指针变量名)[数组长度] 比较如下几个定义: ①int x ; 定义整型变量 x; ②int *px; 定义指向整型的指针变量 px; ③int b[5]; 定义含有 5 个元素的整型数组 b; ④int(*p)[5];定义指向含有 5 个元素的整型数 组的指针变量 p。 例如:
int a[3][5]={{1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15}};

int (*p)[5]; p=a;
这里 p 是一个指向含有 5 个整型元素的一维数组的指针变量;a 是一 个 3 行 5 列的二维数组,即每一行相当于一个含有 5 个元素的一维数组。
216

由于二维数组名是一个行指针类型的地址常量,则语句 “ p=a;”的 作用就是将数组首地址赋给 p,让行指针变量指向二维数组的 a 的首行, 即一维数组 a[0]。

P ,a P+1 P+2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

通过行指针可以表示二维数组的首地址、行地 址、元素地址、元素等 当 p 指向 a 数组的开头时, 可以通过以下形式来引 用 a[i][j] *(p[i]+[j]) *(*(p+i)+j) (*(p+i)+)[j] p[i][j] 与 *(a[I]+[j]) 相对应 与 *(*(a+i)+j) 相对应 与 (*(a+i)+)[j] 相对应 与 a[i][j] 相对应

例 6. 11 将例 6.10 改为用指向一维数组的行指针来 引用二维数组元素 #include <iostream> #include <iomanip>
217

using namespace std; void main() { int i,j;
int a[3][4]={{1,2,3,4},{10,20,30,40},{100,200,300,400}};

int (*p)[4]; //定义行指针 for(p=a;p<a+3;p++) { for(j=0;j<4;j++) cout<<setw(7)<<*(*p+j );//通过指针数组引用二维数组元素实现输出 cout<<endl; } } 6.4 指针、数组、函数的结合(P178) 一、数组名作实参
由于数组名代表数组在内存中的起始地址,因此,当数组名作函 数参数时,主调函数和被调函数之间的参数传递是按“地址方式

传递” 。数组名做函数的参数,要求形参和实参必 须是数组名或与数组元素同类型的指针(地址) 。 1.形参为数组名 这种情况是将整个数组进行传递,即将实参数 组的首地址传给对应的形参数组。也可以说,当发 生函数调用时,形参数组实际上是与实参数组共用 一段内存空间。因此,形参数组的变化就是实参数
218

组的变化。 x[i] a[i] (形参数组) (实参数组)

例 6.12 任意输入 10 个整数,按从小到大的顺序重新排序。
问题分析:
由于排序的工作经常要做,因此可将排序设计成一函数并且采用选择交换法实现。

#include <iostream> using namespace std; void sort(int x[ ],int n) //排序函数 从大到小 { int i,j,tmp,p,max; for(i=0;i<n-1;i++) { max=x[i]; p=i; for(j=i+1;j<n;j++) if(x[j]>max) { max=x[j]; p=j; } if (p!=i) { tmp=x[i];x[i]=x[p];x[p]=tmp; } } } void main()
219

{

int j; int a[10]={2,4,6,0,65,34,8,90,22,12}; int b[20]={2,4,6,0,65,34,8,90,22,12,23,6….}; printf("\n"); sort(a,10); sort(b,20); for(j=0;j<10;j++) cout<<a[j]<<‖ ―; cout<<endl; }

例 6.13 分析如下程序

#include <iostream> using namespace std; void swap(int *x,int *y) //交换 { int t; t=*x; *x=*y; *y=t; } void sort( int x[ ], int length ) //排序函数 从大到小
220

{

int i , j; for(i=0;i<length-1;i++) for(j=i+1;j<length;j++) { if (x[i]<x[j]) swap(&x[i],&x[j]);

}

} void inputa(int x[], int n) { int i; for(i=0;i<10;i++) //输入数据 { cout<<"please input x[ ―<<i<<‖ ]"; cin>>x[i]; } } void printa(int x[],int n) { int i; for(i=0;i<10;i++) cout<<x[i]<<‖ ―; cout<<endl; } void main() { int x[10]; inputa(x,10);
221

printa(x,10); sort(x,10); cout<<"the sorted array is :"<<endl; printa(x,10); } 2.形参为指针变量 这种情况是将实参数组的首地址传给对应的指针变 量。也可以说,当发生函数调用时,形参指针变量实际上是 与实参数组共用一段内存空间。因此,形参指针变量的变
化就是实参数组的变化。

x[i]

(形参指针变量)

a[i] (实参数组) 例 6.14 函数形参为指针变量,实参为数组名。 #include <iostream> #include <iomanip> using namespace std; void printa(int x[], int length) { int i; cout<<endl; for(i=0;i<length;i++) cout<<setw(5)<<x[i]; cout<<endl;
222

} void main() { int x[10],i; for(i=0;i<10;i++) x[i]=i; printa(x,10); } 二、指针变量作实参(该指针变量指向一个数组的 首地址) ,函数形参为数组 例 6.15 函数形参为数组,实参为指针变量(该指 针变量指向一个数组的首地址) #include <iostream> #include <iomanip> using namespace std; void printa(int x[ ],int length) { int i; cout<<endl;; for(i=0;i<length;i++) cout<<setw(5)<<x[i]; cout<<endl; } void inputa(int x[ ],int length)
223

{

int i; cout<<endl;; for(i=0;i<length;i++) cin>>x[i]; }

void main() { int x[10],i,*p; p=x; inputa(p,10); printa( p, 10); } 6.5 字符串与指针(P184~186) (自学)
C++允许用一个字符指针指向一个字符串。

例如: char *p=‖ Look! a bird.‖
其意义为:将字符串‖ Look! a bird.‖放在指针变量 p 所指向的存 储单元中,然后再将字符串的首地址赋给 p。

注意:用字符数组作为字符串和用指针指向的一个字符串之间的区别

例如:
224

char mark[]=‖A program‖; char *pmark=‖A program‖;
说明: 二者存储的内容相同,可以以相同的方式引用其存储的字符串内 容,但其占用的存储空间不同,mark 数组的存储空间及长度在定义 之后就已确定;而*pmark 可以通过改变其存储的的地址从而指向另 外的字符串,并且不受其原来指向的字符串的长度限制。

6.6 指针数组和指向指针的指针(P188~192) 一、指针数组的概念 指针数组是指元素为指针类型数据的数组,即 数组的每个元素是一个指针变量。 指针数组定义的一般形式为: 类型名 *数组名[数组长度]; 例如: int *p[3];
表示 p 是一个含有 3 个元素的数组,每个元素是一个指向整型的指针 变量。

指针数组通常和二维数组或字符串相联系,指针数组的元素可以 用来指向二维数组的行或用来指向字符串等。

例 6.16 将例 6.10 改为用指针数组来引用二维数组元素

#include <iostream>
225

#include <iomanip> using namespace std; void main() { int i,j;
int a[3][4]={{1,2,3,4},{10,20,30,40},{100,200,300,400}};

int *p[3]; //定义指针数组 p for(i=0;i<3;i++) p[i ]=a[i]; //建立指针数组与二维数组之间的关系 for(i=0;i<3;i++) { for(j=0;j<4;j++) cout<<setw(5)<<*(p[i]+j ); //通过指针数组引用二维数组元素实现输出 cout<<endl; } }
注意:

*(p[i]+j );还可写成:*(*(p+i)+j );
注意: 要区分指针数组和指向一维数组的行指针的定义方式是 不同的。例如:int *p[3];作为运算符, “[ ]”比“*”的优先 级高,所以在定义 int *p[3];中 p 先与[3]结合,表示 p 是一 个含有 3 个元素的数组;然后再与“*”结合,表示数组元素 是指针类型的,每个元素指向一个整型变量。
226

而在定义“ int (*)p[3]; ”中, “ (

) ”用来改变优先

级,首先是“ (*p) ” ,表示 p 是一个指针变量,然后再与“[3]” 结合,表示(*p)是一个整型一维数组,而 p 就是一个指向含 有 3 个元素的一维整型数组的指针(即行指针) 。

二、指向指针的指针(P190)
指向指针的指针是指指向指针数据的指针。

例:int a=10,*p; p=&a; cout<<a<<‖ ―<<*p<<endl; int **q; q=&p; cout<<a<<‖ ―<<*p<<‖ ―<<*(*q)<<endl;
例 6.16 指向字符型数据的指针变量(P191) #include <iostream> using namespace std; int main() { char **p; char
*name[]={"BASIC","FORTRAN","C++","PASCAL","COBOL"};

char *q;
227

p=name+2; cout<<*p<<endl; cout<<**p<<endl; return 0; }

6.7 引用(P194~199) 一、引用的概念
引用是个别名。当建立引用时,程序用另一个变量或对象(目标)的 名字初始化它。从那时起,引用作为目标的别名而使用,对引用的改动实 际就是对目标的改动。

引用通常用在以下几个方面: ①独立引用; ②参数传递; ③传回引用(*) 声明一个引用的格式如下: 数据类型 &引用名=已定义的变量名; 例如 :int a; int &b=a; //声明 b 是一个整型变量的 引用变量,并且被初始化为 a 二、引用的简单使用
228

例 6.17 独立引用的例子 #include<iostream> using namespace std; int main() { int i; int &j=i; // j 是 i 的别名; i=30; cout<<"i="<<i<<" j="<<j<<"\n"; j=80; // 即改变 i 的值; cout<<"i="<<i<<" j="<<j<<"\n"; cout<<"address of i"<<&i<<endl; cout<<"address of j"<<&j<<endl; return 0; } 三、关于引用的简单说明 (1)引用不是一种独立的数据类型,它必须与某 一种数据类型相联系,即同时对其初始化; 例如: int a; int &b=a; //ok int &b; //error,必须同时初始化 float a; int &b=a; //error,类型不一致 (2)引用不是独立的变量,编译系统不为其单独分配
229

存储单元。 (3)引用运算符只在声明时使用,任何其他“&‖ 的使用都是地址运算符。 例如: int one; int &r=one; //&是引用运算符 int *p=&one //&是地址运算符 (4)对引用的初始化,可以用一个变量名,也可 以用另一个引用。 例如: int a=10; int &b=a; int &c=b; cout<<a<<b<<c<<endl; (5)引用不可重新赋值。不可使其作为另一变量 的别名。 例如: int i,k; int &j=i; int &j=k; 四、将引用作为函数参数
引用作为函数参数的目的:在于扩充函数传递数据的功能。

(1)将变量名作为实参。 此时,传给形参的是一个变量的值。 例:6.18 实现两个变量的值互换的程序。
230

#include<iostream> using namespace std; void swap(int a,int b) { int temp; temp=a; a=b; b=temp; } int main() { int i=3,j=5; swap(i,j); cout<<‖i=‖<<i<<‖,‖<<‖j=‖<<j<<endl; //i 和 j 的值未互换 return 0; } (2)传递变量的指针 此时,传给形参的是一个变量的地址。 例:6.19 利用指针变量作形参,实现两个变量的值互换的程序。 #include<iostream> using namespace std; void swap(int *a,int *b) { int temp; temp=*a; *a=*b; *b=temp; } int main() { int i=3,j=5;
231

cout<<‖i=‖<<i<<‖,‖<<‖j=‖<<j<<endl; swap(&i,&j); cout<<‖i=‖<<i<<‖,‖<<‖j=‖<<j<<endl; //i 和 j 的值互换 return 0; } (3)传递变量的别名 此时,传给形参的是一个变量的别名。 例:6.20 利用“引用形参” ,实现两个变量的值互换的程序。 #include<iostream> using namespace std; void swap(int &a,int &b) { int temp; temp=a; a=b; b=temp; } int main() { int i=3,j=5; cout<<‖i=‖<<i<<‖,‖<<‖j=‖<<j<<endl; swap(i,j); cout<<‖i=‖<<i<<‖,‖<<‖j=‖<<j<<endl; //i 和 j 的值互换 return 0; }
说明: 当将一个引用作为参数传递时,编译器实际上传递了调用者中相应变量的地址。在函数调用语句中, 无须使用地址运算符&。在函数中使用参数时,也无须使用指针。当将某个引用作为参数传递时,对该参 数的所有修改实际上都是对调用者中的相应变量进行。
232

引用与指针非常相似,但有本质区别:指针变量的内容是一个地址,而引用为变量的别名。

注:仔细阅读 P21~22

五、对引用的进一步说明 (1)不允许对 void 类型进行引用 例如: void &r=10; //error (2)不能建立引用数组 例如: int a[10]; int &ra[10]=a; //error (3)当使用引用运算符 &取一个引用的地址时, 其值为所引用的变量的地址。 例如: int num=50; int &ref=num; int *p=&ref; 则:p 中保存的是变量 num 的地址。 (4)可以建立指针变量的引用 例如: int i=5; int *p=&i; int *pt=p; //pt 是一个指向整型变量的指针变量的引用,初始化为 p (5)可以用 const 对引用加以限定,不允许改变该 引用的值 int i=5; const int &a=i;
233

a=3; int i=3;

//error, 企图改变引用 a 的值 //ok;

六、用引用返回值(*补充)
函数返回引用是调用函数后返回值为为返回变量的一个引用。

其目的是:为了将该函数用在赋值运算符的左边。 案例 1: #include<iostream> using namespace std; int a[]={1,3,5,7,8}; int &index(int); int main() { cout<<index(2)<<endl; index(2)=25; cout<<index(2)<<endl; return 0; } int &index(int i) { return a[i]; } 案例 2: #include<iostream> using namespace std;
234

int a[10]; int &array(int i); int main() { int i,number; a[0]=0; a[1]=1; cin>>number; for(i=2;i<number;i++) { array(i)=array(i-2)+array(i-1);
cout<<"array("<<i<<")="<<array(i)<<endl;

} return 0; } int &array(int i) { return a[i]; }

235

第七章 结构体类型(P201)
一种用于存储不同类型数据的数据结构。 一、结构体类型的定义(P202) 结构体定义的一般形式为: struct { 结构体名 成员名 1; 成员名 2; 成员名 n; 数据类型 。 。 。 。 。 。 数据类型 }; 例如:描述一个职工的结构体数据类型。 struct person { int int float }; 说明:
236

数据类型

number; age; wage;

char name[80];

①结构体的定义指明该结构体由几个成员项组成,以及每个成员项具有什 么数据类型; ②struct 是关键字,标志结构体类型。每个成员项由其数据类型组成,每 个成员项后面用分号“; ”作为结束符,整个结构体的定义也用分号作为结 束符。

例如:描述学生信息的结构体数据类型。 strucct { int student stunum;

char name[20]; char sex; int float }; 注意: 结构体的定义明确地描述了该结构的组织形式。 在程序执 行时,结构体的定义并不引起操作系统为该结构分配内存空 间。结构体的定义仅仅是定义了一种特定的构造数据类型,他 指定了这种结构使用内存的模式。 二、结构体类型变量的定义 某个结构体一经定义之后, 就可以指明使用该结构体的具 体变量、数组和指针变量。 结构体变量说明的一般形式为: old; score;

char addr[80];

struct

结构体名

结构体变量名;
237

例如:

struct

student

Li;

(指出了结构体变量 Li 使用 student 结构,也即是说,结构体变量 Li 是 由前述的 student 的六个成员项组成,每个成员项的类型和名字都与 student 结构体定义中给出的相同。 )

说明: ①结构体变量的说明将引起操作系统按照结构体定义时制订 的内存模式为其分配一定的内存空间。 例如:Li 结构体变量在内存中将占用如下所示的内存空间。
struct student stunum 2 字节

name[20] 字节 sex old

。 。 。 。 。 。 。

20 字节 1 字节 2 字节

score

4 字节

Addr[80]

。 。 。 。 。 。

80 字节

②当结构体变量使用相同的结构体时,可以一起说明: 例如: struct student Li,Wang,Zhang;
238

③结构体变量的说明必须在结构体定义之后; ④结构体的定义和其变量的说明也可以同时进行; 例如: strucct { int student stunum;

char name[20]; char sex; int float old; score;

char addr[80]; }Li,Wang,Zhang; ⑤一个结构体变量占用内存的实际大小, 可以利用 sizeof 运算 求出。 其一般格式为: sizeof(运算量)
其中:运算量可以是基本变量、数组或结果体变量,也可以是数据类型的名称。

三、结构体变量的初始化 结构体变量说明的同时, 可以对其赋初值, 即进行初始化。 一般形式为: struct 结构体名 结构体变量={初始化数据}
239

说明: 大括号包围的初始化数据的个数、类型及顺序应与结构体成员项一一对应;

例如: (1)定义、说明、初始化同时进行。 strucct { int student stunum;

char name[20]; char sex; int float old; score; jiefang road‖};

char addr[80]; }Li={0312, “Li ping” , ‘ m’ , 19, 85, “75# (2)先定义,再进行说明和初始化。 struct { date int month; int day; int year; }; struct date today={10,15,2004};

四、结构体的嵌套
如果一个结构体的成员项仍然是结构体, 则称为结构体的 嵌套。 结构体的嵌套常用于处理一些关系较为复杂的数据。
240

例如:具有如下结构形式的通讯录数据。 姓 名 工作单位 邮政 编码 地址 电话 家庭住址 邮政 编码 地址 电话

观察上述数据结构, 可以看出工作单位和家庭住址都包含 有:邮政编码、地址和电话三项,此时,可以使用结构体的嵌 套形式处理,比较简单。 struct { int char char }; struct { char name[20]; struct struct }; 说明: 在结构体 per 中,其成员项 workaddr、homeaddr 的类型 是另一个结构体 address。这时称 per 是外层结构体,address 是内层结构体
241

address post; addr[80]; tele[15]; per

address workaddr; address homeaddr;

name

workaddr post addr tele

homeaddr post addr tele

注意:如果程序中出现结构体的嵌套,则只能处理最内层的成 员项。内层成员项的一般表示形式如下: 结构体变量名 . 外层成员项 . 内层成员项 例如: struct per Wang; 则: Wang . name Wang . workaddr . tele // 表示 Wang 的姓名 //表示 Wang 的工作单位的电话

Wang . homeaddr . post //表示 Wang 的家庭邮政编码 说明: 对内层成员项可以进行各种运算和操作, 就象对待同类型 的普通变量一样。

五、结构体变量的使用(P205)
1.在相同结构体类型变量之间可以进行赋值; 例如: struct Date { int month;
242

int day; int year; }; struct Student { int num; char name[20]; char sex; Date birthday; float score; }student1; struct 则: student1= student2;
//C 是不允许的

student2={10002,"Wang Li",'f',5,23,1982,89.5};

2.可以引用一个结构体变量中的一个成员; 表示结构体的成员项的一般形式为: 结构体变量名 . 成员名 例如:Li . stum Li . name Li . sex 。 。 说明: “. “是成员运算符,他在所有运算符中优先级最高,他 的结合规律是从左向右。
243

对于结构体成员项可以象普通变量一样进行各种运算。 例如: sum=Li . score+Wang . score; Li . old= Wang . old; 3.对于具有嵌套结构的结构体类型,则要通过多个成员运算, 逐级找到最低一级成员; 例如: student.birthday.month

4.不能对结构体变量进行整体的输入和输出,只能对各个成 员分别进行输入和输出; 5.可以引用结构体变量的地址,也可引用结构体变量成员的 地址; 例:7。1 (P206) #include <iostream> using namespace std; struct Date { int month; int day; int year; }; struct Student
244

{ int num; char name[20]; char sex; Date birthday; float score; }student1,student2={10002,"Wang Li",'f',5,23,1982,89.5}; int main() { student1=student2; cout<<student1.num<<endl; cout<<student1.name<<endl; cout<<student1.sex<<endl;
cout<<student1.birthday.month<<'/'<<student1.birthday.day<<'/';

cout<<student1.birthday.year<<endl; cout<<student1.score<<endl; return 0; }

六、结构体数组(P207)
在 C++中, 具有相同数据类型的数据可以组成数组, 同样, 具有相同结构的结构体数据也可以组成数组,称为结构体数 组。结构体数组的每一个元素都是结构体变量。
245

其说明形式如下: struct 结构体名 结构体数组名[元素个数] 例如: struct { int Student num;

char name[20]; char sex; int float }; struct Student s[10]; 说明了结构体数组 s[ ],有 10 个元素 s[0]、s[1]、 。 。 。s[9], 每个元素都是具有 student 结构的结构体变量。
S[0] S[1] S[9] stunum name 1001 li ping 1002 wang ling 。 。 。 。 1010 zhang wei sex m f m old score 19 85 18 95 20 78 addr 75# jiefang road 60# nanjing road 73# hongqi road

age; score;

char addr[80];

说明: 结构体数组在说明的同时也可以进行初始化,他的一般形 式为: struct 结构体名 例如:
246

结构体数组名[元素个数] ={初始数据};

struct employee { char name[20]; char sex; int }; struct employee worker[3]= {{―james‖,‘m‘,4500},{―mary‖,‘f ‘,5000},{―alice‖,‘m‘,3000}}; 此外,与数组的初始化一样,有时方括号内的元素的个数 可以省略,使用如下形式: struct employee worker[ ]= {{―james‖,‘m‘,4500},{―mary‖,‘f ‘,5000},{―alice‖,‘m‘,3000}}; 系统编译时, 会根据给出的结构体常量的个数来确定数组 元素的个数。 salary;

案例 12。 3 有一组学生的数据记录, 每个记录包含 num、 name 和 score[3],编写程序找出总分最高的学生记录。 #include<stdio.h> void main() { int i,j,k,sum,highest;
247

struct stu { int int num; score[3]; hua"},{102,"wang wei"},{103,"zhang char name[20]; }s[]={{101,"li highest=0; for(i=0;i<5;i++) { sum=0; printf("please input %s three score:",s[i].name); for(j=0;j<3;j++) { printf("\n please input %d subject score:",j+1); scanf("%d",&s[i].score[j]); sum=sum+s[i].score[j]; } if (sum>highest) { } printf("\n"); } printf("the highest student is :\n");
248

jun"},{104,"zhao fei"},{105,"liu qiang"}};

highest=sum; k=i;

printf("number is :%d\n",s[k].num);

printf("name

is :%s\n",s[k].name);

printf("score and total is :%d,%d,%d,%d\n", s[k].score[0],s[k].score[1],s[k].score[2],highest ) ; }

七、结构变量地址与结构指针
由于指针可以存放任何类型数据的地址, 因此也可以存放 一个结构体变量的地址。 例如: struct date { unsigned int year; unsigned int month; unsigned int day; } d,*p; p=&d;
p d d.year d.month d.day

结构指针运算符:-> 用于通过指针间接地访问被指向的结构变量的成员。 其应用形式如下: 结构指针->成员变量; 例如:
249

p->year; p->month; p->day; 案例:12。4 #include<stdio.h> struct student { }*p; void main() { struct student stu; p=&stu; int No; char *name;

等价于 d.year; 等价于 d.month; 等价于 d.day;

说明:运算符: “->”具有最高优先级。

printf("\n please input name:"); scanf("%s",p->name); scanf("%d",&p->No); } //等价 stu.name //等价 &stu.No printf("\n please input student number:"); printf("\n student %d ,%s",p->No,p->name);

八、结构指针的运算(*)
注意:当结构指针指向结构体数组时,对结构指针的运算 才有意义。 案例:12。5 有 N 个学生信息(包括学号,姓名,总分) ,要
250

求按总分从大到小排序后输出。 #include<stdio.h> #define N 4 #include<string.h> struct student { int xh; char name[8]; int total; }; void zin(struct student *p,int n) { int i,j; for(j=0;j<n;j++,p++) { printf("please input %d infor(xh name total :\n",j+1); scanf("%d%s%d",&p->xh,p->name,&p->total); } } //定义数据输入函数 //定义结构体类型

void zsort(struct student *p,int n) { int i,j,k; struct student tmp; for(i=0;i<n-1;i++) { k=i;
251

//定义排序函数

for(j=i+1;j<n;j++) if((p+j)->total>(p+k)->total) if (k!=i) { tmp.xh=(p+i)->xh; (p+i)->xh=(p+k)->xh; (p+k)->xh=tmp.xh; strcpy(tmp.name,(p+i)->name); strcpy((p+i)->name,(p+k)->name); strcpy((p+k)->name,tmp.name); tmp.total=(p+i)->total; (p+i)->total=(p+k)->total; (p+k)->total=tmp.total; } } } void zout(struct student *p,int n) { int j; printf("the sorted is :\n"); for(j=0;j<n;j++,p++) printf("%d } void main()
252

k=j;

//定义数据输出函数

%s

%d

\n",p->xh,p->name,p->total);

{

struct student stu[N]; zin(stu,N); zsort(stu,N); zout(stu,N);

}

小结: 引入结构体数据类型的目的: 将不同的数据类型包装在一 个类型之中,以方便将其作为一个整体同时进行处理。然而由 于实际应用中,面对的问题多种多样,包含的内容各不相同, 因此 C 让用户根据需要自行设计结构体类型的组成。并且规 定,在使用一个结构体类型之前,先进行有关该结构体类型的 声明。因此,可以说,结构体是一种较为复杂但又非常灵活的 构造类型。

九、函数之间结构体变量的数据传递(P168)
1. 向函数传递结构体变量的成员 由于结构体变量中的每个成员可以是简单变量、数组或指 针变量等,因此,作为成员变量,他可以象简单变量、数组或 指针变量一样,参与所属类型所允许的任何操作。
253

2.向函数传递结构体变量 在 C 的新标准中允许将结构体变量(实参)作为一个整体 传送给相应的形参,此时传递的是实参结构体变量的值,即按 数据传递。将实参中各成员的值赋给对应的形参成员。 3.传递结构体的地址 函数的实参为结构体变量的地址,对应的形参是一个基类 型相同的结构体类型的指针,即按地址传递。 例 12.6 通过函数给结构体成员赋值 #include<stdio.h> #include<conio.h> typedef struct { char s[10]; int t; }ST; void getdata(ST *p) { } void main() { ST a; getdata(&a); printf("%s,%d\n",a.s,a.t); getch();
254

scanf("%s%d",p->s,&p->t);

} 例 12.7 函数的返回值是结构体类型 #include<stdio.h> typedef struct { int a; char b; int t; }ST; ST fun(ST x) { } void main() { ST y; y.a=0;y.b='A'; printf("y.a=%d y=fun(y); printf("y.a=%d y.b=%c\n",y.a,y.b); } 例 12.8 读入五位用户的姓名和电话号码,按姓名的字典顺序 排列后,输出用户的姓名和电话号码#include<stdio.h> #include<string.h> #define N 5 typedef struct
255

x.a=99;x.b='S'; return x;

y.b=%c\n",y.a,y.b);

{

char name[20]; char num[10];

}USER; void getdata(USER *sp) { int i; printf("enter name & phone number :\n"); for(i=0;i<N;i++) { } void getsort(USER *sp) { int i,j,k; USER temp; for(i=0;i<N-1;i++) { k=i; for(j=i+1;j<N;j++) if(strcmp(sp[k].name,sp[j].name)>0) k=j; temp=sp[k];sp[k]=sp[i];sp[i]=temp; } } void outdata(USER *sp) { int i; printf("after sorted:\n"); for(i=0;i<N;i++)
256

gets(sp[i].name);

gets(sp[i].num);}

printf("%s, %s\n",sp[i].name,sp[i].num); } void main() { USER sp[N]; getdata(sp); getsort(sp); outdata(sp); }

12.3 共用体(P172)
一、共用体类型的定义 union 共用体名 { 数据类型 数据类型 成员名 1; 成员名 2;
257

。 。 。 。 。 数据类型 }; 例如: union ufield { int i; char c; float f; }; 说明: 三个成员项在内存中使用共同的存储空间, 他们在内存中 存放时使用的内存起始地址是相同的,也即是说,三个成员项 的存储空间是相互覆盖的。 由于共用体中各个成员项的数据类 型长度不同, 所以共用体在存储时是按其成员项中数据类型长 度大的成员项占用内存空间。
整型变量 i
字符变量 c

成员名 n;

实型变量 f

二、共用体变量的声明
一般形式为: union 共用体类型 共用体变量名; 例如: union ufield udata1,udata2;
258

也可将类型定义与变量说明同时进行。 例如: union ufield { int i; char c; float f; }data1,data2; 注意: 共用体与结构体 在定义、说明和使用上非常相似,但二 者在内存的分配上有着本质的区别。

三、共用体变量的使用
由于共用体的各个成员项使用共同的内存区域, 所以共用 体的内存空间在某个时刻只能保存某个成员项的数据, 也即是 说,在程序中参加运算的只能是共用体的某个成员项。 共用体引用的一般形式为: 共用体变量名. 成员名 例如: scanf( “%d” ,&data1.i) scanf( “%d” ,&data1) 例如:
259

正确 错误

此外,共用体与结构体可以互相套用。

union date { }; struct student { int num; char name[20]; char sex; float jump; float run; union date km; }; 案例 12。9 现要统计若干职员的信息,以便加薪时使用。职 员分为一般职员和高级管理人员。 对于一般职员要统计的信息 包括: 姓名 (name) 、 性别 (sex) 、 年龄 (age) 、 职位 (position) 、 工龄(workyears) ;高级管理人员需要统计的信息包括:姓名 (name) 、性别(sex) 、年龄(age) 、职位(position) 、工龄 (workyears) 、级别(grade) 。 问题分析: 这两种人员根据职位(position)项( “gen”表示普通职 员, “sin” 表示高级职员) 的不同, 分别需统计工龄和级别 (可 用共用体解决) 。把所有职员的信息放入一个结构体数组中, 数组中的每一个元素(结构体变量)中又包含了一个共用体。
260

float int

shot; lie;

#include<string.h> void main() { union dd { }; struct { char name[20]; char sex; int age; char position[4]; union dd p; } empl[3]; int i; for(i=0;i<1;i++) { printf("\nplease input %d information:(name sex age position \n",i+1); scanf("%s %c %d %s", empl[i].name,&empl[i].sex,&empl[i].age,empl[i].position); if (strcmp(empl[i].position,"gen")==0) { printf("\nplease the workyears:\n"); scanf("%d",&empl[i].p.workyears); } else if (strcmp(empl[i].position,"sin")==0)
261

int workyears; char grade;

{ else }

printf("\nplease the grade:\n"); scanf(" %c",&empl[i].p.grade); } printf("input error!\n");

printf("\n"); for(i=0;i<1;i++) { if(strcmp(empl[i].position,"gen")==0) printf("%20s %4c %6d %10s %6d \n", empl[i].name,empl[i].sex,empl[i].age,empl[i].position, empl[i].p.workyears); else printf("%20s%4c%6d%10s%6c \n", empl[i].name,empl[i].sex,empl[i].age,empl[i].positio n,empl[i].p.grade); } }
第八章 类和对象 8.1 面向对象程序设计方法概述 8.1.1 面向对象程序设计的基本概念 一、对象 二、类 三、消息 四、方法

8.1.2 面向对象程序设计的基本特征 一、抽象 二、封装 三、继承 四、多态

8.1.3 面向对象的程序设计的特点 8.1.4 面向对象的软件开发过程 8.2 类的声明和对象的定义 一、类和对象的关系
262

二、声明类类型 三、定义对象的方法 四、类和结构体的异同 8.3 类的成员函数 一、成员函数的性质 二、在类外定义成员函数 三、inline 成员函数 四、成员函数的存储方式 8.4 对象成员的引用 一、通过对象名和成员运算符访问对象中的成员 二、通过指向对象的指针访问对象中的成员 三、通过对象的引用访问对象中的成员 8.5 类和对象的简单应用举例 8.6 类的封装性和信息隐蔽 一、公用接口与私有实现的分离 二、类声明和成员函数定义的分离 三、面向对象程序设计中的几个名词 8.

更多相关文档:

C++语言程序设计-谭浩强_图文

C++语言程序设计-谭浩强_计算机软件及应用_IT/计算机_专业资料。第 1C++的...(C 语言本身缺乏这种机制,而 C++正是具备这样的机 制) (4)多态:第 12 章...

《c++程序设计》谭浩强课后习题答案

c++程序设计谭浩强课后习题答案_理学_高等教育_教育专区。第一章 1.5 题 #...} 3.12 题 #include <iostream> using namespace std; int main () {long...

c++程序设计 谭浩强 答案 完整版

搜试试 3 悬赏文档 全部 DOC PPT TXT PDF XLS ...c++程序设计 谭浩强 答案 完整版 第一章 1.5 题 ...将输入的第二个字符赋给 return 0; } 3.12 题...

C++程序设计谭浩强第1章2013修订

C++程序设计谭浩强第1章2013修订_理学_高等教育_教育专区。c++课件C++语言程序设计学习目的: 1. 程序设计是计算机及其相关专业学生必备的技能之一。 2. 通过本课程...

c++程序设计谭浩强第9章

实用PPT模板 如何化解七大面试提问方... Power Point...c++程序设计谭浩强第9章 暂无评价|0人阅读|0次下载...1(12,25,30); cout<<"The volume of box1 is...

《C++程序设计》谭浩强版实验指导书

搜试试 3 帮助 全部 DOC PPT TXT PDF XLS ...《C++程序设计谭浩强版实验指导书_理学_高等教育_...12C++程序设计》实验指导 要求:若干个数用赋...

C++程序设计谭浩强第2章2013修订

C++程序设计谭浩强第2章2013修订_计算机软件及应用_IT/计算机_专业资料。c++课件第二章 数据类型与表达式 2.1 C++数据类型(P19~20) 1.整数类型整数类型的标识符...

c++程序设计谭浩强课后习题答案(完整版)

c++程序设计谭浩强课后习题答案(完整版)_工学_高等教育_教育专区。第一章 1.5 ...} 3.12 题 #include <iostream> using namespace std; int main () {long...

c++程序设计 谭浩强版答案

搜 试试 帮助 全部 DOC PPT TXT PDF XLS ...c++程序设计_谭浩强_答案(... 35页 免费如要投诉...} 1.8 题 #include <iostream> 第一章 1.5 题 ...

《c++程序设计》谭浩强_答案

搜 试试 帮助 全部 DOC PPT TXT PDF XLS ...《c++程序设计谭浩强_答案 隐藏>> 第一章 1.5 ...将输入的第二个字符赋给 return 0; } 3.12 题...
更多相关标签:
网站地图

文档资料共享网 nexoncn.com copyright ©right 2010-2020。
文档资料共享网内容来自网络,如有侵犯请联系客服。email:zhit325@126.com