9512.net
甜梦文库
当前位置:首页 >> 其它课程 >>

信息学编程-C++基础



简单的C++程序介绍
高级语言编译过程
库文件 (各种函数) 源程序 目标文件 编译 compile 可执行文件

(文本文件)
*.CPP

(二进制文件)
*.OBJ

(二进制文件)
连接 link *.EXE

F7
在Vitual

C++系统中,可直接从源程序编译连接至可执行 程序,但依然要生成*.OBJ及*.EXE这两个文件。 1

一个简单的C++程序 #include<iostream.h>
函数体 开始
主函数

包含文件

void main(void )

分号,一条完整 语句的结束符

{ cout<<“I am a student.\n”; //输出字符 串 }
函数体 结束 输出流,在屏幕上打 印引号内的字符串
注释或说明

本程序编译执行后,在DOS屏幕上打印出
I am a student.
2

第二章 数据类型、运算符与表达式

3

data

Program

CPU
运算器
(2000H)+(2002H)

内存

外存
硬盘 软盘

2000H 2001H 2002H 2003H 2004H

3

3+5=?

5
8 内存

用一个字节表示整数,范围为-128~127;用两个字节表 示整数,范围为-32768~ 32767。一般用四个字节表示整 4 数。(举例)

15 14 13 12 11 10

9

8

7

6

5

4

3

2

1

0

有符号数 无符号数

0 1 1 1 1 1 1 1 1 1 1 1 1 1 11
0 1 1 1 1 1 1 1 1 1 1 1 1 1 10 …… 0 0 0 0 0 0 0 0 0 0 0 0 0 0 01

32767

32767

32766 32766 …… 1 1

0 0 0 0 0 0 0 0 0 0 0 0 0 0 00

0

0
65535

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1(补码)

1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 ……
1 0 0 0 0 0 0 0 0 0 0 0 0 0 01 1 0 0 0 0 0 0 0 0 0 0 0 0 0 00

-2 65534 ……
-32767 -32768 32769
5 32768

常量与变量 常量:在程序运行过程中,其值一直保持不变的 量为常量。

常量也区分不同的类型:30,40 为整型,30.0, 40.0为实型,编辑器只是根据其表面形式来判断其 类型。
变量:在程序运行过程中,其值可以改变的量为 变量。 变量在程序的执行中能够赋值,发生变化。变量 有一个名字,并在使用之前要说明其类型,一经 说明,就在内存中占据与其类型相应的存储单元。
6

#include<iostream.h> #define PRICE 30 //常量,在程序中保持不变 void main(void) { int num, total; //定义变量,在内存中开辟区间 num total num=10; //变量赋值,10为常量

total=num*PRICE;
cout<<“total=“<<total; //输出结果

10 PRICE

300

}

其中:num=10 30 total=num*PRICE 是赋值号,不同于数学意义上的等号。

7

C++中有多种数据类型,均有常量与变量之分,各 占不同的内存空间,正确定义与使用数据是编写 程序的基本前提。

8

变量名的命名方法:

变量名、数组名、函数名…称为标识符。
标识符只能由字母、数字、下划线这三种字符组成,且第 一个字符必须为字母或下划线,长度不大于247个字符, 大小写不通用。(关键字不能作为标识符)。

关键字即是VC++的语法要求中使用的字。
如 int if while 等。

正确的标识符:INT, sum , de12, SUM等。变量必须使 用前定义,以分配空间。 举例说明
9

abc English 2xy x-y if Else b(3) Chine_bb b3y AbsFloat float

‘def’

一般变量都是用匈牙利命名法命名的。 int nCount; char chChoice;

10

整型数据
整型常量:

常量是根据其表面形式来判定,整型量即是没有小数点的 整数,范围:-231~(231-1) ,有三种形式: 1)十进制(默认方式)
2)八进制 以0开头

43 1345 87654
043, 056, 011

3)十六进制 以0x开头 (举例说明)

0x12

0xa3

0x34

0xdf

11

#include<iostream.h>

void main(void)
{ int int10,int8,int16; //定义3个整型变量 int10=10; int8=010; //默认为十进制 //八进制 输出

int16=0x10;

//十六进制

int10=10
int8=8 int16=16

cout<<"int10="<<int10<<endl; cout<<"int8="<<int8<<endl; cout<<"int16="<<int16<<endl; }

12

整型变量: 分为有符号型与无符号型。 有符号型: short 在内存中占两个字节,范围为-215~(215-1) int 在内存中占四个字节,范围为-231~(231-1)

long在内存中占四个字节,范围为-2-31~231-1
无符号型:最高位不表示符号位

unsigned short 在内存中占两个字节,范围为0~216-1
unsigned int 在内存中占四个字节,范围为0~232-1

unsigned long在内存中占四个字节,范围为0~232-1

13

1)整型常量亦有长短之分,常量中无unsigned型,但一 个非负的整型常量可以赋给unsigned型的变量。
2)若一个常量定义为长整型数,则在其后加l或L进行区 分。 如:32l 32L 564L等,内存为其分配四个字节存储。 一个数在内存中为

11111111111111111111111111111111
当这个数为有符号数时,是-1;为无符号数时,是232-1

内存中的数是以补码的形式存放的。(举例说明)

14

#include <iostream.h>

不同类型的整型数据间 { unsigned short a; 的赋值归根到底就是一 条:按存储单元中的存 short int b= -1; 储形式直接传送。
void main() a=b; cout<<"a="<<a<<endl; unsigned short a;

}
结果:65535

a 1111111111111111
1 b 1 1 1 1 1 1 1 1 1 1 1 1 1 1 115

实型数据
实型数又称浮点数,有两种表示方式: 1)十进制形式: 23.0 24.5 3.56789 356789e1 e前有数字,后

2) 指数形式: 23E1 145e-1 面必须是整数。

实型变量分单精度 float 和双精度 double 两种形式: float:占四个字节,提供7~8位有效数字。 double: 占八个字节,提供15~16位有效数字。 举例说明
16

#include<iostream.h>

void main(void)
{ float a, b;

double c, d;
a=0.01; b=3.45678e-2; c=3.45678e-2; d=9.7654e-5;

a=0.01 b=0.0345678

c=0.0345678

d=9.7654e-005

Press any key to continue

cout<<"a="<<a<<'\t'<<"b="<<b<<endl; cout<<"c="<<c<<'\t'<<"d="<<d<<endl;

}

17

实数是既有整数又有小数的数。

实数可以表示成:N=S×RJ
S 称为尾数,尾数决定有效数字,即数字的精度。

J 表示指数(阶码)。
R 是基数,可取2,4,8,16等,对具体机器而言,基数 取好后,就不能再变了。 数有正有负, 所以设置数符; 阶码亦有正负, 所以设置阶符

如果为实数,则用浮点数的形式在内存存储,表示如下:
Jt 阶符 J 阶码 Sf 数符 S 尾数
18

一般用4个字节表示一个浮点数,也有用8个字 节表示的。

字长一定,尾数越多,精度越高;阶码越多, 范围越大。
当计算机中出现小于机器所能表示的最小数 时,机器只能当零来处理,当出现超过机器所能 表示的最大数时,出现溢出现象,一旦出现溢出, 就会停止运算。定点数,浮点数均会出现溢出现 象。
19

字符型数据(char)
字符型数据实际上是作为整型数据在内存中存储的。 计算机是以字符编码的形式处理字符的,因此,我们在计算机内部 是以ASCII码的形式表示所有字符的。所以7位二进制数即可表示 出一个字符,我们用一个字节的容量(8位)存储一个字符。 例如:字符A的ASCII码为0x41或65,在内存中表示为:

0

1

0

0

0

0

0

1

在程序中表示为: char grade ;//定义一个字符型的变量空间(1个字节) grade=‘A’; //必须用‘ ’表示,否则易与标识符混同 ‘ ’内括起来的字符表示该字符的ASCII码。
20

进一步,由于在内存中的形式与整型数据相同,所以,可以直接用 其整型值给变量赋值。 char grade; grade=65; 以下的赋值形式均是等同的。 grade='A'; grade=65 ; grade=0x41; grade=0101;

#include<iostream.h> 输出: void main(void) a=A { char a,b; b=A a=‘A’; //输入ASCII码 b=65; //输入十进制数 即在内存中的表示均是相同的 cout<<"a="<<a<<endl; 1 0 0 0 0 0 1 cout<<"b="<<b<<endl; 0 21 }

非打印字符
有些ASCII的字符代表某些操作,不能打印出来, 如回车、退格等,可用两种方式表示这些字符。 1)用ASCII码的形式 2)用转义字符 char re=13; char re=‘\n’;(p15)

22

转义字符 \a \n \t \b \r \f \v \\ \′ \" \0 \ddd \xhh

含 义 响铃 换行,将当前位置移到下一行开头 水平制表(跳到下一个tab位置) 退格,将当前位置移到前一列 回车,将当前位置移到本行开头 换页,将当前位置移到下页开头 竖向跳格 反斜杠字符“\” 单引号(撇号)字符 双引号字符 空字符 1到3位8进制数所代表的字符 1到2位16进制数所代表的字符

ASCII代码 7 10 9 8 13 12 8 92 39 34 0
23

转义字符虽然包含2个或多个字符,但它只代 表一个字符。编译系统在见到字符“\”时, 会接着找它后面的字符,把它处理成一个字 符,在内存中只占一个字节。

24

典型转义字符 :
‘\n’换行 输出区 ‘\b’ 退格 '\t' 下一个

若输出中包含这些特定格式,则再加一个\ 输出 c:\tc\tc 表示为cout<<"c:\\tc\\tc";

可以用转义字符表示任一一个ASCII字符 ‘\ddd’ (八进制) ‘\xhh‘ (十六进制) '\101' '\x41' '\x61' '\141'
25

#include<iostream.h> void main(void) 输出: { c1=a c2=a char c1,c2,c3,c4; c3=a c4=a char n1,n2; 使用转义字符 c1='a'; //字符常量 c1=a c2=a c2=97; //十进制 c3=a c4=a c3='\x61'; //转义字符 c4=0141; //八进制 cout<<"c1="<<c1<<'\t'<<"c2="<<c2<<endl; cout<<"c3="<<c3<<'\t'<<"c4="<<c4<<endl; n1=‘\n’; //转义字符:回车 n2=‘\t’; //转义字符:下一个输出区 (Tab) cout<<"使用转义字符\n"; cout<<"c1="<<c1<<n2<<"c2="<<c2<<n1; cout<<"c3="<<c3<<n2<<"c4="<<c4<<n1; 26 }

字符串常量:

用" "表示,在内存中顺序存放,以'\0'结束。
如:"CHINA"

C

H

I

N

A

\0

实际上内存是对应字符的ASCII码形式

0x43
01000011

0x48
01001000

0x49

0x55

0x41
01000001

\0
00000000

01001001 01010101

'a'在内存中占一个字节

a

"a"占两个字节

a

\0

01100001

01100001

00000000
27

标识符常量

在C++中有二种方法定义标识符常量,一种是使用编译预 处理指令;另一种是使用C++的常量说明符const。 例如:
#define PRICE 30

//在程序中凡是出现PRICE均用30替代
#define PI 3.1415926

#define

S “China”

const float pi=3.1415926; //将变量pi定义为常量

(举例说明)

28

#include<iostream.h> #define PI 3.14156 #define S "China" void main(void) { const float pi=3.14156; //变量作为常量使用 cout<<"PI="<<PI<<endl; 输出: cout<<"10*PI="<<10*PI<<endl; PI=3.14156 cout<<S<<endl; // PI=PI+3; 10*PI=31.4156 // pi=pi+4; China cout<<"PI="<<PI<<endl; PI=3.14156 cout<<"pi="<<pi<<endl; pi=3.14156 }

29

下列常量的表示在C++中是否合法?若不合法,指出原因; 若合法,则指出常量的数据类型。

32767

35u

1.25e3.43L

0.0086e-32

‘\87’ “Computer System” ‘\96\45’ -0 +0 .5 -.567

“ a”

‘ a ’

30

变量 1) 在程序的执行过程中,其值可以改变的量 称为变量。 2) 变量名必须用标识符来标识。 3) 变量根据其取值的不同值域,分为不同类 型的变量:整型变量、实型变量、字符型变 量、构造型变量、指针型变量等等。
31

4) 对于任一变量,编译程序要为其分配若干 个字节(连续的)的内存单元,以便保存变 量的取值。 5) 当要改变一个变量的值时,就是把变量的 新的取值存放到为该变量所分配的内存单元 中;用到一个变量的值时,就是从该内存单 元中取出数据。 6) 不管什么类型的变量,通常均是变量的说 明在前,使用变量在后。
32

int i, j, k;
四个字节的 连续空间

//定义了三个整型变量i,j,k
四个字节的 连续空间 四个字节的 连续空间

i

j

k

float x,y,z;
四个字节的 连续空间

开辟空间后 ,空 四个字节的 连续空间 间中为随机值
y

//定义了三个实型变量x,y,z
四个字节的 连续空间

x

z

char c1,c2; //说明了二个字符型变量c1,c2

double dv1;//说明了一个双精度型变量dv1
1个字节的 空间 1个字节的 空间 八个字节的 连续空间

c1

c2

dv1

33

变量赋初值 在定义变量的同时给变量赋值,即在内存中开辟出一个空 间后马上给此空间赋值。

但这个空间的值并不是固定不变的,在程序的运行中一样 可以改变。 int a=4; //定义语句,在开辟空间后马上为空间赋值
a=6; //重新为该空间赋值
4 6

a
char a='\x64', b='d'; a=‘A’; b=‘\n’; a2=121; int a1=6, a2=98; a1=011;
34

算术运算符和算术表达式
一、算术运算符和算术表达式 + - * / %

用算术运算符连接起来的式子是算术表达式
两个整数相除结果为整数 1/2=0 5/2=2

整数才可求余,余数的符号与左边数的符号相同。 3%2=1 -3%2=-1 3%-2=1 -3%-2=-1 8%4=0

二、优先级与结合性 () * / % + —
35

三、强制转换类型 (类型名)(表达式) (double) a (int) (x+y) (int) 6.2%4=2

在强制类型运算后原变量不变,但得到一个所需 类型的中间变量。 如:int x; x=5 y=5.8 y的值没有改 变,仍是单精 度浮点型
36

float y=5.8;
x=(int)y;

四、自增、自减运算符 (难点) i=6; i++; i=i+1
6 7 i

++ ++i;
7 6 i

-- i=i+1 i=7

i=7

i=6; i--; int i, j; i=3;

i=i-1
3 4 i

i=5
4 j

--i ; int i, j; i=3;

i=i-1
3 4 i

i=5
3 j

j = ++i;

j = i++;

i=4 j=4

i=4 j=3

++在前, 先运算,后赋值

++在后, 先赋值,后运算 37

1)自增、自减运算符只能用于变量,不可用于常量和表 达式
因为表达式在内存内没有具体空间,常量所占的空间不能 重新赋值 3++ (x+y)++ (-i)++

2)结合方式自右至左,优先级最高,向右取最大 -i++ -(i++) i+++j 5 (i++) +j i=4, j=2
38

若i=3, j=2 (i++) +j 等于

赋值运算符和赋值表达式
bmw=2002 "="左边必须是变量名。 若“ = ” 两边变量类型不同,在赋值时要进 行类型转换。 转换原则:根据左边变量的类型转换。
39

少字节?多字节 1)若多字节变量为unsigned ,则转换后多余字节补 零。 short int a=-1; unsigned long b; b=a;
unsigned
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 a

b
40

2)若多字节变量为有符号型,则转换后扩展少字 节的最高位。
short int a=-1; long b; a 1 1 1 1 1 1 1 1

b=a; 有符号型,符号扩展

b 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
转换后,数据的符号不变。
41

多字节?少字节

低位照搬 int a=-1;
short int b; b=a;

int a=65535;
short int b; b=a;

b=-1

b=-1

a 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

b 1 1 1 1 1 1 1 1
42

复合的赋值运算符 a+=3 a=a+3 x*=y+3 x=x*(y+3) x/=x-4 x=x/(x-4)

x+=y
i+=j--

x=x+y
i=i+(j--)

赋值表达式
a=b=5 ; b=5 a=5
43

"="的结合性为自右至左

a=12;

a+=a-=a*a;

a=a-(a * a) =12-(12*12)=-132 a=a+(-132)=-132-132=-264
a -264 -132 12

44

关系运算符和关系表达式
关系运算符(比较运算)

< > <= >=
1. = = 与 =

==

!=

a=5; 赋值运算

a= =5;判断是否相等

2. < > <= >= 的优先级大于= = !=
3. 算术运算符的优先级大于关系运算符的优先级
45

关系表达式:用关系运算符将表达式连接起来称 为关系表达式。其值非真即假。在C++语言中,用 非0代表真,用0表示假。关系表达式的结果只有 两个,真为1,假为0。 a= ='a' 0

a=2 b=3 c=4
a>2 0 0 1

a>'a'

0

b=a= =2 1

a>b+c
a= =2

'a'>'A'
b= ='a'+1

1
0

c-a= =a

1

46

逻辑运算符 1. 运算符 与&& 或 || 非!

&&
A 0 0 1 B 0 1 0 结果 0 0 0 A 0 0 1

||
B 0 1 0 结果 0 1 1


A 结果

0
1

1
0

有 0出 1, 有 1出 0
47

1

1

1

1

1

1

有0出0,全1出1

有1出1,全0出0

A,B同时成立

A或B有一个成立

例如:两个条件:江苏籍 男生 江苏籍的男生 江苏籍的学生和所有男生 非江苏籍的学生 注意: 1.优先级:!?&&?| | 江苏籍&&男生 江苏籍||男生 !江苏籍

!?算术?关系?逻辑?赋值?逗号
48

2.作为条件,所有非0值均为真;作为结果,只有0 或1两种。 5>3 && 2 || 8<4-!0 3.不可写为 1<x<10 应为:1<x && x<10

4.当前面的表达式可以得出整个表达式的结果时, 不必再求后面的表达式。 a&&b&&c 当a为0时,表达式为0,不必求b与c。
a||b||c 当a为1时,表达式为1,不必求b与c。
49

x=4 y=5

i= ++x= =5 || ++y= =6 i= x++= =5&& y++= =6
判断某年是否为闰年 1)能被400整除

x=5 y=5 i=1 x=5 y=5 i=0

year%400= =0

2)能被4整除,不能被100整除 (2200年不是) year%4= =0&& year%100!=0 (year%400= =0) || (year%4= =0&&year%100!=0)
50

当c=4时,以下的值各多少? (c=1)&&(c=3)&&(c=5) 1 0 0

(c= =1)||(c= =2) || (c= =5)
(c!=2) && (c!=4) &&(c>=1)&&(c<=5)

51

sizeof()运算符
sizeof() 运算符是一个单目运算符,用于计算某一 个操作数类型的字节数。其格式为: sizeof(<类型>) sizeof(int) //其值为4 sizeof(float) //其值为4 sizeof(double) //其值为8 sizeof(char) //其值为1
52

逗号运算符和逗号表达式
表达式1,表达式2,表达式3,…,表达式n 顺序求解,结果为最后一个表达式的值,并且优 先级最低。

a=(3+4, 5*6, 2+1);
a=3*3, a+6, a+7; (a=3*5, a*4), a+5

a=3
16 20 a=9 a=15
53

下列语句中表达式中i, j的值各为多少 1、int i=0, j=0; i=3,j=1 i=3, (j++)+i ; 2、 int i=0, j=1; i+=j*=3;

i=3,j=3

3、int i=1, j=0;
j=i=((i=3)*2); i=6,j=6

4、int i=1, j=1;
i+=j+=2; i=4,j=3

54

各类数值型数据间的混合运算 整型、实型、字符型数据间可以混合运算。 在进行运算时,不同类型的数据要先转换成同一 类型的数据再进行运算。 转换规则如下: 10+'a'+1.5-87.65*'b'
double long unsigned float

int

char
55

第三章

简单的输入输出

56

输入语句:cin 程序在执行期间,接收外部信息的操作称为
程序的输入;而把程序向外部发送信息的操

作称为程序的输出。在C++中没有专门的输
入输出语句,所有输入输出是通过输入输出

流来实现的。

57

要使用 C++ 提供的输入输出时,必须在程序
的开头增加一行:

#include <iostream.h> 即包含输入输出流的头文件“iostream.h”。
有关包含文件的作用,在编译预处理部分

(第五章)作详细介绍。
58

输入十进制整数和实数
cin >> <变量名1>《 >> <变量名2> ...... 》(举例说明)

int a,b;
cin>>a>>b; //程序运行至此停下,等待从键盘输入变量值
键盘 3 a

键盘输入:3 5<CR> 或:3<CR> 5<CR> 均可。
键盘

5 b
59

输入语句自动过滤空白字符。

浮点型数据同整型数据一样。 float c,d; cin>>c>>d; char ch1,ch2; cin>>ch1>>ch2; 若输入:ab<CR> 则ch1为a, ch2为b。

若输入:a b<CR> 则ch1为a, ch2为b。

字符型变量过滤空白字符。cin格式过滤空白字符
60

float a;
int i1,i2; char ch1,ch2;

输入:34 5.678 1a b<CR>
i1:34 a:5.578 ch1:a i2:1 ch2:b

cin>>i1>>a>>i2>>ch1>>ch2;

在缺省的情况下,cin自动跳过输入的空格,换言 之,cin不能将输入的空格赋给字符型变量,同样 地,回车键也是作为输入字符之间的分隔符,也 不能将输入的回车键字符赋给字符型变量。
61

若要把从键盘上输入的每一个字符,包括空格和 回车键都作为一个输入字符赋给字符型变量时, 必须使用函数cin.get()。其格式为:
cin.get(<字符型变量>);

cin.get()从输入行中取出一个字符,并将它赋给字 符型变量。这个语句一次只能从输入行中提取一 个字符。
char c1; cin.get(c1);
62

char ch1,ch2,ch3;
cin.get(ch1);

则:ch1:A ch2:空格 ch3:B

cin.get(ch2);
cin.get(ch3); 输入:A B<CR>

并且在输入缓冲区中保留回车键。
空格的ASCII码为32
ch2 0 0 1 0 0 0 0 0
63

输入十六进制或八进制数据 在缺省的情况下,系统约定输入的整型数是十进 制数据。当要求按八进制或十六进制输入数据时, 在cin中必须指明相应的数据类型:hex为十六进 制;oct为八进制;dec为十进制。

64

int i,j,k,l; cin>>hex>>i; cin>>oct>>j; cin>>k; cin>>dec>>l; //指明输入为十六进制数 //指明输入为八进制数 //输入仍为八进制数 //指明输入为十进制数

当执行到语句cin时,若输入的数据为:

11 11 12 12<CR>
结果:i:17 j:9 k:10 l:12
65

使用非十进制数输入时,要注意以下几点: 1、八进制或十六进制数的输入,只能适用于整型 变量,不适用于字符型变量,实型变量。 2、当在cin中指明使用的数制输入后,则所指明的 数制一直有效,直到在接着的 cin 中指明输入时所 使用的另一数制为止。如上例中,输入k的值时, 仍为八进制。
66

3、输入数据的格式、个数和类型必须与cin中所列
举的变量类型一一对应。一旦输入出错,不仅使

当前的输入数据不正确,而且使得后面的提取数
据也不正确。

int a, b;

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

cin>>a>>b;

cin>>ab;

67

输出数据

cout

与输入cin对应的输出是cout输出流。
当要输出一个表达式的值时,可使用cout来实现, 其一般格式为: cout << <表达式> 《<< <表达式>......》;

其中运算符“<<”称为插入运算符,它将紧跟其 后的表达式的值,输出到显示器当前光标的位置。
68

int a=6; float f1=12.4; char s1[ ]=“abcd”;
6 a 显示器

cout<<a<<‘\t’<<f1<<‘\t’<<s1<<endl;
12.4
6 12.4 abcd f1

显示器

a b c d \0

显示器

‘\t’为转义字符Tab endl为回车或‘\n’

s1

69

cout将双引号中的字符串常量按其原样输出
char ch1=‘a’,ch2=‘b’; cout<<“c1=“<<ch1<<‘\t’<<“c2=“<<ch2 <<endl; c1=a c2=b<CR>
int i1=4,i2=5;
float a=3.5; cout<<“a*i1=“<<a*i1<<endl<<“a*i2=“<<a*i2<<endl;

a*i1=14

a*i2=17.5

70

指定输出项占用的宽度:

在输出的数据项之间进行隔开的另一种办法是指定输出项 的宽度。如上面的两个输出语句可改写为: cout <<setw(6)<< i<<setw(10)<<j<<endl;
_ _ _ _ _ 4_ _ _ _ _ _ _ _ _12 cout << setw(5)<<m<<setw(10)<<j*k<<endl; _ _ _ _ 7_ _ _ _ _ _ _ _ 24 其中setw(6)指明其后的输出项占用的字符宽度为6,即 括号中的值指出紧跟其后的输出项占用的字符位置个数, 并向右对齐。setw是“set width”的缩写。 71

使用setw()应注意以下三点: 1、在程序的开始位置必须包含头文件 iomanip.h,即在程 序的开头增加: #include <iomanip.h>

2、括号中必须给出一个表达式(值为正整数),它指明
紧跟其后输出项的宽度。 3、该设置仅对其后的一个输出项有效。一旦按指定的宽 度输出其后的输出项后,又回到原来的缺省输出方式。
72

输出八、十六进制数和科学表示法的实数 对于整型数据可指定以十六进制或八进制输出,而对于 实型数据可指定以科学表示法形式输出。例如,设有如 下一个程序: #include <iostream.h> void main(void) { float x=3.14,y=100; cout.setf(ios::scientific,ios::floatfield); //表明浮点数用科学表示法输出 cout << x<<’\t’; cout <<y<<endl; 执行该程序后的输出为: 3.140000e+000 1.000000e+002 }
73

与 cin 中类同,当在 cout 中指明以一种进制输出整 数时,对其后的输出均有效,直到指明又以另一

种进制输出整型数据为止。对实数的输出,也是
这样,一旦指明按科学表示法输出实数,则接着

的输出均按科学表示法输出,直到指明以定点数
输出为止。明确指定按定点数格式输出(缺省的

输出方式)的语句为:
cout.setf(ios::fixed,ios::floatfield);
74

第四章

C++的流程控制语句

75

程序的三种基本结构
1、顺序
A B

2、选择

条件?
真 假 真

x>y?


A

B

z=x

z=y

76

3、循环
当P为真
A

P
Y

N

当型

A
i<10

i++

77

A

直到P为真
直到型

A N

P
i++ i>=10

Y

78

if语句 判断选择语句,有三种形式: 1) if(表达式) if (a>b) cout<<a; 2) if(表达式) 语句1 else 语句2
真 真

条件

语句



语句

条件



语句1 语句2

if (a>b) cout<<a; else cout<<b;

79

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

else if (表达式2)
...... else if (表达式n)
表达式1

语句2

语句n


表达式2

else 假

语句n+1





表达式3


表达式4





语句1

语句2

语句3

真 语句4

语句5
80

表达式1


表达式2




表达式3




表达式4





语句1

语句2

语句3

真 语句4

语句5
81

注意:1) if 后可跟复合语句。
2) 注意 ;的位置。 3) 注意多重 if else 的搭配。
if (a>b) { a=1; b=0; } 真

a>b



else
{ a=0; b=1; }

a=1 b=0

a=0 b=1

82

if (i >j) i++;



i>j



i+ + i>j

if (i>j); i++;





i+ + if 总是与它上面最近的 else 配对,如要改变,用复合语 句{ }。 注意书写格式,相互配对的语句要对齐。
83

例:输入两个实数,按代数值由小到大次序输出这两个数。 void main( void ) { float a,b,t; //定义变量 cout<<“ Input 2 Real Number:\n";//在屏幕上的提示信 息 cin>>a>>b; //给变量赋值 a:7, b:3 if(a>b) { t=a; a=b; b=t; }//交换数据,用中间变量 cout<<a<<‘\t’<<b<<endl;//输出变量 输出结果: } t a 7 3 7 3 7
b 3 7
84

嵌套的条件语句(举例说明) x=100; a=10; b=20; ok1=5; ok2=0; if(a<b)

if(b!=15)
if(!ok1) x=1;

else if (ok2) x=10; x=-1; x=-1

85

条件运算符

是C++中的唯一的三目运算符。
表达式1?表达式2 :表达式3 max=a>b?a:b ; // 求a, b中的大者



表达式1



表达式2 表达式3

当 a=2 b=1 a>b为真,表达式的值等于a, max值为2

当 a=1 b=2 a>b为假,表达式的值等于b, max值为2 注意: 1. 条件运算符的优先级比赋值运算符高
x=(x=3) ? x+2 : x-3

x=5
a>b?a:c>d?c:d
z=a>b?'A':a+b
86

2. 结合方向自左至右

3. 三个表达式的类型可不同

x=9, y=6, z=5;

x=((x+y)%z>=x%z+y%z)?1:0;
cout<<"x= "<<x<<endl; x=0 x=1; y=2; z=3; x+=y+=z;
9

y=y+z=5 x=x+5=6

cout<<( z+=x>y?x++:y++)<<endl;
87

void main(void )

x 6

y 5

z 3

输出

{ int x=1,y=2,z=3;
x+=y+=z; cout<<x<y?y:x<<endl; cout<<x<y?x++:y++<<endl; cout<<x<<“,”<<y<<endl; cout<<y<<“,”<<z<<endl;

6
6 6

5
6 6 7

3
3 3 9

6
5 6,6 9

cout<<z+=x>y?x++:y++<<endl; 6

6
3 3

7
4

9
4

7,9 4 0
1
88

x=3; y=z=4;
cout<<z>=y&&y>=x<<endl; }

cout<<(z>=y&&y= =x)?1:0<<endl; 3 4

4
4

执行以下程序段后,变量a,b,c的值分别是: int x=10, y=9; int a,b,c;

a=(--x= =y++)?--x:++y; x=8 y=10
b=x++; c=y;

a=8

b=8 x=9
c=10
89

void main(void ) { int a=5,b=1,c=0; if(a=b+c) cout<<“* * *\n”;

else cout<<“$ $ $\n”;
}

***

90

switch语句
多分支选择语句。if语句只有两个分支,而实际问题中常 常需要用到多分支的选择。如,成绩分为A(100~85)、 B(84~70)、C(69~60)、D(60以下)等。
‘A’
N ‘B’ N

‘C’
Y Y Y 100~85 84~70 69~60

N N

‘D’ Y no pass

显示出错 91

cin.get(grade); if(grade= =‘A’)

cout<<“100~85\n”;
else if (grade= =‘B’) cout<<“84~70\n”; else if (grade= =‘C’) cout<<“69~60\n”; else if (grade= =‘D’) cout<<“no pass\n”;

else
cout<<“error\n”;
92

switch(表达式) { case 常量表达式1:语句1 case 常量表达式2:语句2 …… case 常量表达式n:语句n default:语句n+1 }
switch(grade) { case ‘A’: cout<<“100~85\n”; case ‘B’: cout<<“84~70\n”; case ‘C’: cout<<“69~60\n”; case ‘D’:cout<<“no 如果grade为 ‘A’,则结 果为 100~85 84~70 69~60 no pass error
93

其流程为:先计算表达式的值,然后顺序地

与case子句中所列出的各个常量进行比较,若
表达式的值与常量中的值相等,就开始进入

相应的case语句执行程序,遇到case和default
也不再进行判断,直至switch语句结束。如果

要使其在执行完相应的语句后中止执行下一
语句,可以在语句后加break。
94

switch(grade) { case ‘A’:cout<<“100~85\n”; break; case ‘B’:cout<<“84~70\n”; break; case ‘C’:cout<<“69~60\n”; break; case ‘D’:cout<<“no pass\n”; break; default:cout<<“error\n”;
95

注意:
1、switch与if不同,它仅能判断一种逻辑关系,即 表达式是否等于指定的常量,而 if 可以计算并判断 各种表达式。

2、case子句后必须为常量,常常是整型和字符型。
3、default可以省略,这时,不满足条件什么也不 执行。

96

4、case和default只起标号的作用,顺序可以颠倒, 颠倒时注意后面的break语句。
5、多个case语句可以共用一组程序。 case ‘A’: case ‘B’:

case ‘C’: cout<<“pass!\n”;

97

void main(void )
{ int i=10;

switch(i)
{ case 9: i++;

case 10: i++;
case 11: i++;

i=11 i=12

default: i++;
} cout<<“i=”<<i<<end l; }

i=13

i=13
98

int x=1, y=0, a=0, b=0; switch( x ) { case 1: switch( y ) { case 0: a++; break; a=1 case 1: b++; break; } case 2: a++; b++; break; a=2 b=1 case 3: a++; b++; a=2 b=1 } cout<<“a=“<<a<<‘\t’<<“b=”<<b<

99

有3个整数a,b,c,由键盘输入,输出其中最大的 数。

100

while语句
表达式

假 真 语句组1

while ( 表达式)
{ 语句组1 } {语句组2}

a=3; while(a<100) a=a+5;

语句组2

当循环语句超过一条时,要

cout<<“a=“<<a; 用{ }将语句组组合在一起。
101

求 1+2+3+……+100 void main(void)

5050 1 3 6 0 sum

{ int i=1,sum=0; //定义变量,初始化
while(i<=100) //构造循环 { } } sum=sum+i; // 循环体,多次执行

100 101 2 3 4 1
i

i=i+1;

循环结束!!

cout<<“sum=”<<sum<<endl; //输出结果 sum=5050

实际上是将i不停地累加到一起

2

循环条件 初值 真 1 循环次数 sum i


3


4


.....


99


100


101
102

0 1

1 2

3 3

6 4

10 5

5050 100 101

注意: 1、循环体如果为一个以上的语句,用{ }括起。

2、循环体内或表达式中必须有使循环结束的条件, 即一定有一个循环变量。 3、while表达式可以成为语句,要特别小心。

103

k=2;

while(k!=0) cout<<k, k--;
cout<<endl;

k 循环条件 输出

2 真 2

1 真 1

0 假 回车

输出:21

104

void main(void)
{ int num=0;

while(num<=2)
{ num++; cout<<num<<endl; } }
0 1 2 3 num 真 真 假 循环条件 真 输出 1<CR> 2<CR> 3<CR> 无

1 2 3

105

void main(void) { int y=10; while (y--); cout<<“y=”<<y<<endl; }
y 条件 输出
10 真 无 9 真 无 ...... 真 无

输出是什么?
循环几次?

1 真 无

0 假 -1

输出:y=-1

循环:10次

106

k=10; while( k=0 ) k=k-1;
k
表达式

cout<< k;

10
0

输出:0

107

以下语句,循环退出时x为多少?

x=10; while (x!=0) x--;

x=0 x=0 x=-1 x=0

x=10; while (x) x--;
x=10; while(x--); x=10; while(--x);

108

#include<iostream.h> 从键盘输入2473<CR>,则程序 void main() 的输出结果是: { char ch; while(cin.get(ch)&&ch!='\n') switch (ch-'2') { case 0: case 1: cout<<(char)(ch+4); case 2: cout<<(char)(ch+4); break; case 3: cout<<(char)(ch+3) ; default : cout<<(char)(ch+2); break; } cout<<endl; } 输出: 668977
109

do—while语句 do
语句组1

{ 语句组1}
while(表达式); {语句组2}
A

表达式




语句组2

直到P为真
直到型

110

求 1+2+3+……+100
void main(void) { int i=1,sum=0; //定义变量,初始化 do { //构造循环 sum=sum+i; // 循环体,多次执行 i=i+1; }while (i<=100); cout<<“sum=”<<sum<<endl; //输出结果 }
111

注意:

do—while首先执行循环体,然后再判断 表达式,至少执行一次循环体。当第一 次循环表达式的值为真时,while与do— while的结果完全一样,否则结果不相同。

112

x=0,y=0; do { y++; x*=x;

若为while循环,则
一次也不执行循环 体,输出为: y=0, x=0

} while ((x>0)&&(y>5));

cout<<“y=“<<y<<“,”<<“x=”<<x<<endl;
y x 条件 0 0
1 0 假
113

输出:y=1,x=0

s=7; do s-=2;
s 表达式 7 第一次 5 N

while(s= =0);
cout<<“s=”<<s<<endl;
输出:s=5
114

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

表达式1

表达式2 Y

N

{语句组1(循环体)}

语句组1
表达式3

{语句组2}
语句组2

for(循环变量赋初值;循环结束条件;循环变量增值)
115

求 1+2+3+……+100
void main(void)
{ int i, sum; for (i=1, sum=0; i<=100; i++) sum=sum+i; void main(void)

{ int i, sum;
i=1; sum=0;

while(i<=100)
{ sum=sum+i; i=i+1; }

cout<<“sum=”<<sum<<endl;
}

cout<<“sum=”<<sum<<endl;
}
116

注意:
1、当型循环,条件测试是在循环开始时进行,有可能一次 也进入不了循环体。 2、for语句中的三个表达式可以部分省略或全部省略,

但;不能省略,若省略表达式2,则表示循环条件为真。

3、for语句中三个表达式可以是任何有效的C语言表达式。

117

void main(void)
{ char i, j ;

for (i=‘a’,j=‘z’ ; i<j ; i++, j-) cout<<i<<j; cout<<endl; } 次数 i j i<j 输出

输出:azbycx.......lomn

a z
真 az

b y
真 by

c x
真 cx

...... .....
真 .....

m n
真 mn

n m
假 CR

118

以下循环结果如何? for ( i=0, k= -1; k=1; i++, k++) cout<<“****\n”; 1 次 10 次,最少执行_____ 以下循环最多执行_____

for (i=0, x=0; i<=9&&x!=876 ; i++)
cin>>x;
119

循环的嵌套 一个循环体内又包含另一个完整的循环体,称为循 环的嵌套。 注意:

1、循环体内有多个语句要用{}括起来。
2、书写格式要清晰。 for ( ; ; )
{ ..... for ( ; ; ) { ....... } }

120

void main(void)
{ int i, j, k=0, m=0; for ( i=0; i<2; i++)

输出: k=0, m=5

{

for ( j=0; j<3; j++)
k++; k- =j;

} m=i+j; cout<<“k=“<<k<<“, m=“<< m<<endl; }

i 0 i<2 真 0 1 2 j j<3 真 真 真 1 2 3 k

1 真

3 假 0

0 1 2 真 真 真 1 2 3

3 假 0

121

几种循环的比较 while ( 表达式)

do
{ 语句组1} while(表达式); {语句组2}
假 语句组1

{ 语句组1 }
{语句组2}

表达式 真 语句组1

表达式 真



语句组2

语句组2

122

for(表达式1;表达式2;表达式3) {语句组1} {语句组2}
表达式2 真 语句组1 表达式3

表达式1


语句组2

123

最大公约数与最小公倍数
求两自然数m , n的最大公约数

欧几里德算法(m>n)
1、m被n除得到余数r(0≤r ≤n) 3、m?n , n?r , 回到1 r=m%n

2、若r=0,则算法结束,n为最大公约数,否则做3 m=6 n=4
m=4 n=2

r=m%n=6%4=2
r=m%n=4%2=0

while ( r=m%n ) { }
124

m=n;

n=r ;

所以,公约数=2

最小公倍数为两数之积除以最大公约数。4*6/2=12

最大公约数:能同时被m和n整除的最大数。

r=m>n?n:m
for(i=1; i<r; i++) if(m%i==0&&n%i==0)

a=i;
cout<<a;
125

将 12345 的每位分别打印出来。 12345%10=5 12345/10=1234

1234%10=4
123%10=3

1234/10=123
123/10=12

12%10=2
1%10=1

12/10=1
1/10=0

while(n)

{

cout<<n%10<<‘\t’;
n=n/10;

}

126

求级数公式:

x x x x n x S ? 1 ? ? ? ? ? ... ? (?1) 2! 4! 6! 8! (2n)!
首先写出通项,然后再用当前项(第n项)除前一 项,得出后一项比前一项大多少倍。

2

4

6

8

2n

x 通项:(?1) (2n)!
n

2n

第n项/第n-1项:

t=x*x/((2*n)*(2*n-1))

表明前一项比后一项大t倍,即后一项乘t等于前一项 后一项=(-1)×前一项×t
127

后一项=(-1)×前一项×t 设通项为term,则可以写出迭代公式

term=(-1)*term*t; t=x*x/((2*n)*(2*n-1))
当前项 前一项

S=0;term=1;n=1;//一定要赋初值
while(fabs(term)>=1e-5) {
新的

S=S+term; term=(-1)*term*x*x/((2*n)*(2*n-1)); n++;
旧的
128

}

x x x x n x S ? 1 ? ? ? ? ? ... ? (?1) 2! 4! 6! 8! (2n)!
第n项/第n-1项: t=x*x/((2*n)*(2*n-1))
第一项:term=1; 第一次循环:S=S+term; term=(-1)*term*t;
这时左边的term代表第二项,而右边的term为第一项。

2

4

6

8

2n

第二次循环:S=S+term; term=(-1)*term*t;
这时左边的term代表第三项,而右边的term为第二项。
当前项

term=(-1)*term*t;

前一项

同样是term,在循环中不断用旧的数值去推导赋值出新的 129 数值。

x x x x n x S ? 1 ? ? ? ? ? ... ? (?1) 2! 4! 6! 8! (2n)!
S=0;term=1;n=1;//一定要赋初值 while(fabs(term)>=1e-5)

2

4

6

8

2n

{
新的

S=S+term;
term=(-1)*term*x*x/((2*n)*(2*n-1));

n++;

旧的

}
130

break语句和continue语句 break在switch语句中,可以使流程跳过判断体,执 行下面的程序。在循环体中,也可以从循环体内跳 出循环体,提前结束循环。 for ( ; ; ) { cin>>x; if (x= =123) break; } 当输入123时,结束循环。
131

break 只能退出一层循环或switch语句。

a=10 ; y=0; do { a+=2; y+=a; cout<<“a=“<<a<<“, y=“<< y<<endl; if (y>50) break;

} while (a=14); 第一次:a=12 y=12 第二次:a=16 y=28 第三次:a=16 y=44 第四次:a=16 y=60 输出:a=12 , y=12 输出:a=16 , y=28 输出:a=16 , y=44 输出:a=16 , y=60
132

continue:其作用为结束本次循环,即跳过循环体中下面 尚未执行的语句,接着进行下一次是否执行循环的判定。 void main(void)
{ int i; for (i=1 ; i<=5 ; i++ )

{ if (i%2) cout<<“*”;
else } continue; cout<<“#”; 1 cout<<“ $\n”; i i<=5 真 i%2 1 输出 *#

输出:*#*#*#$

2
真 0 无

3
真 1 *#

4
真 0 无

5
真 1 *#

6


}

133

$

void main(void) i=0 i<2 第一次 { int i, j, x=0 ; j 0 1 2 3 for (i=0 ; i<2; i++) 假 真 假 真 j%2 { x++; x 2 2 3 3 for (j=0;j<=3; j++) { if ( j%2 ) continue; x++; i=1 i<2 第二次 } j 0 1 2 3 x++; j%2 假 真 假 真 } x 6 6 7 7 cout<<“x=“<< x<<endl; }

4
4

4 8

输出:x=8

i=2 i<2 结束

134

void main(void ) { int k=0; c++ A B C char c=‘A’; do c B C D { switch (c++) k 2 4 7 { case ‘A’: k++; break; case ‘B’: k--; 真 真 真 case ‘C’: k+=2; break; case ‘D’: k=k%2; continue; case ‘E’: k=k*10; break; default: k=k/3; } 输出:k=4 k++; }while (c<‘G’); cout<<“k=”<< k<<endl; }

D E

E F F G

1 11 4

真 真 假

135

总结: 在循环体中,break从循环体内跳出循环体,提前 结束循环。 for(... ; ... ; ... ) { ........ break; ........ }
136

continue:其作用为结束本次循环,即跳过循环体 中下面尚未执行的语句,接着进行下一次是否执行 循环的判定。
for(... ; ... ; ... ) { while( ...... ) {

........
continue; ........ } }

........
continue; ........
137

求素数:只可以被1与自身整除的数。
判断一个数 t 是否为素数,用2到t-1循环除。
for( i=2; i<t t/2 ; if(t%i==0) break; if (i>=t/2) (i==t) cout<<“是素数。\n”; i++)

else cout<<“不是素数\n”;

进一步,由于 t 不可能被大于 t/2 的数整除,所 以可将循环次数降低。 138

求范围内的素数(50~100):
for(t=50, k=0 ; t<=100; t++) { for( i=2; i<t ; i++) if(t%i==0) 判断t是否 break; 为素数 if (i= =t) { cout<<t<<“ “; k++; if(k%5==0) cout<<endl; } 保证每行输 } 出5个数据

139

鸡兔共有30只,脚共有90只,问鸡兔各有多少?
void main(void)

{ int i; //i代表鸡,则兔为30-i只
for(i=0; i<=15; i++) if(2*i + 4*(30-i)= =90) { cout<<“鸡”<<i<<endl; cout<<“兔”<<30-i<<endl;

}
}
140

一百万富翁 遇到一陌生人,陌生人找他谈一个换钱
的计划,该计划如下:我每天给你十万元,而你第 一天只需给我一分钱,第二天我仍给你十万元,你 给我两分钱,第三天我仍给你十万元,你给我四分 钱,....,你每天给我的钱是前一天的两倍,直到满 一个月(30天),百万富翁很高兴,欣然接受了这

个契约。请编写程序计算陌生人给百万富翁多少钱,

百万富翁给陌生人多少钱?
141

利用循环语句编程,打印下列图形: * 行号 空格 星号 行号: i * * 1 3 1 * * * 空格:4-i 2 2 2 * * * * 3 1 3 * * * 星号:i 4 0 4 * * for(i=0;i<4;i++) *
{ 找规律: 上面四行 for(j=4-i-1;j>0;j--) cout<<" "; for(k=1;k<=i+1;k++) cout<<" * "; cout<<endl<<endl;

}

142

void main(void) { int i,j,k; for(i=0;i<4;i++) { for(j=4-i-1;j>0;j--) cout<<" "; for(k=1;k<=i+1;k++) cout<<" * "; cout<<endl<<endl; } for(i=0;i<4-1;i++) { for(j=4-1-i;j>0;j--) cout<<" * "; cout<<endl<<endl; } }

143

打印图形: * * * * * * * * * * * * * * * *

行号 0 1 2 3

空格 3 2 1 0

星号 1 3 5 7

行号:i 空格:3-i

*

*
*

*
*

*
*

*

*

星号:2*i+1

如果打印n行 行号:0~n-1 空格:0~n-1-i
144

计算:2+22+222+.....+2222222=? 累加和 s=0 22=2*10+2; 设通项为t

所以,通项的循环表示为:
前一项

222=22*10+2;
2222=222*10+2;

t=t*10+2;
当前项

t的初值为2

循环体为: { s = s +t t=t*10+2;



145

void main(void) { int t,s; s=0; t=2; for(int i=0;i<7;i++) { s=s+t; t=t*10+2; } cout<<s<<endl; }

146

满足以下条件三位数n,它除以11所得到的商等于 n的各位数字的平方和,且其中至少有两位数字相 同。 131 131/11=11 12+32+12=11

分析:
数字应该从100循环到999 将每位数字剥出,判断其是否满足条件

147

满足以下条件三位数n,它除以11所得到的商等于 n的各位数字的平方和,且其中至少有两位数字相 同。 131 131/11=11 12+32+12=11 分析:

用a,b,c分别代表三位数,a,b,c分别从0循环到9, 组成所有可能的三位数,然后找出满足条件的数 来。

148

?

2 2 4 4 2n 2n ? ? ? ? ? ?? ? ? 2 1 3 3 5 2n ? 1 2n ? 1
通项:

求n=1000时π的近似值
分析:

迭代算法:
本次计算 的结果

s=s×t

2n 2n t? ? 2n ? 1 2n ? 1
迭代结束条件:

上次迭代 的结果

迭代 1000次

注意s与t的初始值

n从1开始迭代 s=1

149

下面程序的功能是用公式求π的近似值,直到最后一项的 值小于10-6为止。请填空。
void main(void ) { int i=1; double ______

? 1 1 1 1 ? 2 ? 2 ? 2 ??? 2 6 1 2 3 n
2

pi=0;

while (i*i<=10e+6) pi+1.0/(i*i) ; { pi=______________

i++;
} pi=sqrt (6.0 *pi) ; cout<<“ pi=”<<pi<<endl; }
150

有1020个西瓜,第一天卖一半多两个,以后每天卖剩下的 一半多两个,问几天以后能卖完?请填空。 #include”stdio.h”
void main(void ) { int day, x1, x2;

day=0; x1=1020;
x1 while (________ ) x1/2-2 { x2=__________; x1=x2; } day++;

cout<<“day=”<<day<<endl;
}
151

第五章

函数与编译预处理

152

概述
函数是程序代码的一个自包含单元,用于完 成某一特定的任务。

C++是由函数构成的,函数是C++的基本模块。

有的函数完成某一操作;有的函数计算出一 个值。通常,一个函数即能完成某一特定操 作,又能计算数值。
153

为什么要使用函数? 1、避免重复的编程。 2、使程序更加模块化,便于阅读、修改。 所编写的函数应尽量少与主调函数发生 联系,这样便于移植。
参数(多个) 函数值(唯一)

函数体
154

说明: 1、一个源程序文件由一个或多个函数组成,编译程序以文 件而不是以函数为单位进行编译的。 2、一个程序可以由多个源文件组成,可以分别编译,统一 执行。 3、一个程序必须有且只有一个main( )函数,C++从main( ) 函数开始执行。 4、C++语言中,所有函数都是平行独立的,无主次、相互 包含之分。函数可以嵌套调用,不可嵌套定义。

5、从使用角度来说,分标准函数和用户自定义函数;从形 式来说,分无参函数和有参函数。
155

库函数是C++编译系统已预定义的函数,用户根据 需要可以直接使用这类函数。库函数也称为标准 函数。

为了方便用户进行程序设计,C++把一些常用数学 计算函数(如sqrt()、exp()等)、字符串处理函数、 标准输入输出函数等,都作为库函数提供给用户, 用户可以直接使用系统提供的库函数。 库函数有很多个,当用户使用任一库函数时,在 程序中必须包含相应的头文件。 如 #include<iostream.h>等。
156

用户在设计程序时,可以将完成某一相对独立功 能的程序定义为一个函数。用户在程序中,根据 应用的需要,由用户自己定义函数,这类函数称 为用户自定义的函数。 根据定义函数或调用时是否要给出参数,又可将 函数分为:无参函数和有参函数。

157

函数定义的一般形式 一、无参函数 主调函数并不将数据传给被调函数。 无参函数主要用于完成某一操作。
参数(多个) 函数值(唯一)

函数体 类型说明 函数名(void)
不传递参数
158

{ 函数体 }

void main(void ) 两个被调函数 调用函数 { printstar ( ); 主要用于完成 print_message ( ); 调用函数 打印操作。 printstar( ); 调用函数 } 函数类型 函数名 函数体 void printstar (void ) { cout<<“* * * * * * * * * * *\n”; } void print_message (void) { cout<<“ How do you do! \n”; } 159

输出: * * * * * * * * * * * How do you do! ***********

160

二、有参函数

主调函数和被调函数之间有数据传递。主调
函数可以将参数传递给被调函数,被调函数

中的结果也可以带回主调函数。
类型说明 函数名(形式参数列表说明 )

{ 函数体 }
161

函数类型

int max (int x,int y) { int z; 函数名 z=(x>y)? x : y ; 函数体 return z; 函数值 } void main (void ) 主调函数 将实际值a,b传给 { int a,b,c; 被调函数的参数 x,y,计算后得到 cin>>a>>b; 调用函数 函数值z返回 c=max (a , b) ;
实际参数

形参列表说明

cout<<“The max is”<< c<<endl;

162

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

x
2

y
3

z
3

cin>>a>>b;
c=max (a , b) ;

2 a

3 b

3 c

cout<<“The max is”<< c<<endl;

163

函数参数和函数的值 形参是被调函数中的变量;实参是主调函数 赋给被调函数的特定值。实参可以是常量、 变量或复杂的表达式,不管是哪种情况,在 调用时实参必须是一个确定的值。 形参与实参类型相同,一一对应。 形参必须要定义类型,因为在定义被调函数 时,不知道具体要操作什么数,而定义的是 要操作什么类型的数。
164

int max (int x,int y) { int z;

z=(x>y)? x : y ;
return z;

} void main (void )
{ int a,b,c; cin>>a>>b; c=max (a+b , a*b) ; }

若a为3,b为5,则实 参为8, 15,分别送给形 参 x, y。
先计算,后 赋值

cout<<“The max is”<<c<<endl;
165

说明:
1、在未出现函数调用时,形参并不占内存的存储单元,只 有在函数开始调用时,形参才被分配内存单元。调用结束 后,形参所占用的内存单元被释放。 2、实参对形参变量的传递是“值传递”,即单向传递。在 内存中实参、形参分占不同的单元。 3、形参只作用于被调函数,可以在别的函数中使用相同的 变量名。 a 5 8 x y 5 形参 b 8
166

实参

void fun(int a, int b) { a=a*10; a 20 2 b 23 3

b=b+a;
cout<<a<<‘\t’<<b<<endl;

}
void main(void)

{ int a=2, b=3;
20 2 cout<<a<<‘\t’<<b<<endl; fun(a,b); }

2 a
23 3

3 b

167

void fun(int x, int y) { x=x*10;

x

y

50 5

56 6

y=y+x;
cout<<x<<‘\t’<<y<<endl;

}
void main(void)

5 2 a 50 2 56 3

6 3 b

{ int a=2, b=3;
fun(a+b,a*b);

cout<<a<<‘\t’<<b<<endl;
}

形参实参类型相等,一一对应
168

形参必须要定义类型,因为在定义被调函数 时,不知道具体要操作什么数,而定义的是 要操作什么类型的数。

形参是被调函数中的变量;实参是主调函数 赋给被调函数的特定值。在函数调用语句中, 实参不必定义数据类型,因为实参传递的是 一个具体的值(常量),程序可依据这个数值 的表面形式来判断其类型,并将其赋值到对 应的形参变量中。
169

函数的返回值 函数的返回值通过return语句获得。函数只 能有唯一的返回值。
函数返回值的类型就是函数的类型。 return语句可以是一个表达式,函数先计算 表达式后再返回值。 return语句还可以终止函数,并将控制返回 到主调函数。
一个函数中可以有一个以上的return语句,执行 到哪一个return语句,哪一个语句起作用。 170

int add ( int a, int b) { 先计算,后返回 return (a+b); } int max ( int a, int b) { if (x>y) return x ;

若函数体内没有return语 句,就一直执行到函数体 的末尾,然后返回到主调 函数的调用处。
可以有多个return语句
171

else return y;
}

既然函数有返回值,这个值当然应属于某一个确 定的类型,应当在定义函数时指定函数值的类型。

int max (float a, float b) // 函数值为整型
函数返回值的类型,也是函数的类型

不带返回值的函数可说明为void型。 函数的类型与函数参数的类型没有关系。 double blink ( int a, int b) 如果函数的类型和return表达式中的类型不一致, 则以函数的类型为准。函数的类型决定返回值的 172 类型。对数值型数据,可以自动进行类型转换。

如果有函数返回 值, 函数的类型就 是返回值的类型

int max ( int a, int b) { int z; 如果有函数返回 z=x>y?x:y; 值,返回值就是函 return z; 数值,必须惟一。 }

函数体的类型、形式参数的类型必须 在函数的定义中体现出来。
参数(多个) 函数值(唯一)

函数体
173

函数的调用
函数调用的一般形式
函数名(实参列表);

i=2; f (i, ++i);

实际调用: f (3, 3);

形参与实参类型相同,一一对应。
函数调用的方式 作为语句 作为表达式 作为另一个函数的参数 printstar( ); c=max (a,b); cout<<max (a,b);
174

在一个函数中调用另一函数(即被调用函数)需要 具备哪些条件呢? 1) 被调用的函数必须是已存在的函数
2) 如果使用库函数,必须用 #include < math.h> 3) 函数调用遵循先定义、后调用的原则,即被调 函数应出现在主调函数之前。

175

float max(float x, float y) { float z;

形参必须说 明参数类型

z=(x>y)? x : y ;
return z;

被调函数先定义

}
void main (void) { float a,b, c; 定义之后再调用

cin>>a>>b;

实参传递的是一个具体的值, c=max (a+b , a*b) ; 不必说明参数类型 cout<<“The max is”<<c<<endl; }
176

4) 如果使用用户自己定义的函数,而该函数与调 用它的函数(即主调函数)在同一个程序单位中 且位置在主调函数之后,则必须在调用此函数之 前对被调用的函数作声明。

177

void main (void)
{ float a,b, c; float max (float,float); cin>>a>>b; c=max (a,b) ; 函数原型说明

cout<<“The max is”<<c<<endl;
}

float max (float x, float y)
{ float z; z=(x>y)? x : y ; return z; }

函数定义

定义是一个完整的函数单位, 而原型说明仅仅是说明函数的 返回值及形参的类型。 178

void main(void)

i

x 5

j 7 6

{ int i=2, x=5, j=7; void fun(int,int); 2 fun ( j, 6); cout<<i<<‘\t’<< j<<‘\t’<< x<<endl; } void fun ( int i, int j) { int x=7; cout<<i<<‘\t’<< j<<‘\t’<<x<<endl;

7 x

7 i

6 j

}

输出: 7
2

6
7

7
5
179

void main(void ) { int x=2,y=3, z=0;void add(int,int,int); cout<<“(1) x=“<<x<<“ y=“<<y<<“ z=“<<z<<endl; add (x, y, z); cout<< (“(3) x=“<<x<<“ y=“<<y<<“ z=“<<z<<endl;

}
void add ( int x, int y, int z) { z=x+y; x=x*x; y=y*y;

x
2

y
3

z
0

cout<<(“(2) x=“<<x<<“ y=“<<y<<“ z=“<<z<<endl;
} (1) x=2 y=3 z=0 (2) x=4 y=9 z=5 (3) x=2 y=3 z=0 2 x 4 3 y 9 0 z 5
180

编写程序,分别计算下列函数的值(x从键盘输入)

f1 ?x? ? 3x ? 2x ?1
3 2

f 2 ?x ? ? x ? 2 x ? 1
2

181

float f1(float x)
{ float y; y=3*x*x*x+2*x*x-1; return y; }

void main(void)
{

float x, y;
cin>>x; y=f1(x); cout<<“x=“<<x<<“ , y=“<<y<<endl;
182

编写程序,分别计算下列函数的值(x从键盘输入)

1 1 1 s ? 1 ? ? 2 ? 3 ? ? ?x ? 1? x x x
当最后一项小于0.00001时,累加结束。

183

float fun(float x)

{ float s=1, t=1;
do { t=t/x; s+=t;

void main(void)
{ float x; cin>>x;

}while (t>0.00001); cout<<“s=“<<fun(x)<<endl; return s; } }

184

计算100~200之间的素数,用函数prime( )判断一个数是 否是素数,若是该函数返回1,否则返回0。 int prime(int x) { for(int i=2;i<x/2;i++) if(x%i==0) return 0; return 1; } void main(void)
{ for(int i=100;i<=200; i++) if(prime(i)==1)

cout<<i<<‘\t’;
}
185

计算输入两个数的最大公约数
int gys(int a, int b) { int r; if(a<b){r=a; a=b; b=r;} while(r=a%b) { a=b; b=r;} return b; } void main(void)

{ int x, y;
cin>>x>>y;

cout<<gys(x,y)<<endl;
}
186

计算输入三个数的最大公约数
int gys(int a, int b,int c)

{ int r;
if(a<b){r=a; a=b; b=r;} r=r>c?r:c; for(int i=r-1;i>=1;i--)

void main(void) { int x, y, z; cin>>x>>y>>z; cout<<gys(x,y,z)<<endl; }

{ if(a%i==0&&b%i==0&&c%i==0)

break;
} return i; }
187

写一个函数验证哥德巴赫猜想;一个不小于6的偶 数可以表示为两个素数之和,如6=3+3, 8=3+5, 10=3+7……。在主函数中输入一个不小于6的偶数 n,函数中输出以下形式的结果∶ 34=3+31

188

函数的嵌套调用 C语言中,所有函数都是平行独立的,无主次、相 互包含之分。函数可以嵌套调用,不可嵌套定义。
int max ( int a, int b) { int c; 嵌套定义 int min ( int a, int b) { return ( a<b? a: b); int min ( int a, int b) { return ( a<b? a: b); } 平行定义

int max ( int a, int b)
{ int c; c=min(a,b); 嵌套调用

}
c=min(a,b);

return ( a>b? a : b);
} }

return ( a>b? a : b);
189

在main函数中调用a函数,在a函数中又调用b函数。

main 函数 ⑴ 调用 a 函数 (9) 结束 (8) (2)

a 函数 (3) 调用 b 函数 (7) (6) (4)

b 函数

(5)

190

f (k , n) ? 1 ? 2 ? 3 ? ....? n
k k k
int power(int m,int n) //m^n { int i,product=m; for(i=1;i<n;i++) 平行定义 product=product*m; return product; 平行定义 } int sum_of_power(int k,int n) //n^k的累加和 { int i,sum=0; for(i=1;i<=n;i++) 嵌套调用 sum+=power(i,k); return sum; } void main(void) { int k,m; 嵌套调用 cin>>k>>m; cout<<"f("<<k<<","<<m<<")="<<sum_of_power(k,m)<<endl; //m^k的累加和 }

k

191

函数的递归调用 在调用一个函数的过程中直接或间接地调用函数本身,称 为函数的递归调用。 int f(int x) { int y,z ; int f1(int x) { int y,z ; int f2(int t) { int a, c ;

.....
z=f(y);

.....
z=f2(y);

.....
c=f1(a);

....
return (2*z); }

....
return (2*z);

....
return (3+c);

}

}
192

有5个人坐在一起,问第5个人多少岁,他说比第4个人大2岁。问第4 个人多少岁,他说比第3个人大2岁。问第3个人多少岁,他说比第2 个人大2岁。问第2个人多少岁,他说比第1个人大2岁。问第1个人多 少岁,他说是10岁。请问第5个人多大? 10 n=1 age(5)=age(4)+2 age(n)= 必须有递归结束条件 age(4)=age(3)+2 age(n-1)+2 n>1 age(3)=age(2)+2
age(2)=age(1)+2 age(1)=10 void main(void) { int age(int); int age ( int n ) { int c; c=age(n-1)+2; int age ( int n )

{ int c;
if (n= =1) c=10; else

cout<<age(5)<<endl;
} }

return c;
}

c=age(n-1)+2;
return c;
193

void main(void) { int age(int);

int age ( int n )
{ int c; if (n= =1) c=10;

cout<<age(5)<<endl;
} age (5) n=5 age (4) n=4 }

else
return c;

c=age(n-1)+2;

age (3) n=3

age (2) n=2

age (1) n=1

c=age (4)+2
return c

c=age (3)+2
return c

c=age (2)+2 c=age (1)+2
return c return c

c=10
return c

c=18

c=16

c=14

c=12

虽然算法一致,但n不同,c不同,在内存中每一层函数变 194 量所在的内存单元均不相同。必须有递归终止条件。

用递归方法求n!
n!=

1

n=0,1

float fac (int n) { float y; if ((n= =0)|| (n= =1) y=1; else y=n*fac(n-1); return y; } fac (5)
n=5 y=5*fac (4) return y y=120

n*(n-1)! n>1 void main (void) { float y; int n; cout<<“Input n:\n”; cin>>n ; cout<<n<<“!=”<<fac(n)<<endl; }

fac (4)
n=4 y=4*fac (3) return y y=24

fac (3)

fac (2)

fac (1)
n=1 y=1 return y
195

n=3 n=2 y=3*fac (2) y=2*fac (1) return y y=6 return y y=2

int sub(int); void main (void) { int i=5; cout<<sub(i)<<endl; }
sub (5) n=5 a=5+sub (4) return a sub (4) n=4 a=4+sub (3) return a

int sub (int n ) { int a; if (n= =1) return 1; a=n+sub(n-1); return a; }
sub (3) n=3 sub (2) n=2 sub (1) n=1 a=1 return a

a=3+sub (2) a=2+sub (1) return a return a

a=15

a=10

a=6

a=3

算法相同,层层调用,每层函数的变量所占内存单元不同。 196

4 f(1234) f(n/10)

void f(int n ) void main (void) {if(n= =0) return; { int i=5; else {cout<<n%10; 43211234 cin>>i; f(n/10); f(i); 输入:1234 cout<<n%10; return; } }} 1
3 f (123) 2 f(12) f(1) f (n/10) return f(0) n=0

cout<<n%10 cout<<n%10 cout<<n%10 cout<<n%10 f(n/10) f(n/10)

cout<<n%10 cout<<n%10 cout<<n%10 cout<<n%10

return
4

return
3

return
2

return
1
197

void recur(char c)

void main(void)

{ cout<<c;
if(c<‘5’) recur(c+1); cout<<c;

{ recur(‘0’);
}

} 输出:012345543210

198

void f(int n) { if(n>=10) f(n/10); cout<<n<<endl; }

1
12

123
1234

void main(void)
{ f(12345); }

12345

199

作用域和存储类 作用域是指程序中所说明的标识符在哪一个区间 内有效,即在哪一个区间内可以使用或引用该标 识符。在C++中,作用域共分为五类:块作用域、 文件作用域、函数原型作用域、函数作用域和类 的作用域。

200

块作用域
我们把用花括号括起来的一部分程序称为一个块。 在块内说明的标识符,只能在该块内引用,即其 作用域在该块内,开始于标识符的说明处,结束 于块的结尾处。 在一个函数内部定义的变量或在一个块中定义的 变量称为局部变量。

201

在函数内或复合语句内部定义的变量,其作用域是 从定义的位置起到函数体或复合语句的结束。形参 也是局部变量。
float f1( int a) void main(void ) a,b,c有效

{ int b,c;
..... }

{ int m, n;
..... } m,n有效

float f2( int x, int y) { int i, j;

.....
}

x,y,i,j 有效
202

主函数main中定义的变量,也只在主函数中有效, 同样属于局部变量。 不同的函数可以使用相同名字的局部变量,它们在 内存中分属不同的存储区间,互不干扰。 void main(void)
{ int x=10; { int x=20; cout<<x<<endl; } cout<<x<<endl; } 10
203

10 定义变量既是在 x

内存中开辟区间
20 x

20

注意:
具有块作用域的标识符在其作用域内,将屏 蔽其作用块包含本块的同名标识符,即

变量名相同,局部更优先。

204

void main(void) { int a=2, b=3, c=5;

2 a

3 b 2 b

-1 5

c

cout<<a<<‘\t’<<b<<‘\t’<<c<<endl; 7 { int a, b=2; a a=b+c;
cout<<a<<‘\t’<<b<<‘\t’<<c<<endl; 2 3 } 7 2 c=a-b; 2 3 cout<<a<<‘\t’<<b<<‘\t’<<c<<endl; }

5 5 -1

205

void main(void) { int a=1,b=2,c=3;

++a;
c+=++b; { int b=4, c;

c=b*3;
a+=c;

a=2 b=3, c=6 b=4 c=12
a=14

cout<<“first:”<<a<<‘\t’<<b<<‘\t’<<c<<endl; a=14,b=4,c=12 a=26 a=26,b=4,c=12 cout<<“second:”<<a<<‘\t’<<b<<‘\t’<<c<<endl; a=26,b=3,c=6 cout<<“third:”<<a<<‘\t’<<b<<‘\t’<<c<<endl; }
206

a+=c;

}

文件作用域 在函数外定义的变量称为全局变量。 全局变量的作用域称为文件作用域,即在整个文 件中都是可以访问的。 其缺省的作用范围是:从定义全局变量的位置开始 到该源程序文件结束。 当在块作用域内的变量与全局变量同名时,局部 变量优先。
207

int p=1, q=5; float f1( int a)

全局变量 a,b,c有效 p,q有效

{ int b,c;
..... } char c1,c2; main( ) 局部变量

{ int m, n;
..... }

m,n有效

c1,c2有效

全局变量增加了函数间数据联系的渠道,在函数调 用时可以得到多于一个的返回值。 208

int min; 全局变量 0 1 int max (int x, int y) min { int z; min=(x<y)?x : y; min 在main( )和max( )中均有效, 1 4 4 z=(x>y)? x : y ; 在内存中有唯一的存储空间。 x y z return z; 函数值为4 } void main (void) 1 { int a,b,c; a cin>>a>>b; c=max (a , b) ; cout<<“The max is”<<c<<endl; cout<<“ The min is”<<min<<endl; } 4

b

4 c

The max is 4

The min is 1
209

在同一个源文件中,外部变量与局部变量同名,则在局部 变量的作用范围内,外部变量不起作用。 int a=3, b=5;
int max(int a, int b) { int c;
a 3 a 8 b 5

c=a>b? a:b;
return c;

max (8,5)

}
void main(void) { int a=8; cout<<max(a,b)<<endl; }
8 5

a

b
210

输出:8

int x;

void cude(void) { x=x*x*x ; x为0
} void main (void) { int x=5; x=5; cude ( ); cout<<x<<endl; }

输出: 125

输出: 5

211

在块作用域内可通过作用域运算符“::”来引用与局部 变量同名的全局变量。 #include <iostream.h> ::i=104 int i= 100; void main(void) i=18 { j=108 int i , j=50; i=18; //访问局部变量i ::i= ::i+4; //访问全部变量i j= ::i+i; //访问全部变量i和局部变量j cout<<”::i=”<<::i<<’\n’; cout<<”i=”<<i<<’\n’; cout<<”j=”<<j<<’\n’; 212 }

函数原型作用域 在函数原型的参数表中说明的标识符所具有的作 用域称为函数原型作用域,它从其说明处开始, 到函数原型说明的结束处结束。

float tt(int x , float y); //函数tt的原型说明
由于所说明的标识符与该函数的定义及调用无关,

所以,可以在函数原型说明中只作参数的类型说
明,而省略参量名。

float tt (int , float);

213

int i=0; int workover(int i) { i=(i%i)*((i*i)/(2*i)+4);

void main(void)
{ int i=5;

rest(i/2);
cout<<“i=“<<i<<endl; rest(i=i/2); cout<<“i=“<<i<<endl; i= rest(i/2);

cout<<“i=“<<i<<endl; i=5 return i; i=2 } i=5 i=0 int rest (int i) i=5 { i=i<2?5:0;
return i; } }

cout<<“i=“<<i<<endl;
workover(i)

cout<<“i=“<<i<<endl;
214

存储类
外存 程序 内存

程 序 区
静态存储区 动态存储区

存放程 序代码

存放变量

需要区分变量的存储类型
215

全局变量 作用域 生存期

动态存储变量

局部变量

静态存储变量

静态存储:在文件运行期间有固定的存储空间,直到文件 运行结束。 动态存储:在程序运行期间根据需要分配存储空间,函数 结束后立即释放空间。若一个函数在程序中被调用两次, 则每次分配的单元有可能不同。 程序区 静态存储区 动态存储区

全局变量

静态局部变量
216 动态局部变量

动态变量(auto):默认,存储在动态区

局部变量 的分类

寄存器变量(register):在cpu内部存储
静态局部变量(static):存储在静态区

动态局部变量未被赋值时,其值为随机值。其作用域的函 数或复合语句结束时,空间被程序收回。

程序执行到静态局部变量时,为其在静态区开辟存储空间, 该空间一直被保留,直到程序运行结束。

由于存储在静态区,静态局部变量或全局变量未赋初值时, 系统自动使之为0。 217

int fun(int a) 只赋一次初值 { int c; static int b=3; c=a+ b++; 2 5 3 4 5 5 9 return c; a a b c c } 输出: void main(void) { int x=2, y; 5 2 5 9 y=fun(x); 9 x y cout<<y<<endl; 变量b是静态局部变量,在内存 y=fun(x+3); 一旦开辟空间,就不会释放,空 cout<<y<<endl; 间值一直保留 218 }

int f (int a) { int b=0; static int c=3; b=b+1; c=c+1; return a+b+c; }

只赋一 次初值

i=0

a=2 b=0, b=1 输出:7 c=3, c=4

i=1

a=2 b=0, b=1 输出:8 c=4, c=5 a=2 b=0, b=1 输出:9 c=5, c=6

i=2 7 8 9

void main(void) { int a=2,i; for (i=0;i<3;i++) cout<<f(a)<<endl; }

219

int func (int a, int b)
{ static int m=0, i=2; i+=m+1; m=i+a+b; return m; } void main(void)

func( 4, 1) a=4, b=1 m=0, i=2 i=3

func( 4, 1) a=4, b=1 m=8, i=3 i=3+8+1=12

m=3+4+1=8
输出:8,17 cout<<p<<endl;

m=12+4+1=17

{ int k=4, m=1, p;
p=func(k, m);

p=func(k, m);
}

cout<<p<<endl;
220

int q(int x)
{ int y=1;

static int z=1;
z+=z+y++;

return x+z;
} void main(void) { cout<<q(1)<<‘\t’; cout<<q(2)<<‘\t’; cout<<q(3)<<‘\t’; }
221

4

9

18

全局变量的存储方式(extern

static)

全局变量是在函数的外部定义的,编译时分配在静态存储 区,如果未赋初值,其值为0。 1、extern 存储类别 全局变量的默认方式,当在一个文件中要引用另一个文件 中的全局变量或在全局变量定义之前要引用它时,可用 extern作说明,相当于扩大全局变量的作用域。 2、静态(static)存储类别

它仅能在本文件中引用,即使在其它文件中用extern说明 也不能使用。相当于限制了全局变量的作用域范围。
222

程序的作用是:给定b的值,输入a和m,求a×b和am的值。
文件file1.c中的内容为: 外部全局 int a; 变量定义 void main(void) { extern int power (int); int b=3, c, d, m; cin>>a>>m;

文件file2.c中的内容为:
外部全局 变量说明 extern int a; int power (int n ) { int i, y=1;

c=a*b;

引用文件外定 义的全局变量

for (i=1; i<=n; i++) y*=a; return y;

cout<<a<<“*”<<b<<“=“<<c<<endl;

d= power(m);
cout<<a<<“**”<<m<<“=“<<d<<en

}
223

静态局部变量:static 在函数内部定义,存储在静态存储 区,与auto对应,在别的函数中不能引用。 全局静态变量:static 在函数外部定义,只限在本文件中 使用,与extern对应。 当变量名相同致使作用域相重时,起作用的是最近说明的 那个变量。

外部 extern
全局变量 局部变量

自动
寄存器

auto
register

静态 static

静态

static
224

内联函数

主调函数

被调函数

调用处

主调函数

内联函数 被调函数

调用处

将被调函数体的代

码直接插到调用处
225

内联函数的实质是用存储空间(使用更 多的存储空间)来换取时间(减少执行时

间).
内联函数的定义方法是,在函数定义时, 在函数的类型前增加修饰词inline。
226

inline int max (int x, int y) { int z;

z=(x>y)? x : y ;
return z;

}
void main (void ) { int a,b,c; cin>>a>>b; c=max (a+b , a*b) ; cout<<“The max is”<<c<<endl; }
227

使用内联函数时应注意以下几点:

1、C++中,除在函数体内含有循环,switch分支和复杂嵌 套的if语句外,所有的函数均可定义为内联函数。
2、内联函数也要定义在前,调用在后。形参与实参之间 的关系与一般的函数相同。

3、对于用户指定的内联函数,编译器是否作为内联函数 来处理由编译器自行决定。说明内联函数时,只是请求编 译器当出现这种函数调用时,作为内联函数的扩展来实现, 而不是命令编译器要这样去做。

4、正如前面所述,内联函数的实质是采用空间换取时间, 即可加速程序的执行,当出现多次调用同一内联函数时, 程序本身占用的空间将有所增加。如上例中,内联函数仅 调用一次时,并不增加程序占用的存储间。 228

具有缺省参数值和参数个数可变的函数 在C++中定义函数时,允许给参数指定一个缺 省的值。在调用函数时,若明确给出了这种实 参的值,则使用相应实参的值;若没有给出相 应的实参,则使用缺省的值。(举例说明)

229

int fac(int n=2) { int t=1; 输出:720 输出:2

for(int i=1;i<=n;i++)
t=t*i; return t; } void main(void)

{
) <<endl; cout<< fac( fac(6) }
230

int area(int long=4 , int width=2) { return long* width;

}

48
void main(void )
{ int a=8, b=6; cout<< area(a,b) <<endl; cout<< area(a) <<endl; cout<< area( ) <<endl; }
231

16
8

使用具有缺省参数的函数时,应注意以下几点: 1.不可以靠左边缺省 int area(int long , int width=2)

int area(int long =4, int width)

错误!

2.函数原型说明时可以不加变量名

float v(float,float=10,float=20);
3.只能在前面定义一次缺省值,即原型说明时定义 了缺省值,后面函数的定义不可有缺省值。
232

参数个数可变的函数

到目前为止,在定义函数时,都明确规定了函数的参数个数及类型。 在调用函数时,实参的个数必须与形参相同。在调用具有缺省参数 值的函数时,本质上,实参的个数与形参的个数仍是相同的,由于 参数具有缺省值,因此,在调用时可省略。在某些应用中,在定义 函数时,并不能确定函数的参数个数,参数的个数在调时才能确定。 在C++中允许定义参数个数可变的函数。

233

首先,必须包含头文件“stdarg.h”,因为要用到里面的三个库函 数 va_start( )、va_arg( )和va_end( )。 其次,要说明一个va_list类型的变量。va_list与int,float类同, 它是C++系统预定义的一个数据类型(非float),只有通过这种类 型的变量才能从实际参数表中取出可变有参数。如:va_list ap;

a

b

...

(可变参数)

ap (va_list)变量

va_start(ap,b):初始化 va_arg(ap,int):依次取参数 va_end(ap):正确结束
234

va_start():有两个参数,va_start(ap,b); b即为可变参数前的最后一个 确定的参数。

va_arg():有两个参数,va_arg(ap,int) int即为可变参数的数据类型名。 int temp; temp=va_arg(ap,int); va_end():完成收尾工作。va_end(ap); 在调用参数个数可变的函数时,必定有一个参数指明可变参数的个 数或总的实参个数。如第一个参数值为总的实际参数的个数。

235

使用参数数目可变的函数时要注意以下几点:

1 、在定义函数时,固定参数部分必须放在参数表的前面, 可变参数在后面,并用省略号“...”表示可变参数。在函数调用时, 可以没有可变的参数。

2、必须使用函数va_start()来初始化可变参数,为取第一个可 变的参数作好准备工作;使用函数va_arg()依次取各个可变的参数值; 最后用函数va_end()做好结束工作,以便能正确地返回。 3 、在调用参数个数可变的函数时,必定有一个参数指明可 变参数的个数或总的实参个数。

236

函数的重载 所谓函数的重载是指完成不同功能的函数可以具 有相同的函数名。 C++的编译器是根据函数的实参来确定应该调用 哪一个函数的。
int fun(int a, int b) void main(void) { cout<<fun(3,5)<<endl; cout<<fun(5)<<endl; }

{ return a+b; }
int fun (int a) { return a*a; }

8 25
237

1 、定义的重载函数必须具有不同的参数个数, 或不同的参数类型。只有这样编译系统才有可能 根据不同的参数去调用不同的重载函数。 2、仅返回值不同时,不能定义为重载函数。

即仅函数的类型不同,不能定义为重载函数
int fun(int a, int b)
{ return a+b; }

void main(void)
{ cout<<fun(3,5)<<endl; cout<<fun(3,5)<<endl; }
238

float fun (int a,int b)
{ return (float) a*a; }

double sin(double x1,double x2)
{ { { return x1*x2;} return a+x;} double x; cin>>x;
sin(x,x)

double sin(double x,int a)
sin(x,10)

void main(void)

不同的参 数类型

cout<<sin(x)<<endl;;
cout<<sin(x,x)<<endl;

cout<<sin(x,10)<<endl;
}
239

int add(int a,int b,int c) { return a+b+c; }

int add(int a,int b) { return a+b; }

不同的参 数个数

void main(void)

{

cout<<"3+5="<<add(3,5)<<endl;
cout<<"3+5+8="<<add(3,5,8)<<endl;

}
240

编译预处理 高级语言编译过程
库文件 (各种函数) 可执行文件 (二进制文件) 连接 *.EXE

编译预处理
源程序

目标文件 编译

(文本文件)
*.CPP

(二进制文件)
*.OBJ

C语言提供的编译预处理的功能有以下三种:
宏定义 文件包含 条件编译
241

宏定义
不带参数的宏定义

用一个指定的标识符(即名字)来代表一个字符串, 以后凡在程序中碰到这个标识符的地方都用字符串 来代替。

这个标识符称为宏名,编译前的替代过程称为 “宏展开”。 # define 标识符 字符串
242

#define PRICE 30 void main(void) { int num, total; /*定义变量*/ num=10; /*变量赋值*/
编译前用30替代

total=num*PRICE;

cout<<"total=“<<total<<endl;
} 编译程序将宏定义的内容认为是字符串,没有任 243 何实际的物理意义。

注意: 1、宏展开只是一个简单的“物理”替换,不做语 法检查,不是一个语句,其后不加分号“;”
2、#define命令出现在函数的外面,其有效范围为 定义处至本源文件结束。可以用# undef命令终止宏 定义的作用域。
#define G 9.8 {.....} # undef G void main(void )

int max(int a,int b)
{...... }
244

3、对程序中用双引号括起来的字符串内容,即使 与宏名相同,也不进行置换。 4、在进行宏定义中,可以用已定义的宏名,进行 层层置换。

245

# define R 3.0 # define PI 3.1415926 # define L 2*PI*R 层层置换

# define S PI*R*R
void main(void)

层层置换

{ cout<<“L=“<<L<<“ S=”<<S<< endl; 不置换 不置换 }
246

带参数的宏定义
#define
#define

宏名(参数表)
S(a, b) 形式参数

字符串
a*b

.... 宏定义

定义的宏

float x, y,area; cin>>x>>y;

实参代入后还原

area=S(x, y); /* area=x*y; */ 宏调用 实际参数
247

按#define命令行中指定的字符串从左至右进行置换 宏名,字符串中的形参以相应的实参代替,字符串 中的非形参字符保持不变。

#define S(a, b) a*b

机械地将实参代入 宏定义的形参形式

area=S(3,2)

3*2
S(3,2)等同于 3*2
248

S(a,b)等同于 a*b

#define PI 3.1415926 #define S(r) PI*r*r void main(void)

S(r)
S(a)

PI*r*r
PI*a*a

{ float a, area, b;
a=3.6; b=4.0; PI*a*a area=S(a); 编译前机械替换, 实参形参一一对应

cout<<“r=“<<a<<“\narea=”<<area<<en 249 dl;

#define PI 3.1415926

S(r)

PI*r*r

PI*a+b*a+b #define S(r) PI*r*r S(a+b) S(a+b) PI*(a+b)*(a+b) void main(void) 错误 编译前机械替换, { float a, area, b; 实参形参一一对应 a=1; b=2; 宏展开时实参不运 area=S(a+b); 算,不作语法检查
cout<<“r=“<<a<<“\narea=”<<area<<en #define S(r) PI*(r)*(r) 250 dl;

定义宏时在宏名与带参数的括弧间不能有空格。
#define S_ (r) P*r*r

带参数的宏与函数调用的区别 相同:有实参、形参,代入调用。
不同之处: 1、函数调用先求表达式的值,然后代入形参,而宏只是机 械替换。 2、函数调用时形参、实参进行类型定义,而宏不需要,只 是作为字符串替代。 3、函数调用是在运行程序时进行的,其目标代码短,但程 序执行时间长。而宏调用是在编译之前完成的,运行时已 将代码替换进程序中,目标代码长,执行时间稍快。 一般用宏表示实时的、短小的表达式。
251

#define A 3 #define B(a) ((A+1)*a) 执行 x=3*(A+B(7)); 后, x的值为:

93

#define neg(x) ((-x)+1)
int neg( int x) {return x+1; }

编译前机械替换, 实参形参一一对应 y=0

void main(void)
{ int y;

((-1)+1) y=neg(1);
cout<<“y=“<<y<<endl; }
252

文件包含 一个源文件可以将另外一个源文件的全部内容包含进来, 即将另外的文件包含到本文件之中。

# include “文件名”
file1.cpp
#include “file2.cpp” file2.cpp B

file1.cp p
B

A

A
253

注意: 1、文件名是C的源文件名,是文本文件,后缀名可 以任选。*.cpp *.h 2、一个#include语句只能指定一个被包含文件。

3、文件名用双引号或尖括号括起来。
4、包含后所有源文件编译为一个可执行文件。
254

条件编译 C语言允许有选择地对程序的某一部分进行编译。 也就是对一部分源程序指定编译条件。
源程序

可以将部分源程序 不转换为机器码

255

条件编译有以下几种形式:
1、 # ifdef 标识符

标识符

# define DEBUG
...... # ifdef DEBUG cout<<x<<‘\t’<<y<<endl; # endif

程序段1 # else 程序段2 # end if

当标识符已被定义过(用#define 定义),则对程序段1进行编译, 否则编译程序段2.
256

2、 # ifndef

标识符

# define DEBUG ...... # ifndef DEBUG cout<<x<<‘\t’<<y<<endl; # endif

程序段1 # else 程序段2 # endif

与形式1相反,当标识符没有被 调试完后加#define 定义过(用#define定义),则对 DEBUG,则不输出 程序段1进行编译,否则编译程 调试信息。 序段2。
257

3、 # if

表达式 程序段1

# define DEBUG ...... # if DEBUG

1

# else 程序段2 # endif

cout<<x<<‘\t’<<y<<endl; # endif

当表达式为真(非零), 编译程序段1,表达式 为零,编译程序段2。

调试完后改为 #define DEBUG 0,则不输出调试信息。

采用条件编译后,可以使机器代码程序缩短。
258

以下程序的运行结果是:
#define DEBUG

void main(void)
{ int a=14, b=15, c;

c=a/b;
# ifdef DEBUG cout<<“a=“<<oct<<a<<“ b=“<<b<<endl; # endif cout<<“c=“ <<dec<<c<<endl; 输出: a=16, b=17c=0
259

程序的多文件组织 而在设计一个功能复杂的大程序时,为了便于程序的设计和调试, 通常将程序分成若干个模块,把实现一个模块的程序或数据放在 一个文件中。当一个完整的程序被存放在多于一个文件中时,称 为程序的多文件组织。

260

内部函数和外部函数 内部函数:函数只限于在本文件中调用,其它文件不能调 用,用static 定义该函数。
static float fac( int n) { ...... }

外部函数:函数的默认形式,可以被其它文件调用,用 extern 定义该函数。调用时,在文件中用extern 说明。
void main(void) { extern enter_string( ); char str[80]; enter_string(str); .......... }

说明外部函数

261

补充算法 方程求解
1、牛顿切线法
只有为数不多的方程有精确解,一般都是用迭代方法近似 求方程的解。方程f(x)=0的实数解实际上是曲线f (x)在x轴 y 上交点的值。
f(x)

x0

x
262

1、任选一x值x1,在y1=f(x1)处做切线与x轴相交于x2处。
2、若|x2-x1|或|f(x2)|小于指定的精度,则令x1=x2,继续做

1。当其满足所需的精度时,x2就是方程的近似解。
根据已知点求其切线的公式为:
f ( x1) x 2 ? x1 ? f ?( x1)
y x2 f(x1) f(x)

这就是牛顿切线法。 牛顿切线法收敛快, 适用性强,缺陷是必 须求出方程的导数。

x1
x2 x1 x

x0

263

已知方程为f(x)=x*x-a时,用牛顿切线法求方程的解。给定 初值x0,精度10-6,算法编程如下。 cin>>x1; //从键盘输入x0
do 上一循环的新值成为本次循环的旧值 旧值算本次循环的新值

{ x0=x1;

x1=x0-(x0*x0-a)/(2*x0) ; // } while (fabs(x1-x0)>=1e-6) ; cout>>”x=”>>x1>>endl;

f ( x 0) x1 ? x 0 ? f ?( x 0)

264

2、弦截法
x1 * f ( x 2) ? x 2 * f ( x1) x0 ? f ( x 2) ? f ( x1)

y x0

f(x1)

f(x)

x2

x2

x0

x
f(x2)

x1

x

1、在x轴上取两点x1和x2, 要确保x1与x2之间有且只有方程唯一的解。 2、x1与x2分别与f(x)相交于y1=f(x1)、y2=f(x2)。 3、做直线通过y1、y2与x轴交于x0点。 4、若|f(x0)|满足给定的精度,则x0即是方程的解,否则,若 f(x0)*f(x1)<0,则方程的解应在x1与x0之间,令x2=x0,继续做2。同 理,若f(x0)*f(x1)>0,则方程的解应在x2与x0之间,令x1=x0,继续 265 做2 ,直至满足精度为止。

x3-5x2+16x-80=0 void main(void ) x1 * f ( x 2) ? x 2 * f ( x1) { float x1,x2, x0, f0, f1, f2; x0 ? f ( x 2) ? f ( x1) do #include <math.h> { cout<<“Input x1, x2\n”; 输入x,输出f(x) float f (float x) cin>>x1>>x2; {return x*x*x-5*x*x+16*x-80; f1=f(x1); f2=f(x2); 判断输入是否合法 } while (f1*f2>0); } do 输入x1,x2,输出x0 { x0=xpoint(x1,x2); float xpoint(float x1,float x2) f0=f(x0); { float x0; if ((f0*f1) >0) { x1=x0;f1=f0;} x0=(x1*f(x2)-x2*f(x1))/(f(x2)-f(x1)); else { x2=x0; f2=f0;} return x0; }while (fabs(f0)>=0.0001); } cout<<”x=”<< x0<<endl; 266 } 用两分法求方程的根。

3、两分法 x0=(x1+x2)/2
x2 x2 x0

y
f(x) x0

x

x1

x

1、在x轴上取两点x1和x2, 要确保x1与x2之间有且只有方程 唯一的解。 2、求出x1,x2的中点x0。 3、若|f(x0)|满足给定的精度,则x0即是方程的解,否则, 若f(x0)*f(x1)<0,则方程的解应在x1与x0之间,令x2=x0, 继续做2。同理,若f(x0)*f(x1)>0,则方程的解应在x2与x0 267 之间,令x1=x0,继续做2 ,直至满足精度为止。

x3-5x2+16x-80=0 void main(void ) { float x1,x2, x0, f0, f1, f2; x0=(x1+x2)/2 do #include <math.h> { cout<<“Input x1, x2\n”; 输入x,输出f(x) float f (float x) cin>>x1>>x2; {return x*x*x-5*x*x+16*x-80; f1=f(x1); f2=f(x2); } while (f1*f2>0); } 判断输入是否合法 do { x0=(x1+x2)/2; f0=f(x0); 求x1与x2的中点 if ((f0*f1) >0){ x1=x0;f1=f0;} else { x2=x0;f2=f0;} }while (fabs(f0)>=0.0001); cout<<”x=”<< x0<<endl; 268 } 用两分法求方程的根。

int q(int x)
{ int y=1;

static int z=1;
z+=z+y++;

return x+z;
} void main(void) { cout<<q(1)<<‘\t’; cout<<q(2)<<‘\t’; cout<<q(3)<<‘\t’; }
269

4

9

18

下面函数pi的功能是:根据以下公式,返回满足精度(0.0005)要求 的π的值,请填空。

? 1 12 123 1234 将后一项除 ? 1? ? ? ? ?? 以前一项, 2 3 35 357 3579
找规律
main( )

输入精度 #include “math.h” 输出π
double pi(double eps)

{ double x; { double s, t; int n; for ( t=1,s=0,n=1 ___________; t>eps; n++) cout<<“\nInput a precision:”; { s+=t; cin>>x; t=n*t/(2*n+1); cout<< “π=“<<pi(x); } } return ___________ ; 2*s }
270

void f(int n) { if(n>=10) f(n/10); cout<<n<<endl; }

1
12

123
1234

void main(void)
{ f(12345); }

12345

271

void main(void) { char s; cin.get(s); 输入:2347<CR> while(s!=‘\n’) { switch(s-’2’) 545455555657 { case 0: case 1: cout<<s+4; case 2: cout<<s+4;break; case 3: cout<<s+3; default: cout<<s+2; break; } cin.get(s); }cout<<endl; }

272

第六章

数组

273

一维数组的定义和引用
数组是同一类型的一组值(10个 char 或15个 int) ,在内存中顺序存放。 整个数组共用一个名字,而其中的每一项又称 为一个元素。 一、定义方式:

类型说明符
定义类型

数组名[常量表达式];

元素个数

int

a[4]; // 表明a数组由4个int型元素组成
数组名称
274

必须是常数

int

a[4]; // 表明a数组由4个int型元素组成

其元素分别为:a[0], a[1], a[2], a[3]
其序号从0开始。若存放首地址为2000H,则在 内存中为:
2000H a[0] 2004H a[1] 2008H a[2] 200CH a[3] 2010H

C++不允许对数组的大小作动态的定义,即数组的 大小不能是变量,必须是常量。
275

如果要根据不同的数值改变数组的大小,可 用常量表达式。如: #define SIZE 50 void main(void)

{ int art[SIZE];
...... }
276

二、一维数组元素的引用
数组必须先定义,具体引用时(赋值、运算、输出)其元 素等同于变量。 a void main(void ) i=0, a[0]=0 0 a[0] 定义 1 a[1] { int i, a[10]; i=1, a[1]=1

for ( i=0; i<10; i++) 赋值
a[i]=i;

i=2, a[2]=2 i=9, a[9]=9

for ( i=9; i>=0 ; i--)
cout<<a[i]<<‘\t输出 ’;

cout<<“\n”; 输出:9_ } _8_ _7_ _6_ _5_ _4_ _3_ _2_ _1_ _0

2 3 4 5 6 7 8 9
277

a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9]

三、一维数组的初始化
在定义数组的同时给数组元素赋值。

注意:
1、对数组中的一部分元素列举初值,未赋值的部 分是0。 int a[10]= {0,1, 2, 3, 4, 5}; int a[10]= {0,1, 2, 3, 4, 5, 0, 0, 0, 0}; 2、不能给数组整体赋值,只能一个一个地赋值。 int a[10]= {0,1,2,.....,9}; 非法
278

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

3、可以用 int a[ ]= {0,1, 2, 3, 4, 5, 6, 7, 8, 9}; 给数 组赋值,编译器会自动计算出内的元素项数,并将 数组定义为该长度。 4、用局部static 或全局定义的数组不赋初值,系统 均默认其为‘\0’。 static int a[10];(即存储在静态数据区中的数组其 元素默认为0)

a

0 0 0 0 0 0 0 0 0 0

数组在内存中顺序存放,第一个元素位于地址的最 低端。 279

求Fibonacci数列:1,1,2,3,5,8,......的前20个数,即 F1=1 (n=1) F2=1 (n=2) Fn=Fn-1+Fn-2 (n>=3)
f[0] f[1] f[2] f[3] f[4] f[5] f[5] f[6] f[7] .... 1 1 2 3 5 8 13 21

f [i]=f [i-1]+f [i-2]
void main (void)
{ int i; int f [20]={1,1}; for ( i=0; i<20; i++) { if (i%5= =0) cout<<“\n”; cout<<f [i]<<‘\t’; }
280

for (i=2 ; i<20 ; i++ )
f [i]=f [i-1]+f [i-2]; }

下面程序的运行结果是:
void main(void)

{ int a[6], i;
for (i=1; i<6; i++)

{ a[i]=9*(i-2+4*(i>3))%5 ;
cout<<a[i]<<‘\t’; } }

a[0] a[1] a[2] a[3] a[4] a[5] 4 4 3 随机 -4 0

i 1 a[i] -4

2 0

3 4

4 4

5 3

输出:-4 0 4 4 3
281

排序算法 用起泡法对6个数排序(由小到大)

将相邻的两个数两两比较,将小的调到前头。
9 8 8 8 8 8 8 5 5 5 5 5 4 4 4

8 5 4 2
0

9 5 4 2
0

5 9 4 2

5 4 9 2

5 4 2 9
0

5 4 2 0
9

5 8 4 4 2 2 0 0
9 9

4 8 2 0
9

4 2 8 0

4 3 0 8

4 3 0 8

5 3 0 8

3 5 0 8

3 0 5 8
9

0 0

9 9

9 9 9

第一趟 循环5次

第二趟
循环4次

第三趟
循环282 3次

4 3 3 3 0 5 8 4 0 5 8 0 4 5 8

3 0 4 5 8 9

0 3 4 5 8 9

总结:

趟数 次数

n 共有6个数 1 2 3 4 5 j(1~n-1) 5 4 3 2 1 n-j

9 9 9
第四趟 循环2次

第五趟 循环1次

for (j=1; j<=n-1; j++) for (i=1; i<=n-j ; i++) { if (a[i]>a[i+1]) { t=a[i]; a[i]=a[i+1]; a[i+1]=t; } 283 }

一般,元素的序号从0开始,因此,程序可以变动如下:

for (j=0; j<n-1; j++) for (i=0; i<n-1-j; i++) { if (a[i]>a[i+1]) { t=a[i]; a[i]=a[i+1]; a[i+1]=t;

}
}
284

二维数组的定义和引用
一、定义方式: 类型说明符 数组名[常量表达式][常量表达式];
行数 列数

int
定义类型

a[3][4];
数组名

表明a数组由3×4个int型元素组成
其元素分别为:a[0][0], a[0][1], a[0][2], a[0][3],

a[1][0], a[1][1], a[1][2], a[1][3],
a[2][0], a[2][1], a[2][2], a[2][3]
285

其元素分别为:a[0][0], a[0][1], a[0][2], a[0][3], a[1][0], a[1][1], a[1][2], a[1][3], a[2][0], a[2][1], a[2][2], a[2][3]

其行列的序号均从0开始。若存放首地址为2000H, 则在内存中为:
2000H 2008H 2010H 2014H 201cH 2020H 2028H 202cH
a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2]a[1][3] a[2][0] a[2][1] a[2][2] a[2][3]

即在内存中,多维数组依然是直线顺序排列的,第 一个元素位于最低地址处。
286

二、二维数组的引用
void main(void)

定义

与一维数组一样,二维数 { int a[2][3], i, j; cout<<“Input 2*3 组必须先定义,其维数必 numbers\n”; 须是常量。具体引用时 for (i=0; i<2; i++) /* 输入 */ (赋值、运算、输出)其 for(j=0; j<3; j++)赋值 元素等同于变量。
cin>>a[i][j];

输入:1 2 3 4 5 6<CR>
输出: _ _ _1_ _ _2_ _ _3

for (i=0; i<2; i++) /* 输出 */ { for(j=0; j<3; j++) cout<<a[i][j]<<‘\t’;

_ _ _4_ _ _5_ _ _6
} }

输出 cout<<“\n” ;
287

三、二维数组的初始化

在定义数组的同时给数组元素赋值。即在编译阶段 给数组所在的内存赋值。 1、分行赋值
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; 2、顺序赋值

int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; //依次赋值
288

3、部分赋值 int a[3][4]={{1},{5},{9}}; /* a[0][0]=1, a[1][0]=5, a[2][0]=9 其余元素为0 */ 1 0 0 0 5 0 0 0 9 0 0 0 int a[3][4]={{0,1},{5}}; /* a[0][0]=0, a[0][1]=1, a[1][0]=5 */
289

0 1 0 0 5 0 0 0 0 0 0 0

4、分行或全部赋值时,可以省略第一维,第二维 不可省。 int a[ ][4]={{1,2},{5,6,7,8,}{9,10,11,12}};
5、不能给数组整体赋值,只能一个一个地赋值。 int a[2][3]={1,2,3,.....,12};

6、用static 定义的数组不赋初值,系统均默认其为 ‘\0’。 static int a[2][3];
290

void main(void)
{ int a[3][3], i, j; for (i=0; i<3; i++) { for (j=0; j<3; j++) if (i= =2)
i=0 a[0][0]=0 a[0][1]=1 a[0][2]=2 i=1 a[1][0]=0 a[1][1]=1 a[1][2]=2

a[i][j]=a[i-1][a[i-1][j]]+1;
else

i=2

a[2][0]=a[1][a[1][0]]+1=a[1][0]+1=1

a[i][j]=j;
} cout<<“\n”; }

a[2][1]=a[1][a[1][1]]+1=a[1][1]+1=2

cout<<a[i][j]<<‘\t’; a[2][2]=a[1][a[1][2]]+1=a[1][2]+1=3
输出:_ _ _0_ _ _1_ _ _ 2 _ _ _0_ _ _1_ _ _ 2 _ _ _1_ _ _2_ _ _ 3

291

有一个3×4的矩阵,要求编程序求出其中值最大 的那个元素的值,以及其所在的行号和列号。

先考虑解此问题的思路。从若干个数中求最大者 的方法很多,我们现在采用“打擂台”算法。如 果有若干人比武,先有一人站在台上,再上去一 人与其交手,败者下台,胜者留台上。第三个人 再上台与在台上者比,同样是败者下台,胜者留 台上。如此比下去直到所有人都上台比过为止。 最后留在台上的就是胜者。
292

程序模拟这个方法,开始时把a[0][0]的 值赋给变量max,max就是开始时的擂主, 然后让下一个元素与它比较,将二者中 值大者保存在max中,然后再让下一个元 素与新的max比,直到最后一个元素比完 为止。max最后的值就是数组所有元素中 的最大值。
293

max=a[0][0]; //使max开始时取a[0][0]的值 for (i=0;i<=2;i++) //从第0行到第2行 for (j=0;j<=3;j++) //从第0列到第3列

if (a[i][j]>max)//如果某元素大于max
{

max=a[i][j]; //max将取该元素的值
row=i; //记下该元素的行号i

colum=j; //记下该元素的列号j
} cout<<row<<‘\t’<<colum<<‘\t’<<max<<endl;
294

将数组行列式互换。
1 4 7 2 5 8 3 6 9 1 2 3 4 5 6 7 8 9

for (i=0; i<3; i++) for (j=0; j<3; j++)

for (i=0; i<3; i++) for (j=0; j<i; j++)

{ t=a[i][j];
a[i][j]=a[j][i];

{ t=a[i][j];
a[i][j]=a[j][i];

a[j][i]=t;
} }

a[j][i]=t;
295

打印杨辉三角形
1

1
1

1
2 1

1
1

3
4

3
6

1
4 1

1

5 10 10

5

1

a[i][j]=a[i-1][j-1]+a[i-1][j]
296

void main(void) { static int n[2],i,j,k; for(i=0;i<2;i++) n[j++]=n[i]+i+1; cout<<n[k]<<'\t'<<n[k++]<<endl;

} 2 1
297

以下程序用于从键盘上输入若干个学生的成绩,统计出平 均成绩,并输出低于平均成绩的学生成绩。输入负数结束
void main() { float x[100],sum=0, ave,a; int n=0,i; cout<<“Input score\n”; _________; cin>>a a>=0 while(__________) ave=sum/n; cout<<“ave=“<<ave<<endl; i<n for( i=0; _____;i++) x[i]<ave if(__________)

{ x[n]=a; sum+=a _______;
_________ n++

cout<<“x[“<<i<<“]”<<x[i]<<endl;

cin>>a;
}
298

输入一个十进制数,输出它对应的八进制数。

不断地除8,求其 余数,直到被除 数为0,最后余数 倒序排列。

725/2=362 362/2=181 181/2=90 90/2=45 45/2=22 22/2=11 11/2=5 5/2=2 2/2=1 1/2=0

余数=1=K0 余数=0=K1 余数=1=K2 余数=0=K3 余数=1=K4 余数=0=K5 余数=1=K6 余数=1=K7 余数=0=K8 余数=1=K9
299

void main(void)
{ int x , i, n ; int a[100]; cin>>x; i=0; } for(i=n-1;i>=0;i--)

cout<<a[i];
cout<<endl;

while(x)
{

a[i]=x%8;
x=x/8; i++; } n=i;

将余数依次 存入数组中

300

已有一个已排好序的数组,今输入一个数,要求按 原来排序的规律将它插入数组中。 3 6 9 13 34 56 78

输入:cin>>x; 25 3 3 6 6 9 9 13 25 34 56 78 13 25 34 56 78 25 34 x 34 y
301

3

6

9

13 25 34 56 78 25 34 x 34 y

3

6

9

13 25 56 34 78 34 56 x 34 56 y
302

void main(void) for(int j=i;j<=5;j++) { int a[6]={1,4,7,10,12}; { int y=a[j]; int x; 将这个数插入 a[j]=x; for(int i=0;i<5;i++) x=y; cout<<a[i]<<'\t'; } cout<<endl; for( i=0;i<6;i++) cout<<"Input x: "; cout<<a[i]<<'\t'; 输入一个数 cin>>x; cout<<endl; for(i=0;i<5;i++) } { if(a[i]>x) 从头比较 break; 大于这个数退出 }
303

a b

3 3

6 6

9

13 34 56 78

9 13 25 34 56 78

输入:cin>>x; 25

304

void main(void) b[i]=x; { int a[6]={1,4,7,10,12}; for(int j=i;j<5;j++) int b[6]; b[j+1]=a[j]; 重新开始赋值 int x; for(i=0;i<6;i++) for(int i=0;i<5;i++) cout<<b[i]<<'\t'; cout<<a[i]<<'\t'; cout<<endl; cout<<endl; } cout<<"Input x: "; cin>>x; for(i=0;i<5;i++) 小于这个数赋值 if(a[i]<x) b[i]=a[i]; else 305 大于这个数退出 break;

a

3

6

9

34 56 13 25 34 56 78 78

输入:cin>>x; 25 for(i=n-1;i>=0;i--)

从后向前循环
306

void main(void) a[i+1]=x; 赋值 { int a[6]={2,5,8,10,12}; for(i=0;i<6;i++) int x; cout<<a[i]<<'\t'; for(int i=0;i<5;i++) cout<<endl; cout<<a[i]<<'\t'; } cout<<endl; cout<<"Input x: "; cin>>x; 关键!从后面开始循环 for(i=4;i>0;i--) { if(a[i]>x) a[i+1]=a[i]; 从前向后移数 else break; 不大于退出循环 307 }

用筛选取法求出2~200之间的所有素数。 筛法:首先将1~n个数为数组置初值。2的倍数不 是素数,置0; 3的倍数不是素数,置0;5的倍数不 是素数,置0;....,依次类推,最后将数组中不是0 的元素输出。
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
2 3 0 5 0 7 0 9 0 11 0 13 0 15 0 17 0 19 0 2 3 0 5 0 7 0 0 0 11 0 13 0 0 0 17 0 19 0
308

数组作为函数参数 一、数组元素作函数参数

数组元素作函数实参,用法与一般变量作实参相同,
是“值传递”。

309

有两个数据系列分别为: int a[8]={26,1007,956,705,574,371,416,517}; int b[8]={994,631,772,201,262,763,1000,781};

求第三个数据系列 c ,要求c中的数据是a b中对应 数的最大公约数。
int a[8]={26, 1007, 956, 705, 574, 371, 416, 517};

int b[8]={994, 631, 772, 201, 262, 763, 1000, 781};
c[8]={2, 1, 4, 3, 2 , 7 , 8, 11}
310

int gys(int m,int n) 求m,n的最大公约数, { int r; 作为函数值返回 if(m<n) { r=m; m=n; n=r; } while(r=m%n) { m=n; n=r; } return n; } void main(void)

{ int a[8]={26,1007,956,705,574,371,416,517}; int b[8]={994,631,772,201,262,763,1000,781}; int c[8]; for(int i=0;i<8;i++) 循环求对应数组元素 c[i]=gys(a[i],b[i]); //对应元素的公约数 的最大公约数 for(i=0;i<8;i++) cout<<c[i]<<'\t'; cout<<endl; 311 }

二、用数组名作函数参数
在C++中,数组名被认为是数组在内存中存放的 首地址。 用数组名作函数参数,实参与形参都应用数组名。

这时,函数传递的是数组在内存中的地址。 实参中的数组地址传到形参中,实参形参共用同

一段内存。
312

void fun(int a[2]) { for(int i=0;i<2;i++) 数组b和数组a占据同一段内存 a[i]=a[i]*a[i]; a同样为数组首地址,也是2000H }

void main(void)
{ int b[2]={2,4}; fun(b); }

a 2000H

4 16 b 2000H 2004H

2 4

cout<<b[0]<<‘\t’<<b[1]<<endl; b就是2000H
输出: 2 4

cout<<b[0]<<‘\t’<<b[1]<<endl;

4

16
313

void sort(int x[ ], int n) { int t,i,j; x for( i=0;i<n-1;i++) 4 8 20 4 a for(j=0;j<n-i-1;j++) if(x[j]>x[j+1]) { t=x[j]; x[j]=x[j+1]; x[j+1]=t;} } void main(void) { int a[5]={20,4,16,8,10}; sort(a, 5 ); for(int i=0;i<5;i++) cout<<a[i]<<'\t'; }

10 16 16 8 20 10

314

有一个一维数组,内放10个学生成绩,求平均成绩。
数组名作 函数形参 float average (float array[ ]) { int i; float aver, sum=array[0]; for (i=1; i<10; i++) sum=sum+array[i]; aver=sum/10; return aver; } void main(void)

{ static float score[10]={ 100, 90, ...};
float aver; 数组名作 aver=average(score); 函数实参 cout<<“aver=“<<aver<<‘\n’;

}
315

注意:

1、用数组名作函数参数,应在主调函数和被调函
数中分别定义数组,且类型一致。 2、需指定实参数组大小,形参数组的大小可不指 定。数组名作实参实际上是传递数组的首地址。

316

3、C++语言规定,数组名代表数组在内存中存储 的首地址,这样,数组名作函数实参,实际上传 递的是数组在内存中的首地址。实参和形参共占 一段内存单元,形参数组中的值发生变化,也相 当于实参数组中的值发生变化。
score
score[0] score[2] score[4] score[6] score[8]

array[0]

array[2]

array[4]

array[6]

array[8]

array
317

程序中的函数p( )用于计算:
主函数利用函数完成计算

p ? ? axi ? byi
i ?0

n ?1

s1 ? ? d i ? 2vi
i ?0

7

s 2 ? ? 3vi ? 4 wi
i ?0

9

int d[]={2,3,5,4,9,10,8}; int v[]={7,6,3,2,5,1,8,9,3,4}; int w[]={1,2,3,4,5,6,7,8,9,10};

int p(int a, int x[], int b, int y[], int n)
{ int i, s; i=0,s=0 i<n; i++) for(________; void main(void) p(1,d,2,v,8) {cout<<“\ns1=“<<____________ _; p(3,v,4,w,10) cout<<“\ns2=“<<_____________ 318 _;

a*x[i]+b*y[i] s+=_____________;
return s; }

int a[10], i; void sub1(void) void main(void)

{ for(i=0;i<10;i++) a[i]=i+i; }
void sub2(void) { int a[10], max,i; max=5; for(i=0;i<max;i++) a[i]=i; }

{ sub1();
sub3(a); sub2(); sub3(a); }

void sub3(int a[])
{ int i; for(i=0;i<10;i++) cout<<a[i]<<‘\t’; 输出:0 2 4 6 8 10 12 14 16 18 0 2 4 6 8 10 12 14 16 18 cout<<endl;

319

编写程序,在被调函数中删去一维数组中所有

相同的数,使之只剩一个,数组中的数已按由
小到大的顺序排列,被调函数返回删除后数组

中数据的个数。
例如: 原数组:2 2 2 3 4 4 5 6 6 6 6 7 7 8 9 9 10 10 10 删除后:2 3 4 5 6 7 8 9 10
320

用多维数组名作函数参数
同样,实参向形参传递的是数组的首地址。
如果实参、形参是二维数组,则形参可以省略第一维,不 可省略第二维,且第二维必须与实参中的维数相等。

int score[5][10] int score[5][10]

int array[ ][10] int array[3][10]

int score[5][10]

int array[ ][8]

错误

321

有一个3×4的矩阵,求其中的最大元素。
int max_value (int array[ ][4])

{ int i, j, k, max;
max=array[0][0]; for (i=0; i<3; i++)

形参

void main (void)
{ static int a[3][4]={{1,3,5,7}, {2,4,6,8},{15,17,34,12}}; cout<<“max is ”<<max_value(a)<<‘\t’;

for (j=0; j<4; j++) if (array[i][j]>max) max=array[i][j]; return (max);

}

实参

}

函数值

数组a与数组array共用一段内存
322

字符数组 用来存放字符数据的数组是字符数组,字符数组中 的一个元素存放一个字符。 一、字符数组的定义 char
类型

数组名[常量表达式];
数组名

char

c[4]; /*每个元素占一个字节 */
数组大小

c[0]=‘I’; c[1]=‘m’; c[2]=‘_’;

323

二、字符数组的初始化
与数值数组的初始化相同,取其相应字符的ASCII值。

char c[10]={‘I’, ‘ ’, ‘a’, ‘m’, ‘ ’, ‘a’, ‘ ’ , ‘b’, ‘o’, ‘y’};
c[0] c[9] ‘’ ‘ a’ ‘ a’ ‘ ’‘‘o’ ‘y’ 随机 c ‘ I’ ‘‘ ’ m’ b’

324

char st1[ ]={65, 66, 68};
‘A’ ‘B’ ‘D’ 如果字符个数大于数组长度,做错误处理;如果数值个数 小于数组长度,后面的字节全部为‘\0’。 如果省略数组长度,则字符数即为数组长度。 static char c[ ]={‘I’, ‘ ’, ‘a’, ‘m’, ‘ ’, ‘a’, ‘ ’ , ‘g’, ‘i’, ‘r’,’l’}; 同理,也可定义和初始化一个二维或多维的字符数组。分 层或省略最后一维。
325

三、字符数组的引用
void main(void)
{ char c[10]={‘I’, ‘ ’, ‘a’, ‘m’, ‘ ’, ‘a’, ‘ ’ , ‘ b’ , ‘ o ’ , ‘ y ’ }; 定义 int i; for (i=0; i<10; i++) cout<<c[i]; cout<<“\n”; }
326

输出

四、字符串和字符串结束标志

C++语言将字符串作为字符数组来处理。
字符串常量:“CHINA”,在机内被处理成一个 无名的字符型一维数组。 A ‘\ 0’ C++语言中约定用‘\0’作为字符串的结束标志, 它占内存空间,但不计入串长度。有了结束标志 ‘\0’后,程序往往依据它判断字符串是否结 束,而不是根据定义时设定的长度。 327 C H I N

字符串与字符数组的区别:

char a[ ]={‘C’,’H’,’I’,’N’,’A’};
字符数组

C

H

I

N

A 随机 随机 长度占5个字节

char c[ ]=“CHINA”;
字符串 C H I N A ‘\0’ 随机 长度占6个字节
328

可以用字符串的形式为字符数组赋初值 char c[ ]={“I am a boy”}; /*长度11字节,以‘\0’结 尾 */ a[ ]={‘I’, ‘ ’, ‘a’, ‘m’, ‘ ’, ‘a’, ‘ ’ , char ‘b’, ‘o’, ‘y’};

/* 长度10字节 */ 如果数组定义的长度大于字符串的长度,后面均为‘ \0’。 char c[10]=“CHINA”;
c

C H

I

N

A ‘\ ‘\ ‘\ ‘\ ‘\ 0’ 0’ 0’ 0’ 0’

‘\0’的ASCII为0,而‘ ’(空格)的ASCII为32。
329

char w[ ]={‘T’, ‘u’, ‘r’, ‘b’, ‘o’, ‘ \0’ }; ]={“Turbo\0”}; char w[ char w[ ]=“Turbo\0”; char w[ ]=‘Turbo\0’;
非法 T u r b o ‘\ ’ o 0 ‘ \ ’ o 0 ‘ \ 0’
330

T u
T u

r
r

b
b

char a[2][5]={“abcd”, “ABCD”};

a A

b B

c C

d ‘\0’ D ‘\0’

在语句中字符数组不能用赋值语句整体赋值。

char str[12];

char str[12]=“The String”;

str=“The String”;定义数组,开辟空

非法,在语句中赋值

间时赋初值

str为字符数组在内存中存储的地址,一经定义,便成为常 量,不可再赋值。
331

字符数组的输入输出
逐个字符的输入输出。这种输入输出的方法,通常是使 用循环语句来实现的。如: char str[10]; 定义

cout<<“输入十个字符:”; for(int i=0;i<10;i++) cin>>str[i]; ...... 赋值 //A

A行将输入的十个字符依次送给数组str中的各个元素。 332

把字符数组作为字符串输入输出。对于一维字符 数组的输入,在cin中仅给出数组名;输出时,在 cout中也只给出数组名。
void main (void )
{char s1[50],s2[60]; cout << “输入二个字符串:”; cin >> s1; cin >> s2; 数组名 数组名

输入:abcd<CR>
string<CR>

cin只能输入一个单 词,不能输入一行

cout << “\n s1 = “ << s1;
“\n”; }

单词。 cout << “ \n s2 = “ << s2 <<
输出到‘\0’为 止
333

当要把输入的一行作为一个字符串送到字符数组 中时,则要使用函数cin.getline( )。这个函数的第 一个参数为字符数组名,第二个参数为允许输入

的最大字符个数。

cin.getline(数组名, 数组空间数);
首先开辟空间

char s1[80]; .......
参数是数组名
334

cin.getline(s1, 80);

void main (void )
{ char s3[81]; 定义

cout<<”输入一行字符串:”; cin.getline(s3,80); 从键盘接收一行字符 //A cout<<”s3=”<<s3<<’\n’; } //B

输出到‘\0’为 止 当输入行中的字符个数小于80时,将实际输入的字符串 (不包括换行符)全部送给s3;当输入行中的字符个数大 于80时,只取前面的80个字符送给字符串。
335

从键盘输入一行字符,统计其中分别有 多少大小写字母,以$号结束输入。 从键盘输入一行字符,统计其中分别有 多少大小写字母。

从键盘输入一行字符,其中的大写变小 写,小写变大写。
336

从键盘接收一行字符,统计有多少个单词数?
we are students.
w
0

e

a

r

e

s

字母 字母 空格 空格 字母 字母 字母 空格 字母 1 1 0 0 1 1 1 0 1

不能用字母数或空格数来判断,只能用字母和空格状态变

化的次数来判断。
设状态变量word , 判别到字母时word为1,判别到非字母 时word为0。 word的初始值为0,当从0变为1时,单词数加1。
337

void main(void) {char s[80]; int i=0, word=0,num=0; cin.getline (s,80); 表明前一字符非字母 while(s[i]!='\0') { if((s[i]>='a'&&s[i]<='z'||s[i]>='A'&&s[i]<='Z')&&word==0) { word=1; 改变状态,防止继续对 num++; 下一字母计数 } else if(s[i]==' '||s[i]=='\t') word=0; 改变状态,碰到下一 i++; 个字母时开始计数 } cout<<"num="<<num<<endl; } 338

六、字符串处理函数
C++中没有对字符串变量进行赋值、合并、比较 的运算符,但提供了许多字符串处理函数,用户可 以调用 #include “string.h” 所有字符串处理函数的实参都是字符数组名

339

1、合并两个字符串的函数 strcat (str1, str2) 空间足够大 static char str1[20]={“I am a ”};
static char str2[ ]={“boy”}; strcat (str1, str2); I a m a '\0' '\0'

b
I

o

y ‘\ 0’ a m

a

b

o

y '\0'

将第二个字符串 str2 接到第一个字符串 str1 后。
注意:第一个字符串要有足够的空间。
340

2、复制两个字符串的函数 strcpy (str1, str2) static char str1[20]={“I am a ”};
static char str2[ ]={“boy”}; strcpy (str1, str2);
str1

I

a m

a

'\0' '\0'

str2 b

o y '\0 ' str1 b o y '\0'

a

'\0' '\0' 字符串正确赋值

strcpy ( str1, “CHINA str1 C H” I ); N A '\0'

str1=str2; str1=“CHINA”; strcpy (“CHINA”, str1);

均为非法
341

3、比较两个字符串的函数 strcmp (str1, str2)

此函数用来比较str1和str2中字符串的内容。函数对字符串
中的ASCII字符逐个两两比较,直到遇到不同字符或‘\0’ 为止。函数值由两个对应字符相减而得。 该函数具有返回值,返回值是两字符串对应的第一个不同 的ASCII码的差值。 若两个字符串完全相同,函数值为0。

if ( strcmp (str1, str2)==0)
{ ........ }

用来判断两字符 串是否相等
342

static char str1[20]={“CHINA”}; static char str2[ ]={“CHINB”}; cout<< strcmp (str1, str2)<<endl; 输出:-1

static char str1[20]={“CHINA”};
static char str2[ ]={“AHINB”}; 输出:2

cout<<strcmp (str1, str2)<<endl;
if (str1= =str2) cout<<“yes\n”; 正确 if (strcmp (str1,str2)= =0) 非法 cout<<“yes\n”;

343

4、求字符串长度的函数 strlen (str1)

函数参数为数组名,返回值为数组首字母到‘\0’的长度。

长度不包括‘\0’。 并非数组在内存中空间的大小。
char s[80];

strcpy(s, “abcd”);
cout<<strlen(s)<<endl; cout<<siziof(s)<<endl; 输出: 4 输出: 80

y ‘\ a 0’ cout<<strlen(str1)<<endl;
str1

b

o

‘\ ‘\ 0’ 0’ 输出: 3

344

char str1[20]={“CHINA”}; cout<<strlen (str1)<<endl; char str1[20]={“a book”}; 输出:5

cout<<strlen (str1)<<endl;
char sp[ ]={“\t\v\\\0will\n”}; cout<<strlen (sp)<<endl; char sp[ ]={“\x69\082”}; cout<<strlen (sp)<<endl;

输出:6

输出:3

输出:1
345

5、 strlwr (str1)

将str1中的大写字母转换成小写字母。
6、 strupr (str1) 将str1中的小写字母转换成大写字母。

346

7、函数strncmp(字符串1,字符串2 , maxlen) 函数原型为: int strncmp(char str1[ ], char str2[ ],int m) 第三个参数为正整数,它限定了至多比较的字符个数 若字符串1或字符串2的长度小于maxlen的值时,函数的 功能与strcmp( )相同。 当二个字符串的长度均大于maxlen的值时,maxlen为至 多要比较的字符个数。

输出:0
347

cout<<strncmp(“China”,“Chifjsl;kf”,3)<<‘\n’;

8、函数strncpy(字符数组名1, 字符串2, maxlen) 函数原型为: void strncmp(char str1[ ], char str2[ ],int m) 第三个参数为正整数,它限定了至多拷贝的字符个数 若字符串2的长度小于maxlen的值时,函数的功能与 strcpy( )相同。 当字符串2的长度大于maxlen的值时,maxlen为至多要拷 贝的字符个数。

348

空间足够大

char s[90],s1[90];

strncpy(s,"abcdssfsdfk",3);
strncpy(s1,"abcdef " , 90); //B

//A

cout<<s<<endl;
cout<<s1<<endl;

输出:abc 输出:abcdef

注意,二字符串之间不能直接进行比较 , 赋值等操

作, 这些操作必须通过字符串函数来实现。
349

输入三个字符串按大小输出。

输入n个字符串按大小输出。

350

void changed(char str1[],char str2[]) {char str3[80]; strcpy(str3,str1); strcpy(str1,str2); void main(void) strcpy(str2,str3); {char s1[80],s2[80],s3[80]; } cout<<"Input 3 strings:\n"; cin.getline(s1); cin.getline(s2); cin.getline(s3); if(strcmp(s1,s2)>0) changed(s1,s2); if(strcmp(s1,s3)>0) changed(s1,s3); if(strcmp(s2,s3)>0)changed(s2,s3); cout<<"sorted:"<<endl<<endl; cout<<s1<<endl<<s2<<endl<<s3<<endl; }
351

void changed(char str1[],char str2[]) {char str3[80]; strcpy(str3,str1); void main(void) strcpy(str1,str2); {char ss[10][80]; int i,j; strcpy(str2,str3); cout<<"Input 10 strings:\n"; } for(i=0;i<10;i++)

cin.getline (ss[i],80);
for(i=0;i<9;i++) for(j=0;j<9-i;j++) if(strcmp(ss[j],ss[j+1])>0) changed(ss[j],ss[j+1]); cout<<"sorted:"<<endl<<endl; for(i=0;i<10;i++) cout<<ss[i]<<endl; 352 }

用选择法对6个数排序(由小到大)
设定一个变量,放入数组中的最小数的序号,然后将其与

最上面的数比较交换。
1、min=1 2、a[min]与a[2]比较 min 1 假定元素序号 为1的数是最 小的数 3、min=2 min 2 这时,最小数 的序号变为2 4、 a[min]与a[3]比较

9 a[1] 8 5 4 2 a[2] a[3] a[4] a[5]

9 a[1] 8 5 4 2 a[2] a[3] a[4] a[5]

0 a[6]
即9与8比较

0 a[6]
即8与5比较 353

min=3
min 3 这时,最小数 的序号变为3 min=5 min 5

a[min]与a[4]比较

min=4
min 4 这时,最小数 的序号变为4 min=6 min 6

a[min]与a[5]比较

9 8 5 4 2 0

a[1] a[2] a[3] a[4] a[5] a[6]

9 8 5 4 2 0

a[1] a[2] a[3] a[4] a[5] a[6]

即5与4比较 a[min]与a[6]比较

即4与2比较 a[min]与a[1]交换

这时,最小数 的序号变为5

9 8 5 4 2 0

a[1] a[2] a[3] a[4] a[5] a[6]

第一趟比较完毕, 最小数是a[6],最小 数的序号为6

第一趟,循环5次

0 8 5 4 2 9

a[1] a[2] a[3] a[4] a[5] 354 a[6]

min=2
min 2

a[min]与a[3]比较

min=3
min 3

a[min]与a[4]比较

从第二个数开始 比较,假定最小 数的序号为2 min=4 min 4

0 8 5 4 2 9

a[1] a[2] a[3] a[4] a[5] a[6]

0 8 5 4 2 9

a[1] a[2] a[3] a[4] a[5] a[6]

a[min]与a[5]比较

min=5 min 5

a[min]与a[6]比较

0 8 5 4 2 9

a[1] a[2] a[3] a[4] a[5] a[6]

0 8 5 4 2 9

a[1] a[2] a[3] a[4] a[5] 355 a[6]

min=5 min 5

a[min]与a[2]交换

第二趟比较完毕, 最小数是a[5],最小 数的序号为5

0 2 5 4 8 9

a[1] a[2] a[3] a[4] a[5] a[6]

第二趟,循环4次
356

min=3
min 3

a[min]与a[4]比较

min=4
min 4

a[min]与a[5]比较

0 2 5 4 8 9

a[1] a[2] a[3] a[4] a[5] a[6]

0 2 5 4 8 9

a[1] a[2] a[3] a[4] a[5] a[6]

min=4 min 4

a[min]与a[6]比较

min=4 min 4

a[min]与a[3]交换

0 2 5 4 8 9

a[1] a[2] a[3] a[4] a[5] a[6]

第三趟,循环3次

0 2 4 5 8 9

a[1] a[2] a[3] a[4] a[5] 357 a[6]

min=4
min 4

a[min]与a[5]比较

min=4
min 4

a[min]与a[6]比较

0 2 4 5 8 9

a[1] a[2] a[3] a[4] a[5] a[6]

0 2 4 5 8 9

a[1] a[2] a[3] a[4] a[5] a[6]

min=4 min 4

a[min]与a[4]交换

0 2 4 5 8 9

a[1] a[2] a[3] a[4] a[5] a[6]

第四趟,循环2次

358

min=5
min 5

a[min]与a[6]比较

min=5
min 5

a[min]与a[5]交换

0 2 4 5 8 9
总结:

a[1] a[2] a[3] a[4] a[5] a[6]

第五趟,循环1次 { min=i ;

0 2 4 5 8 9

a[1] a[2] a[3] a[4] a[5] a[6]

for (i=1; i<=n-1; i++)

n 共有6个数 趟数 1 2 3 4 5 i(1~n-1) 次数 5 4 3 2 1 n-i
}

for (j=i; j<=n; j++)
if (a[min]>a[j]) t=a[min]; min=j ;

a[min]=a[i];
a[i]=t;
359

一般,元素的序号从0开始,因此,程序可以变动如下: for (i=0; i<n-1; i++) { min=i;

每一次循环前设 置最小数的序号
小循环,找最 小数的序号, 从 i 找起 大循环,找到 后与 i 交换
360

for (j=i; j<n ; j++) if (a[min]>a[j]) min=j ;

t=a[min];
a[min]=a[i];

a[i]=t;
}

调试程序的方法:

1)单步调试:以行为单位,每运行一步,程序就会中断, 可以实时查询目前各变量的状态及程序的走向。可以选择 是否进入子函数。 2)运行到光标处,可以直接使程序运行到光标处再进行 单步调试,这种方法可以不必运行正确的循环而直接到有 疑问的地方。

361

在a数组中查找与x值相同的元素所在的位置,数据从a[1] 元素开始存放,请填空: #define MAX 10
void main(void) { int a[MAX+1], x, i; for(i=1;i<=MAX;i++)

a[i] while(x!=___________)
i-____________________;

i!=0 if(___________)

cout<<x<<“the pos:”<<i<<endl; cin>>__________; a[i] cout<<“Not found”<<endl;
362

cout<<“Enter x:”; else cin>>x; a[0]=x; i=MAX;

void main(void) { char str[ ]=“SSSWILTECH1\1\11W\1WALLMP1”; char c; int k; for(k=2; (c=str[k])!=‘\0’;k++) { switch(c) { case ‘A’ : cout<<‘a’; continue; case ‘1’: break; case 1: while((c=str[++k])!=‘\1’&&c!=‘\0’); case 9: cout<<‘#’; case ‘E’ : S W IT CH *# W aMP * case ‘L’: continue; default: cout<<c; continue; } cout<<‘*’; } cout<<endl; } 363

以下程序分别在a数组和b数组中放入an+1和bn+1个由小到大的有 序数,程序把两个数组中的数按由小到大的顺序归并到c数组中, 请填空: while( a[i]!=max||b[j]!=max) void main(void) { if(a[i]<b[j]) { int a[10]={1,2,5,8,9,10},an=5; a[i] { c[k]=________;
int b[10]={1,3,4,8,12,18}, bn=5; int i,j,k, c[20], max=9999; a[an+1]=b[an+1]=max; i=j=k=0;

k++;

i++ _______}
else

b[j] { c[k]=_________;
k++;

j++ _____________;}
} for(i=0;i<k;i++)cout<<c[i];
cout<<endl; }
364

编写程序,在被调函数中删去一维数组中所有相同
的数,使之只剩一个,数组中的数已按由小到大的

顺序排列,被调函数返回删除后数组中数据的个数。
例如: 原数组:2 2 2 3 4 4 5 6 6 6 6 7 7 8 9 9 10 10 10

删除后:2 3 4 5 6 7 8 9 10

365

第七章

结构体、共同体和枚举类型

366

定义:

将不同种类型的数据有序地组合在一起,构
造出一个新的数据类型,这种形式称为结构

体。 结构体是多种类型组合的数据类型。

367

struct

结构体名
关键字 结构体名

{ 成员列表 };

struct student { int num; char name[20];
不同数据 类型组成 的成员

char sex;
char addr[30];

};

分号不能少
368

定义结构体类型变量的方法 一、先定义结构体类型再定义变量名

struct student { int num; 结构体类型只是一种数据 char name[20]; 类型,不占内存空间,只 char sex; 有定义结构体类型变量时 int age; 才开辟内存空间。 float score; char addr[30]; }; struct student student1, student2;
结构体类型名 变量1 变量2
369

# define STUDENT struct student STUDENT { int num; char name[20]; char sex; int age; 凡是STUDENT的地

方都用struct student
机械替换。

float score;
char addr[30];

};
STUDENT student1,student2;
370

二、在定义类型的同时定义变量
struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; } student1, student2;
紧接着定 义变量
371

struct 结构体名
{

成员列表
}变量名列表;

三、直接定义结构体类型变量
struct { int num; char name[20]; char sex; int age; float score; char addr[30]; } student1, student2; 不出现结构体名。
372

struct
{

成员列表
}变量名列表;

1、结构体类型的变量在内存依照其成员的顺序顺
序排列,所占内存空间的大小是其全体成员所占空

间的总和。
2、在编译时,仅对变量分配空间,不对类型分配 空间。

3、对结构体中各个成员可以单独引用、赋值,其
作用与变量等同。

格式:变量名 . 成员名 student1 . num
373

4、结构体的成员可以是另一个结构体类型。
struct date { int month; int day; int year; }; }; 成员类型 struct student { int num; char name[20]; struct date birthday; 成员名

5、成员名可以与程序中的变量名相同,二者分占不同的内 存单元,互不干扰。例如,在程序中仍可以定义变量 int num;
374

结构体类型变量的引用 1、不能对结构体变量整体赋值或输出,只能分别对各个成 员引用。 错误 cin>>student1; 必须用成员名引用

cin>>student1.num;

student1.num=100;

可以将一个结构体变量整体赋给另外一个相同类型的结构 体变量。 student2=student1; 2、嵌套的结构体变量必须逐层引用。 student1.birthday.day=25; 3、结构体变量中的成员可以同一般变量一样进行运算。 student1.birthday.day++; student1.score+=60; 375

对局部变量类型的结构体变量初始化
void main(void) { struct student { long int num;

char name[20];
char sex;

char addr[30];

对变量初始化,一一赋值

} student1={901031, “Li Lin”, ‘M’, “123 Beijing Road”}; cout<<student1.name<<endl;

输出: LiLin

376

关于结构类型变量的使用,说明以下几点:

1、同类型的结构体变量之间可以直接赋值。这种 赋值等同于各个成员的依次赋值。 2、结构体变量不能直接进行输入输出,它的每一 个成员能否直接进行输入输出,取决于其成员的类 型,若是基本类型或是字符数组,则可以直接输入 输出。
3、结构体变量可以作为函数的参数,函数也可以 返回结构体的值。当函数的形参与实参为结构体类 型的变量时,这种结合方式属于值调用方式,即属 377 于值传递。(举例说明)

结构体数组 结构体数组中的每个元素都是一个结构体类型的变 量,其中包括该类型的各个成员。数组各元素在内

存中连续存放。

378

一、结构体数组的定义
struct student { int num; struct student { int num; char name[20];

char name[20];
char sex;

int age;
float score;

char sex;
int age;

char addr[30];
}; struct student stu[30];

float score;
char addr[30]; } stu[30]; 直接定义
379

二、结构体数组的初始化
struct student
{ int num; char name[20]; char sex; } stu[3]={ {1011, "Li Lin",'M'}, {1012,"Wang Lan",'F'}, {1013,"Liu Fang",'F'};

380

struct student { int num; char name[20]; char sex; } stu[ ]={ {1011,"Li Lin",'M'}, {1012,"Wang Lan",'F'}, {1013,"Liu Fang",'F'}};

381

以下程序的结果是:
void main(void) { struct date { int year, month, day; } today;

cout<<sizeof(struct date)<<endl;
} 12
382

根据下面的定义,能打印出字母M的语句是:
struct person { char name[9];

int age;
}; struct person class[10]={ “Jone”,17, “Paul”,19, “Mary”,18, “Adam”,16 }; A) cout<<class[3].name<<endl; 输出:Adam B) cout<<class[3].name[1]<<endl; 输出:d

C) cout<<class[2].name[1]<<endl; 输出:a
D) cout<<class[2].name[0]<<endl; 输出:M
383

结构体类型的静态成员

当把结构体类型中的某一个成员的存储类型定义为静态时,表示 在这种结构类型的所有变量中,编译程序为这个成员只分配一个 存储空间,即这种结构体类型的所有变量共同使用这个成员的存 储空间。
<类型> <结构体类型名>::<静态成员名>; 其中类型要与在结构体中定义该成员的类型一致,结构体类型名 指明静态成员属于哪一个结构体。 struct s{ static int id; int eng; }; 结构体类型 数据类型 int s::id=50; 这时,未定义结构体变量, 但已将静态成员的空间安 排好。 若有定义:s s1,s2; 则变量s1,s2的id成员占用同一 存储空间(静态区)。
384

在结构体中说明的静态成员属于引用性说明,必须在文件作用域 中的某一个地方对静态的成员进行定义性说明,且仅能说明一次。 int s::id; 说明id的初值为0(静态变量的缺省初值均为0)

385

共用体 C++语言中,允许不同的数据类型使用同一存储区域,即 同一存储区域由不同类型的变量共同表示。这种数据类型 就是共用体。 union data union 共用体名 { int i; { 成员表列; char ch; } 变量表列; float f; union data a, b, c; } a, b, c;

这几个成员在共用体变量中存放在同一地址,相互覆盖,
其长度为最长的成员的长度。
386

共用体变量的引用

不能整体引用共用体变量,只能引用变量中 的成员。
a.i 表示为整型

a.ch 表示为字符型
a.f 表示为符点型
387

共用体变量的特点
1、共用体的空间在某一时刻只有一个成员在起作 用。 2、共用体变量中的成员是最后一次放入的成员。 3、共用体变量不能在定义时赋初值。

4、共用体变量不能作为函数的参数或函数值,但 可使用指向共用体的指针变量。 5、共用体可以作为结构的成员,结构体也可以作 为共用体的成员。
388

union un { int i; double y; }; struct st { char a[10]; union un b; }; cout<<sizeof(struct st)<<endl;
389

18

union un
{ short int a;

低字节低地址 高字节高地址

2000H

6
5 65 ?

char c[2];
} w;

2001H

w.c[0]=‘A’; w.c[1]=‘a’;
cout<<oct<<w.a<<endl;
‘a’ 2001H

输出:060501 56 ?
‘A’ 2000H

0 1 1 0 0 0 0 1 0 1 0 0 0 0 0 1
w.c[1] w.c[0]

a

390

void main(void)
{ union EXAMPLE

{
}e;

struct { int x, int y;} in;
int a,b;

e.a=1; e.b=2;

x in y

4 2 1
8

a b
b

e.in.x=e.a*e.a;
e.in.y=e.b+e.b;

输出:4

8

cout<<e.in.x<<‘\t’<<e.in.y<<endl; }
391

枚举类型 如果一个变量只有几种可能的值,可以定义

为枚举类型。 枚举类型就是将变量的值一一列举出来,变
量的值仅限于列举出来的值的范围内。
392

enum weekday {sun, mon, tue, wed, thu, fri, sat}; 数据类型 可能取的值 变量

enum weekday workday, weekend ; workday 和 weekend 值只能是sun 到 sat 其中之一。

另一种定义变量的方法 enum {sun, mon, tue, wed, thu, fri, sat} weekend ; workday,

其中sun, mon,....,sat称为枚举元素或枚举常量,为用户定 义的标识符,所代表的意义由用户决定,在程序中体现出 来。 393

1、枚举元素为常量,不可赋值运算。 sun=0; mon=1; 2、在定义枚举类型的同时,编译程序按顺序给每个枚举元 素一个对应的序号,序号从0开始,后续元素依次加1。 enum weekday {sun, mon, tue, wed, thu, fri, sat}; 0 , 1, 2, 3, 4, 5, 6 3、可以在定义时人为指定枚举元素的序号值。 enum weekday {sun=9, mon=2, tue, wed, thu, fri, sat}; 9 , 2, 3, 4, 5, 6 , 7 4、只能给枚举变量赋枚举值,若赋序号值必须进行强制类 型转换。 day=mon ; day=1; day=(enum weekday)1;
394

5、枚举元素可以用来进行比较判断。 if (workday= = mon) if (workday>sun)

6、枚举值可以进行加减一个整数n的运算,得到其前后第 n个元素的值。 workday=sun; workday=(week)(workday+2); 7、枚举值可以按整型输出其序号值。 workday= = tue

workday=tue;
cout<<workday; 2
395

void main(void) { enum team{ qiaut, cubs=4, pick, dodger=qiaut-2;}; cout<<qiaut<<‘\t’<<cubs<<‘\t’; cout<<pick<<‘\t’<<dodger<<endl; }

输出:0 4

5 -2
396

第八章

指针和引用

397

指针的概念
数据在内存中是如何存取的?

系统根据程序中定义变量的类型,给变量分配一定的长度
空间。字符型占1个字节,整型数占4个字节.....。内存区的

每个字节都有编号,称之为地址。
内存单元 的地址
2000H 2001H 3

2002H
2003H 2004H

5

内存单元 的内容
398

内存

1、直接访问
按变量地址存取变量的值。cin>>i; 实际上放到定义 i 单 元的地址中。 i 2、间接访问 将变量的地址存放在另一个单元p中,通过 p 取出变量的 地址,再针对变量操作。 3000H 2000H p 2000H i

一个变量的地址称为该变量的指针。
如果在程序中定义了一个变量或数组,那么,这个变量或
数组的地址(指针)也就确定为一个常量。
399

变量的指针和指向变量的指针变量
变量的指针就是变量的地址,当变量定义后,其指针(地

址)是一常量。
int i; &i :2000H 2000H i

可以定义一个变量专门用来存放另一变量的地址,这种 变量我们称之为指针变量。在编译时同样分配一定字节 的存储单元,未赋初值时,该存储单元内的值是随机的。 指针变量定义的一般形式为: 指针类型 类型标识符 *变量名 int 变量名
400

*i_point;

指针变量同样也可以赋值:
int i, *i_point; i_point=&i; 3000H 2000H i_point int i; int *i_point=&i; 2000H i

也可以在定义指针变量时赋初值:

一个指针变量只能指向同一类型的变量。即整型指针变量 只能放整型数据的地址,而不能放其它类型数据的地址。

* 在定义语句中只表示变量的类型是指针,没有任何计算
意义。 * 在语句中表示“指向”。&表示“地址”。 401

3000H 2000H i_point

2000H 3 i

int i;

表示 类型

int *i_point=&i;
表示 指向

*i_point=3;

402

指针变量的引用 int *p, i; p=100;
非法

指针变量只能存放地址,不要将非地址数据赋给指针变量。

p=&i;
a 10 &a p1 10 b 100 &b p2 100

void main(void) { int a=10, b=100; int *p1, *p2;

指针变量赋值

p1=&a; p2=&b; cout<<a<<‘\t’<<b<<endl; cout<<*p1<< ‘\t’<<*p2<<endl; 表示 指针变量引用 } 指向

10

100
403

void main(void)

{ int a, b;
int *p1, *p2; 指针变量赋值

a 10 &a p1

b 100 &b p2

p1=&a; p2=&b;

通过指针对 *p1=10; *p2=100; 变量赋值 cout<<a<<‘\t’<<b<<endl; cout<<*p1<<‘\t’<<*p2<<endl; 指针变量引用 }

404

void main(void) { int a, b; int *p1, *p2; *p1=10; *p2=100;

但指针变量未赋值,即 指针指向未知地址
通过指针对 变量赋值
a b

cout<<a<<‘\t’<<b<<endl; cout<<*p1<<‘\t’<<*p2<<endl; }

随机 p1

随机 p2

绝对不能对未赋值的指针变量作“指向”运算。
int i, *p1;
p1=&i;
用指针变量前,必须 对指针变量赋值

405

输入a, b两个整数,按大小输出这两个数。
void main(void) { int *p1, *p2, *p, a,b; cin>>a>>b; p1=&a; p2=&b; if (a<b) a 10 b 100

交换地址

&a &b p1

&b &a p2

&a p

{ p=p1; p1=p2; p2=p; } cout<<a<<‘\t’<<b<<endl;

10

100

cout<<*p1<<‘\t’<<*p2<<endl;
}

100

10
406

虽然变量不变,但指向变量的指针发生变化

++, - -, * 优先级相同,都是右结合性。
int a=3, *p;

p=&a;

a 2000H
43

2004H 5

2008H 7

&a

p
(*p)++; 相当于a++。表达式为3, a=4

407

++, - -, * 优先级相同,都是右结合性。
int a=3, *p;

a 2000H 3

2004H 5

2008H 7

p=&a;

&a 2004H p
*p++; *(p++)首先*p ,然后p=p+1,指针指向下一 个int单元 表达式为3, p=2004H。
408

++, - -, * 优先级相同,都是右结合性。
int a=3, *p;

p=&a;

a 2000H
43

2004H 5

2008H 7

&a

p
++*p ++(*p) *p=*p+1 a=4
409

++, - -, * 优先级相同,都是右结合性。
int a=3, *p;

a 2000H 3

2004H 5

2008H 7

p=&a;

&a 2004H p
*++p *(++p),首先:p=p+1, 然后取*p。即取p 所指的下一个int单元的内容。

表达式为5 p=2004H
410

指针变量作为函数参数:

函数的参数可以是指针类型,它的作用是将
一个变量的地址传送到另一个函数中。 指针变量作为函数参数与变量本身作函数参 数不同,变量作函数参数传递的是具体值,

而指针作函数参数传递的是内存的地址。
411

输入a, b两个整数,按大小输出这两个数。
swap(int *p1, int *p2) { int t; t=*p1; *p1=*p2; *p2=t; }

point1 &a

a 100 10

a=100

void main(void) &a { int *point1, *point2, a,b; p1 cin>>a>>b; point2 point1=&a; point2=&b; &b if (a<b) swap (point1, point2); &b cout<<“a=“<<a<<“,b=”<<b<<endl; p2 cout<<*point1<<“,”<<*point2<<endl; }

t 10

b 100 10 b=10
输出:a=100,b=10 100,10
412

输入a, b两个整数,按大小输出这两个数。
swap(int x, int y) { int t; t=x; x=y; y=t; } void main(void) { int *point1, *point2, a,b; cin>>a>>b; point1=&a; point2=&b; if (a<b) swap (a, b); 值传递

a 10 &a point1
b 100 &b

x 100 10

x=100

t 10
y 100 10 y=10

cout<<“a=“<<a<<“,b=”<<b<<‘\npoint2 ’; 输出:a=10,b=100 413 cout<<*point1<<‘\t’<<*point2; 10,100

用指针变量作函数参数,在被调函数的执行 过程中,应使指针变量所指向的参数值发生 变化,这样,函数在调用结束后,其变化值 才能保留回主调函数。 函数调用不能改变实参指针变量的值,但可 以改变实参指针变量所指向变量的值。

用指针变量作函数参数,可以得到多个变化 了的值。
414

void grt(int *x , int *y , int *z) { cout<< ++*x<<‘,’<< ++*y<<‘,’<<*(z++)<<endl;} int a=10, b=40, c=20; 11, 41, 20 void main(void) 12, 42, 20 { prt (&a, &b, &c); prt (&a, &b, &c); a x 10 &a }

++*x: *x=*x+1
*(z++): *z ; z=z+1
415

int s( int *p) 输入:1 3 5<CR> { int sum=10; sum a p sum=sum + *p; 1 &a 11 return sum; } void main(void) sum 10 &a 11 { int a=0, i, *p, sum; p for (i=0; i<=2; i++) { p=&a; cin>>*p; sum=11 sum=s(p); sum=13 cout<<“sum=”<<sum<<endl; sum=15 } }

416

sub( int *s) { static int t=0; t=*s + t; return t; } void main(void) { int i, k; for (i=0; i<4; i++) { k=sub(&i);

i=0 t=*s+t=0 k=0 sum=0 i=1 t=*s+t=1 k=1 sum=1 i=2 t=*s+t=3 k=3 sum=3 i=3 t=*s+t=6 k=6 sum=6

sum=0 sum=1 sum=3 sum=6
417

cout<<“sum=“<<k<<‘\t’; } cout<<“\n”;

int *p; void main(void) { int a=1, b=2, c=3; p=&b; pp(a+c, &b);

b 2 &b p

b &b a 4

cout<<“(1)”<<a<<‘ ‘<<b<<‘ ‘<<*p<<endl; } *p=*b+4=2+4=6 (2) 2 6 6 pp(int a, int *b) a=6-c=2 { int c=4; (1) 1 6 6 *p=*b+c; a=*p-c;
418

举例:最大最小值、方程根

419

数组的指针和指向数组的指针变量
数组与变量一样,在内存中占据单元,有地 址,一样可以用指针来表示。C++规定:数 组名就是数组的起始地址;又规定:数组的

指针就是数组的起始地址。数组元素的指针
就是数组元素的地址。
420

一、指向数组元素的指针变量的定义与赋值 int a[10], *p;
数组第一个元素的地址 &a[0]
2000H 2004H 2008H 200CH

p=&a[0];

a

p=a;

直接用数组名赋值

p

p是变量,a为常量。 若数组元素为int型,则指向其的指针变 量也应定义为int型。 int a[10]; int *p=a;
这两种情况均为赋初值

2010H
2014H 2018H 201CH 2020H

int *p=&a[0];

2024H

a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] 421

二、通过指针引用数组元素
&a[0] int a[10]; p int *p=a; 为指针变量赋初值
2000H 2004H 2008H 200CH

a
1 2

*p=1;

通过指针变量为 数组元素赋值

a[0]=1;

2010H 2014H 2018H

C++规定,p+1指向数组的下一

201CH
2020H 2024H

个元素,而不是下一个字节。
*(p+1)=2; *++p=2; a[1]=2;

a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9]

指针变量也重新赋值
422

p=p+1; *p=2; p=2004H

*(p+1)=2;
*(a+1)=2;

a[1]=2;
&a[0]
2000H

a 1

*(a+1)与a[1]等同。

p

2004H
2008H 200CH

2

*++p=2; p=p+1; *p=2; p=2004H *++a=2; 错误

2010H
2014H 2018H 201CH 2020H 2024H

a为常量,不可赋值。 p+i 或 a+i 均表示 a[i] 的地址 &a[i] *(a+i) a[i] *(p+i)

a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9]

p[i]

423

用指向数组的指针变量输出数组的全部元素
void main(void) void main(void)

{ int a[10], i;
int *p;

{ int a[10], i;
int *p=a;

for (i=0; i<10; i++)
cin>>a[i];
指针变量赋初值

for (i=0; i<10; i++)
cin>>a[i];

输入数组元素
指向下一元素

for (i=0; i<10; i++) cout<<*p++<<‘\t’;

for (p=a; p<a+10; p++)

cout<<*p<<‘\t’;
}
输出指针指向的数据

*p, p=p+1

}

输出数据后指针加 1 424

void main(void) { int x[ ]={1,2,3}; int s, i, *p;
p p+1 p+2

x

1 2 3

s=1; p=x;
for (i=0; i<3; i++) i=0 i=1 i=2 6
425

s*=*(p+i);
cout<<s<<endl; }

s=s*(*(p+0)) =s*1=1 s=s*(*(p+1)) =s*2=2 s=s*(*(p+2)) =s*3=6

static int a[ ]={1, 3,5, 7, 11, 13}; main( )

{ int *p;
p=a+3;

p &a[3]

cout<<*p<<'\t'<<(*p++)<<endl; cout<<*(p-2)<<'\t'<<*(a+4)<<endl; }

1 3 5 7 11 13

a[0] a[1] a[2] a[3] a[4] a[5]

11 5

7 11
426

三、数组名作函数参数
数组名可以作函数的实参和形参,传递的是数组的 内存单元中的数据发生变化,这种变化会反应到主 调函数内。

地址。这样,实参、形参共同指向同一段内存单元,

在函数调用时,形参数组并没有另外开辟新的存储
单元,而是以实参数组的首地址作为形参数组的首

地址。这样形参数组的元素值发生了变化也就使实
参数组的元素值发生了变化。
427

1、形参实参都用数组名 void main(void) { int array[10]; ...... f(array, 10); 形参数组,必须进行类型说明 f(int arr[ ], int n)

{
...... } 实参数组

.....
}

用数组名作形参,因为接收的是地址,
所以可以不指定具体的元素个数。
428

array,arr arr[0]
2000H 2004H 2008H

指向同一 存储区间

200CH
2010H 2014H 201CH 2020H 2024H 2028H

array[0] array[1] array[2] array[3] array[4] array[5] array[6] array[7] array[8] array[9]
429

2、实参用数组名,形参用指针变量 void main(void) { int a [10]; ...... f(int *x, int n )

{

形参指针 ......

实参数组 f(a, 10); } .....

}
430

3、形参实参都用指针变量

void main(void)
{ int a [10],*p;

形参指针 f(int *x, int n ) { ......

p=a;
...... 实参指针 f(p, 10); ..... }

}

实参指针变量调用前必须赋值
431

4、实参为指针变量,形参为数组名

void main(void)
{ int a [10],*p;

形参数组 f(int x[ ], int n )

p=a;
...... 实参指针

{
......

f(p, 10);
..... }

}

432

将数组中的n个数按相反顺序存放。 void inv(int x[ ], int n) { int t, i, j, m=(n-1)/2; for (i=0;i<=m; i++) { j=n-1-i; t=x[i]; x[i]=x[j]; x[j]=t; } } void main(void) { int i, a[10]={3,7,9,11,0,6,7,5,4,2}; inv(a,10); for (i=0;i<10; i++) cout<<a[i]<<‘\t’; }

x与a数组指向同 一段内存
x[0] x[1] x[2] x[3]

x, a 3 7

x[4]
x[5] x[6] x[7] x[8]

x[9]

9 11 0 6 7 5 4 2

a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9]
433

void inv(int *x, int n) 用指针变量来 { int *p, t, *i, *j, m=(n-1)/2; 接受地址 i=x; j=x+n-1; p=x+m; x, a for (; i<=p; i++,j--) i x[0] 3 { t=*i; *i=*j; *j=t; x[1] 7 x[2] } 9 11 x[3] } x[4] 0 p void main(void) x[5] 6 { int i, a[10]={3,7,9,11,0,6,7,5,4,2}; x[6] 7 inv(a,10); x[7] 5 for (i=0;i<10; i++) x[8] 4 cout<<a[i]<<‘\t’; x[9] j 2 }

a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9]
434

输入10个整数,将其中最小的数与第一个数 对换,把最大的数与最后一个数对换。写3个 函数:①输入10个数;②进行处理;③输出 10个数。

435

编写函数 int fun(int x, int *pp),其功能是,求出 能整除x且不是偶数的各整数,并按照从小到大的 顺序放在pp指向的内存中,函数返回值为这些整 数的个数。若x的值为30, 数组中的数为1,3,5, 15,函数返回4。

436

int fun(int x, int *pp)
{ int k=0; for(int i=1;i<x;i++) { if(i%2&&x%i==0) { *(pp++)=i; k++; } } return k;

void main(void) { int a[1000],x,n;

cin>>x;
n=fun(x,a);

for(int i=0;i<n;i++)
cout<<a[i]<<'\t'; cout<<endl; }
437

}

输入一行字符串,将字符串中所有下标 为奇数位置上的字母转换为大写(若不 是小写字符则不必转换)。

438

void change(char *pchar)

{ while(*pchar)
{ if(*pchar>='a'&&*pchar<='z')

*pchar=*pchar-32;
pchar++;

void main(void) { char str[100]; cin.getline(str,100); change(str);

if(*pchar==0)
break; pchar++; } }

cout<<str<<endl;
}
439

数组名作函数参数
数组名可以作函数的实参和形参,传递的是数组的 内存单元中的数据发生变化,这种变化会反应到主 调函数内。

地址。这样,实参、形参共同指向同一段内存单元,

在函数调用时,形参数组并没有另外开辟新的存储
单元,而是以实参数组的首地址作为形参数组的首

地址。这样形参数组的元素值发生了变化也就使实
参数组的元素值发生了变化。
440

既然数组做形参没有开辟新的内存单元,接受的 只是实参数组的首地址,那么,这个首地址也可 以在被调函数中用一个指针变量来接受,通过在 被调函数中对这个指针变量的指向进行操作而使 实参数组发生变化。

实际上在被调函数中只开辟了 p的空间,里面放的是a的值。 p
实参,在主调函 数开辟的空间 形参,用指针变 量来接受地址
441

a

四、指向多维数组的指针和指针变量
用指针变量也可以指向多维数组,表示的同样是多维数组

的首地址。 int a[3][4]; //首地址为2000H
2000H 2008H 2010H 2014H 201cH 2020H 2028H 202cH a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2]a[1][3] a[2][0] a[2][1] a[2][2] a[2][3]

a 2000H a[0] 2010H a[1] 2020H a[2]

2000H a[0][0] a[1][0] a[2][0]

2004H a[0][1] a[1][1] a[2][1]

2008H a[0][2] a[1][2] a[2][2]

200CH a[0][3] a[1][3] a[2][3]

可以将a数组看作一个一维数组,这个一维数组的每个元素 又是一个具有4个int型数据的一维数组,这样,我们就可 以利用一维数组的概念来标记一些写法。
442

a
2000H a[0] 2010H a[1] 2020H a[2]

2000H 2004H 2008H 200CH a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3]

a[2][0] a[2][1] a[2][2] a[2][3]

a[0]=*(a+0) a[1]=*(a+1) a[2]=*(a+2)

a+0为a[0]的地址&a[0],其值为2000H。 a+1为a[1]的地址&a[1],其值为2010H。 a+2为a[2]的地址&a[2],其值为2020H。

a[0]为一维数组名,其数组有四个int型的元素: a[0][0],a[0][1],a[0][2],a[0][3]

同样,a[0]代表一维数组的首地址,所以,a[0]为&a[0][0] 。 443

a
2000H a[0] 2010H a[1] 2020H a[2]

2000H 2004H 2008H 200CH a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3]

把a[0]看成 一维数组b

a[2][0] a[2][1] a[2][2] a[2][3]

a[0]代表一维数组的首地址,也就是一维数组名,a[0]为 &a[0][0]。 a[0]为&a[0][0] a[0][0]=*(a[0]+0) b[0] = *(b+0) a[0]+1为&a[0][1] a[0][1]=*(a[0]+1) a[0]+2为&a[0][2] a[0][2]=*(a[0]+2) b[1] = *(b+1) b[2] = *(b+2)

a[0]+3为&a[0][3]

a[0][3]=*(a[0]+3)

b[3] = *(b+3)

行 列 a[i][j]=*(a[i]+j) a[1]+2为&a[1][2] a[1][2]=*(a[1]+2) 444

a
2000H a[0] 2010H a[1] 2020H a[2]

2000H 2004H 2008H 200CH a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3]

a[2][0] a[2][1] a[2][2] a[2][3]

行 a[1]+2为&a[1][2] a[1][2]=*(a[1]+2)



a[i][j]=*(a[i]+j)

a为二维数组名,a+1为a[1]的地址,也就是数组第

一行的地址,所以a为行指针。
a[1]为一维数组名,a[1]+1为a[1][1]的地址,也就是 数组第一行第一列的地址,所以a[1]为列指针。
445

a
2000H a[0] 2010H a[1] 2020H a[2]

2000H 2004H 2008H 200CH a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3]

a[2][0] a[2][1] a[2][2] a[2][3]

可以看到:a, a+0 , *(a+0), a[0], &a[0][0]表示的都

是2000H,即二维数组的首地址。
实际上,a[0], a[1], a[2]并不是实际的元素,它们在

内存并不占具体的存储单元,只是为了我们表示方
便起见而设计出的一种表示方式。

a为行指针,加1移动一行。
*a或a[0]为列指针,加1移动一列。
446

a
2000H a[0] 2010H a[1] 2020H a[2]

2000H 2004H 2008H 200CH a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3]

a[2][0] a[2][1] a[2][2] a[2][3]

a[1]=*(a+1)

*(a+1)+2=&a[1][2]

*(*(a+1)+2)=a[1][2] **(a+1)=*(a[1])=*(*(a+1)+0)=a[1][0] (*(a+1))[1]=*(*(a+1)+1)=a[1][1]

*(a+1)[1]=*((a+1)[1])=*(*((a+1)+1))=**(a+2)=a[2][0]
注意二维数组的各种表示法,a为常量。
447

a
1900H a[0] 1910H a[1] 1920H a[2]

1900H 1904H 1908H 190CH a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3]

a[2][0] a[2][1] a[2][2] a[2][3]

int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};

设数组的首地址为1900H,则:
1900H a为_____________ 1920H a+2为_____________ 1900H *a为______________ 1908H *a+2为______________

1918H 1 *(a+1)+2为_____________ **a为_______________
19 1920H *(*a+9)为_____________ (a+1)[1]为_____________ 448

void main(void)

p+1

a[0]+1
p

{ static int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23}; int *p;
a[0]是列指针

for(p=a[0]; p<a[0]+12 ; p++) { if((p-a[0])%4= =0) cout<<endl; cout<<*p<<‘\t’ ; 类型不匹配! } }

a+1

for(p=a; p<a+12 ; p++)
1 9 17 3 11 19 5 13 21 7 15 23

a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] 449 a[2][3]

int a[3][4],*p; 如何用p表示二维数组中的任一元素? p=a[0] p+1 p+2 p+3 p+4 p+5 a[i][j] *p *(a[0]+0) a[0][0]

p a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3]
450

p+2

*(a[0]+1) a[0][1] *(a[0]+2) a[0][2] *(a[0]+3) a[0][3] *(a[0]+4) a[1][0] *(a[0]+5) a[1][1]

p+4

*(p+4*1+0) *(p+4*1+1)

*(p+4*i+j) *(p+m*i+j)

m为第二维的维数。是个常数

fun(int *q1, int *q2, int *q3)
{ *q3=*q2+*q1; } void main ( void)

程序输出的第一行为___ 1

1 第三行为___ 2 第二行为_____ p1 p2 p3 1 1 2 3 5

{ int i , j, a[3][3]={1,1},*p1,*p2,*p3; p1=a[0], p2=a[0]+1,p3=a[0]+2;

for(i=2;i<9;i++)
fun(p1++, p2++, p3++);

for(i=0;i<3; i++)
for(j=0;j<3;j++) { cout<<a[i][j]<<‘\t’; cout<<endl; }

i=2 *q3=2 i=3 *q3=3 i=4 *q3=5

451

指向由m个整数组成的一维数组的指针变量 int (*p)[m];
int (*p)[4], a[4];
指向下一行

a
p p+1

a+1

p+1指针加16个字节。a+1指针加4个字节。

452

int (*p)[4], a[3][4];
a
p p+1
2000H 2004H 2008H 200CH

p+2

a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3]

p为行指针,可以直接将二维数组名a赋给 p。这样,a与p等同。 p=a a[2][3] *(*(a+2)+3)

p[2][3]

*(*(p+2)+3)

两种表示 完全等价

a为常量 p为变量
453

若有以下的定义和语句,则下面各个符号的 正确含义是:
int a[3][4] , (*p)[4];
p=a;
p p+1 p+2

a

2000H

2004H

2008H

200CH

a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3]

1.p+1

a数组第一行元素的首地址

为行指针

2.*(p+2) a数组第二行元素的首地址 为列指针 &a[2][0]

3.*(p+1)+2
4.*(*p+2)

&a[1][2]

为列指针
454

数据元素 *(*(p+0)+2)=a[0][2]

若有以下的定义和语句,则对a数组元素的非 法引用是: int a[2][3], (*pt)[3];
pt=a; 1) pt[0][0] 3) *(pt[1]+2) 2) *(pt+1)[2] 3) *(a[0]+2)

*(pt+1)[2] 右结合性 =*((pt+1)[2]) =*(*(pt+1+2)) =*(*(pt+3))=pt[3][0]

455

多维数组的指针作函数参数 主要注意的是函数的实参究竟是行指针还是

列指针,从而决定函数形参的类型。要求实
参、形参一一对应,类型一致。(举例)

456

求二维数组a[3][4]的平均值。 void main(void) { float score[3][4] = { {65,67,70 ,60}, {80,87,90,81}, {90,99,100,98} }; float sum=0;

for(int i=0;i<3;i++)
for(int j=0;j<4;j++) sum=sum+score[i][j]; cout<<“aver=“<<sum/12<<endl;
457

void main(void) { float score[3][4] = { {65,67,70 ,60}, {80,87,90,81}, {90,99,100,98} }; float aver; aver=fun1(score, 3); aver=fun2(*score, 12); p 161 8.15
458

字符串的指针和指向字符串的指针变量 字符串的表示形式 string l o v e 1、用字符数组实现 I
数组首地址

C h i n a \0

void main(void )
{ char string[ ]=“I love China”;

cout<<string;
} string为数组名,代表数组的首地址,是常量。
459

string I l o v e

C h i n a \0

char string[20]; string=“I love China”; 正确赋值形式 strcpy(string, “I love China”); cin.getline(string); //从键盘输入
460

错误!常量不 能赋值

2、用字符指针表示字符串

void main(void)

指针变量

{ char *string=“I love China”;

cout<<string;
}

字符串常量 I l o v e C h i n a \0

string 将内存中字符串常量的首地址赋给一个指针变量
461

void main(void) { char *string; string=“I love China”;

}

指针变量赋值,合法 具体字符

*string=“I love China”;

char *string;

cin.getline(string); 指针未赋值就作指向运算
462

将字符串a复制到字符串b。 void main(void)
int i; *(b+i)=*(a+i);
a I
I

i=0 *(b+i)=*(a+i)

{ char a[ ]=“I am a boy”, b[20];b[i]=a[i] for(i=0; *(a+i)!=‘\0’; i++) i=2 *(b+i)=‘\0’;
cout<<a<<endl;
a m
a

i=1

a

b o y \0
y \0

cout<<b<<endl;
}

b

必须以\0结束 463

void main(void)
{ char a[ ]=“I am a boy”, b[20]; *p2=*p1

char *p1, *p2;
int i; p1=a; p2=b; for(; *p1!=‘\0’; p1++,p2++) a I a m *p2=*p1; 必须以 \0结束 *p2=‘\0’ ; p1p1 a a+1 cout<<a<<endl; b I cout<<b<<endl; } p2 p2 b b+1 a b o y \0 p1

y \0
p2464

void main(void) { char a[ ]=“I am a boy”, b[20]; char *p1, *p2;

for(; *p1!=‘\0’; )

int i;
p1=a; p2=b; *p2=*p1; *p2=‘\0’; cout<<a<<endl; cout<<b<<endl; for(; *p1!=‘\0’; p1++,p2++)

*p2++=*p1++;
*p2=‘\0’;

while(*p2++=*p1++);
for(; *p2++=*p1++ ; );

for(; 465 ); (*p2++=*p1++)!=‘\0’ ;

以下程序判断输入的字符串是否“回文”,若是回文,输出YES。

void main(void) { char s[81], cr, *pi, *pj; int i, j, n; cin.getline(s); n=strlen(s); s s+n-1 pi=________; pj=________;//pi 指向串开始,pj指向最后 pi++ while(*pi==‘ ‘ ) _________; while(*pj==‘ ‘pj-) ________; pi<pj while( ( ___________) &&(*pi==*pj) ) { pi++; _______; pj-- } if((pi<pj) cout<<“NO”<<endl; else cout<<“YES\n”; } 466

字符串指针作函数参数

将一个字符串从一个函数传递到另一个函数,

可以用地址传递的办法。即用字符数组名作
参数或用指向字符串的指针变量作参数。在 被调函数中可以改变原字符串的内容。

467

将字符串a复制到字符串b。
void main(void)

from
a

to { char a[ ]={“I am a teacher”}; b

char b[ ]={“You are a student”};

copy_string(a , b); from与a一个地址,to与b一个地址
cout<<a<<endl; copy_string( char from[],char to[]) { int i; for (i=0; from[i]!=‘\0’; i++) to[i]=from[i]; to[i]=‘\0’; } 468

cout<<b<<endl;
}

将字符串a复制到字符串b。

copy_string(char *from, char *to)
{ for ( ; *from!=‘\0’; )

for(; *from++=*to++; ) ;
void main(void) }

*to++=*from++; *to=‘\0’; a from

{ char a[ ]={“I am a teacher”};

char b[ ]={“You are a student”};

copy_string(a,b);
cout<<a<<endl; cout<<b<<endl; }

b

to
469

也可以用字符指针来接受数组名

字符指针变量与字符数组

字符数组和字符指针变量都可以实现字符串的存储
和运算,区别在于: 字符数组名是常量,定义时必须指明占用的空间大 小。 字符指针变量是变量,里面存储的是字符型地址,

可以整体赋值,但字符串必须以‘\0’结尾。
470

void fun(char *s)
{ int i, j;

void main(void)

{ char str[80]= for( i=j=0; s[i]!=‘\0’; i++)“hcance”; if(s[i]!=‘c’) fun(str);

s[j++]=s[i];
必须以\0结束 s[j]=‘\0’;

cout<<str<<endl;
}

return;
}

s str h

a c

n a

j i i前进, j i j i jj i 当s[i]等于字符‘c’时, 不动

‘\ e ‘\ n c e 0’ 0’
j i i i

输出:hane

471

void swap(char *s1, char *s2)
{ char t; AD BC

t=*s1; *s1=*s2; *s2=t;
} void main(void) { char *s1=“BD”, *s2=“BC”, *s3=“AB”; if(strcmp(s1,s2)>0) swap(s1,s2);

BB

if(strcmp(s2,s3)>0) swap(s2,s3);
if(strcmp(s1,s2)>0) swap(s1,s2);

cout<<s1<<endl<<s2<<endl<<s3<<endl;

472

有一字符串,包含n个字符。写一函数,将此字符 串中从第m个字符开始的全部字符复制成为另一个 字符串。 void main(void) { char str1[100]={“I am a student”},str2[100]; int m; cin>>m; fun(str1,str2,m); cout<<str2<<endl;
473

}

void fun(char *p1, char *p2, int m)

{ int n=strlen(p1);
if(n<m)

原字符串长度

{ cout<<“No trans\n”;*p2=0; return;} for(int i=m, p1=p1+m-1; i<n;i++) *p2++=*p1++; *p2=‘\0’; return; }
474

从第m个字符开始

函数的指针和指向函数的指针变量 可以用指针变量指向变量、字符串、数组,也可以

指向一个函数。
一个存放地址的指针变量空间可以存放数据的地址 (整型、字符型),也可以存放数组、字符串的地 址,还可以存放函数的地址。 函数在编译时被分配给一个入口地址。这个入口地 址就称为函数的地址,也是函数的指针。像数组一 样,C++语言规定,函数名就代表函数的入口地址
475

专门存放函数地址的指针变量称为指向函数的指针
变量。 函数类型

(*指针变量名)(参数类型 );
空间的内容只能 放函数的地址

同时该函数具有两个整型形参

int (*p)( int, int);
且该函数的返回值为整型数

p

直接用函数名为指针变量赋值。 int max (int x, int y)

p=max;

{ return x>y?x:y;
}

这时,指针变量p中放的是max 函数在内存中的入口地址。
476

函数名max代表函数在内存中的入口地址,是一个

常量,不可被赋值。
而指向函数的指针变量 p 可以先后指向不同的同种 类型的函数。但不可作加减运算。
定义

int (*p)( int , int);

p=max; p=min;

赋值
477

如何用指向函数的指针变量调用函数?
int max(int x, int y)

int max(int x, int y) { return x>y?x:y; } { return x>y?x:y; } void main(void) void main(void) { int a, b, c,max(int,int); 给指针变 { int a, b, c; int (*p)(int, int ); 量赋值 定义指向函数 p=max ; cin>>a>>b; 的指针变量 cin>>a>>b; c=max(a,b); 一般的调 通过指针 c=p(a,b); 用方法 cout<<c<<endl; cout<<c<<endl;变量调用 } } 实际上就是用p替换函数名 c=(*p)(a,b) 478

指向函数的指针变量作函数参数(实现通用函数)

用二分法求方程的解。f1(x)=x2-3

479

二分法求解方程

y
f(x) x2 x2 x0 x0

x2= x0
x0=(x1+x2)/2

x0

x1

x

1、在x轴上取两点x1和x2, 要确保x1与x2之间有且只有方程 唯一的解。 2、做x0=(x1+x2)/2。 3、若|f(x0)|满足给定的精度,则x0即是方程的解,否则, 若f(x0)*f(x1)<0,则方程的解应在x1与x0之间,令x2=x0, 继续做2。同理,若f(x0)*f(x1)>0,则方程的解应在x2与x0 480 之间,令x1=x0,继续做2 ,直至满足精度为止。

用二分法求方程的解。f1(x)=x2-3
float f1(float x)
{return x*x-3;} 已知x求f1(x) 求中值

void main(void) { float x1, x2, x0; do { cout<<“Input two real 输入初值 number\n”; cin>>x1>>x2; }while (f1(x1)*f1(x2)>0); 判断x1与x2之间 是否有方程根

do { x0=(x1+x2)/2; if ( (f1(x1)*f1(x0)) <0 ) x2=x0; 循环迭代 else x1=x0; }while (fabs (f1(x0))>=1e-6); cout<<x0<<endl; } 循环结束条件

481

当求解方程f2(x)=3x2-5x-3时,同样
float f2(float x) {return 3*x*x-5*x-3;} main( ) { float x1, x2, x0; do { cout<<“Input two real number\n”; cin>>x1>>x2; }while (f2(x1)*f2(x2)>0);

do { x0=(x1+x2)/2; if ( (f2(x1)*f2(x0)) <0 ) x2=x0; else x1=x0; }while (fabs (f2(x0))>=1e-6); cout<<x0<<endl;
}

可以看到,虽然算法相同,仅是方程不同,两个程序不能 通用。 可以用指向函数的指针变量,设计相同算法的通用函数。 482

float devide(float (*fun)(float ))

float f1(float x)

{ float x1, x2, x0; 形参用指向函数 {return x*x-3;} do 的指针变量fun float f2(float x) 接受函数名 { cout<<“Input two number\n”; {return 3*x*x-5*x-3;} cin>>x1>>x2; 调用函数, main( ) }while ( fun(x1) * fun(x2) >0); 实参为函 { 用fun调用函 do 数名f1 数,实际调用 float y1,y2; { x0=(x1+x2)/2; 的是实参函数 y1=devide(f1); if ( fun(x1) * fun(x0) <0 ) x2=x0; else x1=x0; y2=devide(f2);

cout<<y1<<‘\t’<< y2;

}while (fabs ( fun(x0) )>=1e-6);
return x0; }

}
483

实参:实际的函数名(函数地址) 形参:指向函数的指针变量 与实参函数的类型完全一致(返回值、参数) 通用函数:所有的内部函数调用都用函数指针调用

484

梯形法求定积分的公式
积分结果为曲线与x轴之间 部分的面积,也即为每份 面积之和。 a+i*h a
b 分成n份,每份长度 h=(b-a)/n f(a)

f(b)

任意一份:高:h
上底:f(a+i*h)

下底:f(a+(i+1)*h)

S=∑[(上底+下底)*高/2]
= ∑[(f(a+i*h)+f(a+(i+1)*h))*h/2]

其中 i=0~(n-1)

a+n*h=b

485

S=∑[(上底+下底)*高/2]

= ∑[(f(a+i*h)+f(a+(i+1)*h))*h/2]
其中 i=0~(n-1) a+n*h=b
(i=1~(n-1))

将上式展开,除f(a),f(b)外,每一底边都参与运算两次,所以有:

S=[ (f(a)+f(b))/2+ ∑f(a+i*h) ]*h y=(f(a)+f(b))/2;

可利用这一公式,计算所有函 初值 数的定积分,也即做成通用公 h=(b-a)/n; 式,具体的函数由指向函数的 for(i=1;i<n;i++) 指针变量来代替,在主调函数 y=y+f(a+i*h); 中为这个指针变量赋值。 486 y=y*h; 计算累加和

float f1(float x)
{ return x*x*x+2*x*x+9; }

pf=f1

float jifen(float (*pf)(float ), float a, float b)
{ y=(pf(a)+pf(b))/2; h=(b-a)/2; for(i=1;i<n;i++) y=y+pf(a+i*h); void main(void)

{ float y;
y=jifen(f1, 1.0, 3.0);

y=y*h;
return y; }

cout<<y<<endl;

}

y2=jifen(f2, 2.0, 5.0);

487

返回指针值的函数 被调函数返回的不是一个数据,而是一个地
址。所以函数的类型为指针类型。
类型标识符 指出返回是什 么类型的地址 *函数名(参数表) int *max(x, y)

488

int *max (int *x, int *y) { int *pt; if (*x>*y) pt=x; else pt=y; return pt; } 用指针类 型接收

void main(void) { int a, b , *p;

cin>>a>>b;
p=max(&a,&b); cout<<*p<<endl; }

返回类型是指针
输出:4

a

2

b

4

p

随机 &b

该指针所指向的空间是在主调 x &a y &b pt &b 函数中开辟的。 489

char *strc(char *str1, char *str2)

{ char *p;

p指向str1的最后 for(p=str1;*p!=‘\0’; p++); do {*p++=*str2++; }while (*str2!=‘\0’); *p=‘\0’; 最后‘\0’结 return (str1); 束 str2向p赋值

}
void main(void) {char s1[80]=“computer”, s2[ ]=“language”, *pt; pt=strc(s1, s2);

computerlanguage
490

cout<<pt<<endl;

s1

c o m p u t e r‘ c o m p u t e r‘ \0’ \0’
p str1 s2 p p

c o m p u t e r‘ \0’
str2 str2

491

已知函数int *f(int *),有以下说明语句:
int *p, *s, a; 函数正确的调用形式是: A) a=*f(s) B) *p=f(s) C) s=f(*p) D) p=f(&a)

492

指针数组和指向指针的指针 指针数组的概念 一个数组,其元素均为指针类型的数据,称为指针 数组。也就是说,指针数组中的每一个元素都是指

针变量,可以放地址。
类型标识 *数组名[数组长度说明] p
p[0] 地址 p[1] 地址 p[2] 地址 p[3] 地址
493

int *p[4]; p为数组名,内有四个元 素,每个元素可以放一 个int型数据的地址 int (*p)[4];

p为指向有四个int型元素的一维数组的行指针

void main(void)
{ float a[]={100,200,300,400,500};

float *p[]={&a[0],&a[1],&a[2],&a[3],&a[4]};
int i; for(i=0;i<5;i++) cout<<*p[i]<<'\t'; cout<<endl; p p+0 *p[i]=*(*(p+i) ) p+1 p+2 p+3 p+4

p数组元素 内放地址
a 100 200 300 400 500 a[0] a[1] a[2] a[3] a[4] 494

}

p[0] &a[0] p[1] &a[1] p[2] &a[2] p[3] &a[3] p[4] &a[4]

void main(void) { int a[12]={1,2,3,...11,12};

a

int *p[4], i;
for(i=0; i<4;i++) p+0 p+1 p[i]=&a[i*3]; cout<<p[3][2]<<endl; p+2 p+3 p[3][2]=*(*(p+3)+2)

p

}

p[0] &a[0] p[1] &a[3] p[2] &a[6] p[3] &a[9] *(p+3) p[3]+1 p[3]+2

1 2 3 4 5 6 7 8 9 10 11 12
495

=*(p[3]+2)
12

常用字符指针数组,数组中的元素指向字符串首地址,这 样比字符数组节省空间。 char *str[ ]={“China”, “Japan”, “America”};
str

str[0] 2000H str[1] 3000H str[2] 3090H

“China” “Japan” “America”

str[1][4] *(*(str+1)+4)
*str[2] **str *(*(str+2)+0) *(*(str+0)+0)

n
A C
496

将若干字符串按字母顺序(由小到大)输出。 void main(void)

{ void sort( );
void print( );

char *alpha[ ]={“Follow me”, “Basic”, “Great Wall”,
“FORTRAN”, “Computer design”}; int n=5; sort (alpha, n); print(alpha, n);
497

void sort(char *alpha[ ], int n) void print(char *alpha[ ], int n) { char *temp; { int i; int i, j, k; for(i=0;i<n;i++) for(i=0;i<n-1;i++) cout<<alpha[i]<<endl; { k=i; } for(j=i+1; j<n; j++) if(strcmp(alpha[k], alpha[j])>0) k=j; 选择法排序 if (k!=i) { temp=alpha[i]; alpha[i]=alpha[k]; “Follow me” alpha[0] alpha[k]=temp; “Basic” alpha[1] } 交换地址 “Great Wall” } alpha[2] “FORTRAN” } alpha[3]

alpha[4]

“Computer design ” 498

指向指针的指针变量
int i,*p;
prt 3000H 5000H p 2000H 3000H i

p=&i;
它。 prt=&p; p=&i int i, *p, **prt;

2000H

同样,p也有地址,可以再引用一个指针变量指向

称prt为指向指针的指针变量。其基类型是指向整
型数据的指针变量,而非整型数据。
499

p=&i; *p=i; **prt=i;

prt=& p;

prt=&i;

prt=p;

非法,基类 型不符
prt 3000H 5000H p 2000H 3000H i 2000H

500

void main(void)
{ a[5]={1,3,5,7,9};

int *num[5]={&a[0],&a[1],&a[2],&a[3],&a[4]};
int **p, i; p=num; p=&num[0]
num a

for(i=0;i<5;i++)

&a[0] p++; &a[1] &a[2] } &a[3] } p=p+1;指向num数组下一个元素 &a[4] 1 3 5 7 9

p { cout<<**p<<‘\t’ ; num

1 3 5 7 9
501

void main(void)

{char *alpha[ ]={“Follow me”, “Basic”, “Great Wall”,
“FORTRAN”, “Computer design”}; char **p; int i; for(i=0; i<5; i++) { p=alpha+i;
alpha alpha+1

alpha[0] alpha[1] alpha[2] alpha[3] alpha[4]

Follow me Basic Great Wall FORTRAN Computer design

cout<<*p<<endl; i=0 p=alpha
} i=1 p=alpha+1

}

502

void main(void) { char *n[4]={“China”, “Japan”, “England”, “Germany”}; n char **p; p

int i;
p=n;

“China” “Japan” “England”

“Germany” 输出:j q

for(i=0; i<4;i++,p++)
cout<<(char) (*(*p+2)+1)<<endl;

}

*(*p+2)+1=*(p[0]+2)+1=p[0][2]+1

h
s
503

以下程序的输出结果是:
char *alpha[6]={“ABCD”,”EFGH”,”IJKL”,”MNO P”, alpha ”QRST”,”UVWX ”}; "ABCD" p alpha[0] char **p; "EFGH" alpha[1] main( ) "IJKL" alpha[2] { int i; "MNOP" alpha[3] p=alpha; "QRST" alpha[4] for(i=0;i<4;i++) "UVWX" alpha[5] cout<<*(p[i]); cout<<endl; *(p[i])=*(*(p+i))=*(*(p+i)+0) } 输出:AEIM 504

以下程序的输出结果是:
char *alpha[6]={“ABCD”,”EFGH”,”IJKL”,”MNO P”, alpha ”QRST”,”UVWX ”}; "ABCD" p alpha[0] char **p; "EFGH" alpha[1] main( ) "IJKL" alpha[2] { int i; "MNOP" alpha[3] p=alpha; "QRST" alpha[4] for(i=0;i<4;i++) "UVWX" alpha[5] cout<<(*p)[i]; (*p)[i] =*(p+0)[i]=p[0][i] cout<<endl; } 输出:ABCD 505

若有以下定义,则下列哪种表示与之等价。 char s[3][5]={“aaaa”,”bbbb”,”cccc”}; A) char **s1= {“aaaa”,”bbbb”,”cccc”}; B) char *s2[3]= {“aaaa”,”bbbb”,”cccc”}; C) char s3[ ][3]= {“aaaa”,”bbbb”,”cccc”};

D) char s4[ ][4]= {“aaaa”,”bbbb”,”cccc”};

506

以下程序调用函数swap_p将指针s和t所指单元(a和b)中的内容交换, 请填空。

int ** void swap_p (______ss, ______tt) int ** { int term; **ss term=_________; ss **tt **ss=_________; &s **tt=term; } tt main( ) &t { int a=10, b=20, *s,*t; s=&a; t=&b; swap_p(&s,&t); printf(“%d %d”,a,b); }

s

a

&a
t

10
b

&b
term

20

507

假设有说明: char *argv[ ]={“hello”, “nanjing”, “jiangsu”}; argv char **pargv=argv; pargv

以下语句的输出结果如何?
cout<<*(pargv+1)<<endl;

“hello” “nanjing” “jiangsu”

cout<<(char)(**pargv+1)<<endl;
cout<<*(*pargv+1)<<endl;

nanjing
i e g
508

cout<<*(*(pargv+2)+4)<<endl;

void main()

{ char *s[]={“1995”,”1996”,”1997”,”1998”};
char **sp[ ]={s+3,s+2,s+1,s}; sp char ss[5]; ss[0]=**sp[0]; ss[1]=*(*sp[1]+1); ss[2]=*(*sp[2]+2);

s
s[0] s[1] s[2] s[3] "1995" "1996" "1997" "1998"

s+3

s+2 s+1 s

ss[3]=*sp[3][3]+6;
ss[4]=‘\0’;

ss 1 9 9 7 0
509

cout<<ss<<endl;

总结:
通过行指针引用二维数组元素
int a[3][4], *p[3], (*pp)[4], **prt;
for(i=0;i<3;i++) p[i]=a[i];

pp

a[0]

pp=a;

p

a

pp+1

a[1]

prt

prt=p; prt+1

prt+2

p[0] p[1] p[2]

8

pp+2

a[2]

a[2][3] *(*(pp+2)+3)

a[2][3] *(*(p+2)+3)

a[2][3] *(*(a+2)+3)
a[2][3] pp[2][3]

a[2][3] *(*(prt+2)+3)
p[2][3] prt[2][3]
510

8

int a[3][4], *p[3], (*pp)[4], **prt;
for(i=0;i<3;i++)

p[i]=a[i];
pp=a;
prt prt+1 prt+2

p

a

prt=p;

p[0] p[1] p[2]

8

a:二维数组名,常量 p:指针数组名,常量 pp:指向具有四个元素的一维数组的指针变量 prt :指向指针的指针变量
511

指针数组作main( )函数的形参
程序是由main( )函数处向下执行的。main函数也可以带参

数。
其它函数由main函数调用的,即在程序中调用的,但main

函数却是由DOS系统调用的,所以main函数实参的值是在

DOS命令行中给出的,是随着文件的运行命令一起给出的。

可执行文件名

实参1

实参2

...... 实参n

可执行文件S9_16.EXE S9_16 CHINA JAPAN 三个形参
512

AMERICAN<CR>

main函数形参的形式:
main( int argc, char * argv[ ])

main( int argc, char **argv)
argc为命令行中参数的个数(包括文件名);

argv为指向命令行中参数(字符串)的指针数组。
S9_16 CHINA JAPAN 文件名 实参1 实参2
argv

AMERICAN<CR>
argv

实参3

argc=4

argv[0] argv[1] argv[2] argv[3]

“S9_16.EXE” “CHINA” “JAPAN” “AMERICA 513 N”

S9_16 CHINA JAPAN 文件名 实参1

AMERICAN<CR>

实参2

实参3
S9_16.EXE CHINA JAPAN
argv

main( int argc, char *argv[ ]) { while (argc>1) { cout<<*argv<<endl; ++argv; --argc; } }
argv

argc=4

argv[0] argv[1] argv[2] argv[3]

“S9_16.EXE” “CHINA” “JAPAN” “AMERICA N”
514

B9_1 Beijing

China<CR>

main(int argc, char **argv )

{

while (argc-- >1)
cout<< *(++argv)<<endl;

Beijing
China

}
argc=3 argc=3 / 2 argc=2 / 1 Beijing China

argv

argv[0] argv[1] argv[2]

“B9_1.EXE” “Beijing” “China”

argc=1
515

小结 1、指针变量可以有空值,即指针变量不指向任何地址。

int *p;
p=0;

#include “iostream.h” #define NULL 0 int *p; p=NULL;

2、两指针可以相减,不可相加。若要进行相减运算,则 两指针必须指向同一数组,相减结果为相距的数组元素个 数 int a[10],*p1,*p2; p2-p1 : 9 p1=a; p2=a+9; 3、指向同一数组的两个指针变量可以比较大小:p2>p1
516

在内存动态分配存储空间 在定义变量或数组的同时即在内存为其开辟了指 定的固定空间。 int n, a[10]; char str[100]; 一经定义,即为固定地址的 空间,在内存不能被别的变 量所占用。

在程序内我们有时需要根据实际需要开辟空间, 如输入学生成绩,但每个班的学生人数不同,一

般将人数定得很大,这样占用内存。
517

#define N ......

100

无论班级中有多少个学

float score[N][5];
cin>>n;

生,程序均在内存中开
辟100×5个实型数空间

for(int i=0;i<n;i++)
for(j=0;j<5;j++)

存放学生成绩,造成内
存空间的浪费。

cin>>score[i][j];
......
518

如何根据需要在程序的运行过程中动态分配存储内存空间? int n; cin>>n;

错误!数组的维数 必须是常量

float score[n][5]; 利用

new 运算符可以在程序中动态开辟内存空间。

new 数据类型[单位数]; new int[4];

在内存中开辟了4个int型的数据空间,即16个字节
519

new int;

在内存中开辟出四 个字节的空间

new 相当于一个函数,在内存开辟完空间后,返

回这个空间的首地址,这时,这个地址必须用一
个指针保存下来,才不会丢失。 int *p; p=new int; *p=6; p 6

new开辟的空间

可以用*p对这个空间进行运算。

520

同样,利用new运算符也可以开辟连续的多个空间(数组)。 int n,* p; cin>>n; p=new int[n];

p
p指向新开辟空间的首地址。

for(int i=0;i<n;i++)
cin>>p[i];

可以用p[i]的形式来引用新开辟的内存单元。

521

注意:用new开辟的内存单元没有名字,指向其首地址的 指针是引用其的唯一途径,若指针变量重新赋值,则用 new开辟的内存单元就在内存中“丢失”了,别的程序也 不能占用这段单元,直到重新开机为止。

int * p, a[4];
p=new int[4];

a

p=a;

p
该段内存由于失去了“名 字”,再也无法引用

new开辟的单元
522

用 new 运算符分配的空间,不能在分配空间时 进行初始化。

同样,用new开辟的内存单元如果程序不“主动”
收回,那么这段空间就一直存在,直到重新开机

为止。
delete 运算符用来将动态分配到的内存空间归还

给系统,使用格式为:
delete p;
523

int *point; point=new int; ...... delete point; 注意:在此期间,point指针不能重 新赋值,只有用new开辟的空间才

能用delete收回。

delete也可以收回用new开辟的连续的空间。
int *point; cin>>n; point=new int[n]; ....... 当内存中没有足够的空间给予

分配时,new 运算符返回空指
针NULL(0)。
524

delete [ ]point;

以下程序求两个数的大者,请填空。 void main(void ) { int *p1, *p2; p1=___________ ; new int p2=___________; new int *p1>>*p2 cin>>_______________; if (*p2>*p1) delete p2; cout<<“max=”<< _______<<endl; *p1
525

*p1=*p2;

main( ) { int *s1, *s2; sub1(&s1,&s2); sub2(&s1,&s2); &s1 cout<<*s1<<‘\t’<<*s2<<endl; sub3(s1, s2); sub4(s1,s2); &s1 cout<<*s1<<‘\t’<<*s2<<endl; p1 } sub1( int **p1, int **p2) { *p1=new int ; *p2=new int ; } sub2(int **p1, int **p2) 20 { **p1=10; **p2=20; **p1=**p2; } 1 sub3(int *p1, int *p2) { p1=new int ; p2=new int ; } sub4( int *p1, int *p2) { *p1=1; *p2=2; *p2=*p1; }

s1

*s1

20
1

526

引用 对变量起另外一个名字 (外号),这个名字称为该 变量的引用。

<类型> &<引用变量名> = <原变量名>; 其中原变量名必须是一个已定义过的变量。如: int max ;
int &refmax=max;

refmax并没有重新在内存中开辟单元,只是引用 max的单元。max与refmax在内存中占用同一地址, 即同一地址两个名字。 527

int max ;
int &refmax=max; max=5 ; refmax=10; refmax=max+refmax;

max 5 10 20 refmax
max与refmax同一地址

528

对引用类型的变量,说明以下几点: 1、引用在定义的时候要初始化。

int &refmax;

错误,没有具体的引用对象
max是已定义过的变量

int &refmax=max;

2、对引用的操作就是对被引用的变量的操作。
3、 引用类型变量的初始化值不能是一个常数。 如:int &ref1 = 5; // 是错误的。 int &ref=i;
529

4、引用同变量一样有地址,可以对其地址进行 操作,即将其地址赋给一指针。 int a, *p;
&是变量的引用 int &m=a; p=&m; &是变量的地址 p &m

a
m

10

*p=10;

530

5、可以用动态分配的内存空间来初始化一个引用变量。
float &reff = * new float ; //用new开辟一个空间,取一个别名reff reff= 200; //给空间赋值

cout << reff ; //输出200
delete &reff; //收回这个空间

这个空间只有别名,但程序可以引用到。
float *p, a;

p=new float;
float a=* new float;

错误!
531

指针与引用的区别:
1、指针是通过地址间接访问某个变量,而引用是 通过别名直接访问某个变量。 2、引用必须初始化,而一旦被初始化后不得再作 为其它变量的别名。

532

当&a的前面有类型符时 (如int &a),它必然是 对引用的声明;如果前面
无类型符(如cout<<&a), 则是取变量的地址。
533

int m=10; int &y=10; int &z;

float &t=&m;

int &x=m;

以下的声明是非法的

1、企图建立数组的引用
2、企图建立指向引用的指针

int & a[9];
int & *p;

3、企图建立引用的引用

int & &px;

534

对常量(用const声明)的引用
void main(void) { const int &r=8; //说明r为常量,不可赋值

cout<<"r="<<r<<endl;
// r+=15; //r为常量,不可作赋值运算

cout<<"r="<<r<<endl;
}
535

引用与函数 引用的用途主要是用来作函数的参数或函数的返回值。
引用作函数的形参,实际上是在被调函数中对实参变量进行操作。 void change(int &x, int &y)//x,y是实参a,b的别名 { int t; t=x; x=y; y=z; } void main(void) a x 3 5 b y 5 3

{ int a=3,b=5;
change(a,b); //实参为变量 cout<<a<<‘\t’<<b<<endl;

t

3

}

输出: 5

3
536

引用作为形参,实参是变量而不是地址,这与指针变量作 形参为指针变量 形参不一样。
形参为整型引用 void change(int *x, int *y) { int t;

void change(int &x, int &y)
{ int t; t=x; x=y; y=z;

t=*x; *x=*y; *y=z;
} void main(void) { int a=3,b=5; change(&a,&b); //实参为地址 cout<<a<<‘\t’<<b<<endl; } a 3 5 3 b 5 3 &b

}
void main(void) { int a=3,b=5;

change(a,b); //实参为变量
cout<<a<<‘\t’<<b<<endl; }

x &a t

y

537

void dd(int &x, int &y, int z)

{

x=x+z;
y=y-x; z=10;

x=8 y=-4

x=13 y=-17

z=10

z=10

cout<<“(2)”<<x<<‘\t’<<y<<‘\t’<<z<<en dl; (2) 8 -4 10 void main(void) } (2) 13 -17 10 { int a=3,b=4,c=5; (1) 13 -17 5 for(int i=0;i<2;i++) dd(a,b,c); cout<<“(1)”<<a<<‘\t’<<b<<‘\t’<<c<<endl; 538 }

void f1( int *px) { *px+=10;}
void f2(int &xx) { void main(void) { int x=0; cout<<"x="<<x<<endl; f1(&x); cout<<"x="<<x<<endl; f2(x); cout<<"x="<<x<<endl; x=0 x=10 x=20 xx+=10;}

}

539

函数的返回值为引用类型
可以把函数定义为引用类型,这时函数的返回值 即为某一变量的引用(别名),因此,它相当于 返回了一个变量,所以可对其返回值进行赋值操 作。这一点类同于函数的返回值为指针类型 。

540

int a=4;

int &f(int x)
{ a=a+x;

函数返回a的引 用,即a的别名

return a;
} void main(void)

{ int t=5;
cout<<f(t)<<endl;

输出 9

(a=9)

f(t)=20;
cout<<f(t)<<endl; t=f(t);

先调用,再赋值 a=20
输出25 (a=25)

先调用,再赋值 t=30
541

cout<<f(t)<<endl; } 输出60 (a=60)

一个函数返回引用类型,必须返回某个类型的变 量。 语句:getdata()=8;

就相当于 int &temp=8;
temp=8 ; 注意:由于函数调用返回的引用类型是在函数运 行结束后产生的,所以函数不能返回自动变量和 形参。 返回的变量的引用,这个变量必须是全局变量或 静态局部变量,即存储在静态区中的变量。 542

我们都知道,函数作为一种程序实体,它有 名字、类型、地址和存储空间,一般说来函 数不能作为左值(即函数不能放在赋值号左 边)。但如果将函数定义为返回引用类型, 因为返回的是一个变量的别名,就可以将函 数放在左边,即给这个变量赋值。

543

int &f(int &x) { static int t=2; t=x++; return t; } void main(void) { int a=3; cout<<f(a)<<endl; f(a)=20; a=a+5; cout<<f(a)<<endl; a=f(a); cout<<f(a)<<endl; }

输出 3 a=4 t=3 t=20 a=5 a=10 输出 10 a=11 a=11

输出 11 a=12
544

const类型变量 当用const限制说明标识符时,表示所说明的数据类型为常量类型。 可分为const型常量和const型指针。 可用const限制定义标识符量,如: const int MaxLine =1000; const float Pi=3.1415926 用const 定义的标识符常量时,一定要对其初始化。在说明时进 行初始化是对这种常量置值的唯一方法 ,不能用赋值运算符对 这种常量进行赋值。如: MaxLine =35;

545

const 型指针
1)禁写指针 声明语句格式为: 如:int r=6; int * const pr=&r; 则指针pr被禁写,即pr将始终指向一个地址,成为一个指针常量。 它将不能再作为左值而放在赋值号的左边。(举例说明) 同样,禁写指针一定要在定义的时候赋初值。 虽然指针被禁写,但其间接引用并没有被禁写。即可以通过pr对 r赋值。*pr=8;
546

数据类型

* const 指针变量名

void main(void) { int a,b;

int *const pa=&a; //一定要赋初值,pa是常量,不能在程序中 //被改变
*pa=10; //可以间接引用

pa=&b;
}

//非法,pa为常量
pa &a 10

a
b

547

2)禁写间接引用 声明语句格式如下: const 数据类型 *指针变量名; 所声明的指针指向一禁写的实体,即间接引用不能被改写。如: const int *p;

所以程序中不能出现诸如 *p= 的语句,但指针p并未被禁写, 因而可对指针p进行改写。

548

void main(void)

{
int a=3,b=5; const int *pa=&b; pa=&a; //可以不赋初值

//指针变量可以重新赋值

cout<<*pa<<endl; //输出3

*pa=10;
a=100;

//非法,指针指向的内容不能赋值
//变量可以重新赋值

cout<<*pa<<endl; //输出100 } 即不可以通过指针对变量重新赋值
549

3)禁写指针又禁写间接引用 将上面两种情况结合起来,声明语句为下面的格式 const 数据类型 *const 指针变量名

如:const int *const px=&x
说明:px是一个指针常量,它指向一禁写的实体,并且指针本 身也被禁写,诸如:px= *px= 此类的语句都是非法的。 在定义时必须赋初值。

550

用指针处理链表 一、链表概述
head 2000H 2000H 3000H 3050H 6000H 2090H

A
3000H

B
3050H

C
6000H

D
2090H

B
‘\0’

链表是由一个个结点组成,每一个结点是一个结构体类型 的变量,各个结点的类型相同,但其地址不一定连续。具

体结点的个数根据需要动态开辟。 每个结点由两部分组成,第一部分放若干数据,第二部分
是指针变量,放下一结点的地址。链表头是一指针变量, 放第一个结点的地址,若结点的第二部分的值为NULL,表 示此链表结束。
551

二、如何处理链表
1、建立链表 #define STU struct student

链表结点的结构:
struct student

STU
{ int num;

{ int num;
float score;

float score;
STU *next;

struct student *next;
} ; 指向同一结构体 类型的指针变量

};
指向同一结构体类 型的指针变量
552

struct student { int num;
p

num 10 score 90 next

float score;
struct student *next; };

struct student *p; //定义了结构体类型的指针 p=new student; //用new开辟一结构体空间,将地址赋给p p->num=10; //为新开辟的结构体空间中的num成员赋值 p->score=90;
用指针引用结 构体内的成员

(*p).num
553

head p1 p2

2000H
A A

p2 p1

3000H
B B

p2 2090H p1 p1 C C

6000H

D

3000H

2090H

‘\0’

1、首先定义两个结构体类型的指针 STU *p1, *p2;

2、用new在内存中开辟一个结构体变量的空间,将地址赋给p1。
p1=new student; /* STU struct student */ 3、将数据赋给刚开辟的变量空间。 cin>>p1->num>>p1->score; 4、若输入的数据有效,将首地址作为链表头,head=p1; 令p2=p1,p1继续用new开辟新的 内存空间。 p1=new student; /* STU struct student 5、将下一个数据赋给新开辟的变量空间。 cin>>p1->num>>p1->score; 6、若输入的数据有效,将p2与p1连接起来,p2->next=p1 再令p2=p1,p1继续用new开辟 新的内存空间。做5。若输入的数据无效,p2就是链表的尾,则p2->next=NULL。 554 */

head p1 p2

2000H
A A

p2 p1

3000H
B B

p2 2090H p1 p1 C C

6000H

D

3000H

2090H

‘\0’

555

STU *p1, *p2, *head; head=NULL; p1=p2=new student; cin>>p1->num>>p1->score; if (p1->num!=0) 第一结点 head=p1;

p1=new student; cin>>p1->num>>p1->score; if (p1->num!=0) { p2->next=p1; p2=p1;} 第二结点

p1=new student; cin>>p1->num>>p1->score; if (p1->num= =0) p2->next=NULL; return (head); 最后结点 返回链表头

p1=new student; cin>>p1->num>>p1->score; if (p1->num!=0) { p2->next=p1; p2=p1; }第三结点

556

STU *creat( ) { STU *head, *p1,*p2; n=0; n为全局变量,表示结点数 head=NULL; p1=p2=new student; cin>>p1->num>>p1->score; while (p1->num!=0) { n=n+1; if (n= =1) head=p1; else p2->next=p1; p2=p1; 开辟新结点 p1=new student; cin>>p1->num>>p1->score; } 向新结点输入数据 p2->next=NULL; return(head); 不满足输入条件,结束 }

557

head

2000H

3000H

3050H

6000H

2090H

A
3000H

B
3050H

C
6000H

D
2090H

B
‘\0’

2、输出链表 void print(STU * head) { STU *p; p=head; 输出数据 { cout<<p->num<<‘\t’<<p>score<<‘\n’; p指向下一结点 p=p->next; } }
558

while(p!=NULL)

3、删除链表 p2 2000H
head p1

A
3000H

p2 3000H p1 B 6000H 2090H

p1

6000H

2090H

D
2090H

B
‘\0’

1、首先定义两个结构体类型的指针 STU *p1, *p2;
2、将链表的表头赋给p1, p1=head; 3、判断p1所指向的结点是否是要删除的结点 p1->num a1。

4、若p1->num!=a1, p2=p1; p1指向下一个结点p1=p1->next,继续判断 下一个结点是否是要删除的结点。继续做3。
5、若p1->num= =a1,则p1当前指向的结点就是要删除的结点,将 p2的指针成员指向p1所指的下一个结点。 p2->next=p1->next; 这样就删除了一个结点。
559

特殊情况: 1、若链表为空链表,返回空指针。 2、删除的结点为头结点时,head指向下一个结点 3、链表内没有要删除的结点,返回提示信息。

560

struct student *del(struct student * head, int num) { struct student *p1,*p2; 链表为空 if (head= =NULL) { cout<<“list null\n”; return NULL;} p1=head; while (num!=p1->num&&p1->next!=NULL) { p2=p1; p1=p1->next; } 未找到结点,循环 if(num= =p1->num) 找到结点 { if (num= =head->num) head=p1->next; else p2->next=p1->next; 结点为第一个 n=n-1; } else cout<<“Not found\n”; return head; 循环结束,没有要找的结点 } 561

4、插入结点:要插入结点的链表是排序的链表。插入10。 p2 2000H p2 3000H 6000H 2090H p1 head 7 12 28 3 p1 2090H ‘\0’ 3000H p1 6000H 7000H 7000H p0 10
6000H 1、定义三个结构体指针变量 STU *p1,*p2,*p0; p0指向要插入的结 点。p1=head; 2、比较p1->num 与p0->num,若p1->num<p0->num,p2=p1; p1=p1->next; 继续比较。

3、若p1->num> =p0->num,p0应插在p1与p2之间,则p2->next=p0 ; p0->next=p1;
562

特殊情况:

1、若链表为空链表,将插入结点作为唯一的结点, head=p0;返回。 2、若插入结点中的数据最小,则插入的结点作为 头结点。
p0->next=head;

head=p0;

3、插入到链尾,插入结点为最后一个结点。
p2->next=p0;
p0->next=NULL;
563

STU *insert(STU * head, STU * stud)
{ STU *p0,*p1,*p2; p1=head; p0=stud; 链表为空 if (head= =NULL) { head=p0; p0->next=NULL;} else while((p0->num>p1->num)&&(p1->next!=NULL)) { p2=p1; p1=p1->next; } 未找到结点,循环 if (p0->num<=p1->num) { if (head= =p1) head=p0; 插入在第一个结点前 p2->next=p0; 找到结点 else p0->next=p1; } 插入在最 else {p1->next=p0; p0->next=NULL;} 后一个后 n=n+1; return (head); 564 }

void main(void) 变量,固定空间 cout<<“Input the inserted record:\n”; { STU *head, stu; cin>>stu.num>>stu.score; int del_num; 建立链表 head=insert(head, &stu); head=creat( ); print(head); print(head); 打印链表
cout<<“Input the deleted number:\n”;

cin>>del_num;
head=del(head,del_num); 删除结点 print(head); cout<<“Input the inserted record:\n”; cin>>stu.num>>stu.score; head=insert(head, &stu); 插入结点 print(head); }

565

2000H
head

3000H

6000H

2090H

3
3000H

7
6000H 7000 7000H stu

12
2090H

28
‘\0’

10
6000H

566

void main(void) { STU *head,*stu; int num; 指针,可以赋值 ...... cout<<“Input the inserted record:\n”; stu=new student; 如果要插入结点,动态开辟新结点 cin>>stu->num>>stu->score; while (stu->num!=0) { head=insert(head, stu); print(head); cout<<“Input the inserted record:\n”; 重新开辟空间 stu=new student; cin>>stu->num>>stu->score; } } 567

用typedef定义类型 typedef定义新的类型来代替已有的类型。

typedef
typedef

已定义的类型
float REAL

新的类型

REAL x, y;

float x, y;

1、typedef可以定义类型,但不能定义变量。

2、tyoedef只能对已经存在的类型名重新定义一个类型名, 而不能创建一个新的类型名。 typedef struct student { int i; int *p; } REC; REC x, y, *pt;

struct student x, y, *pt;
568

typedef char *CHARP;
CHARP p1,p2; char *p1, *p2;

typedef char STRING[81];
STRING s1, s2, s3; char s1[81], s2[81],s3[81]; char STRING[81]; char STRING[81]; s; STRING

1、先按定义变量的方法写出定义体 char s[81];
2、把变量名换成新类型名 3、在前面加typedef 4、再用新类型名定义变量 #define REAL float typedef

编译前简单替换

typedef:编译时处理,定义一个类型替代原有的类型。
569



更多相关文章:
文件处理-信息学竞赛、C++编程初学者
文件处理-信息学竞赛、C++编程初学者_学科竞赛_高中教育_教育专区。信息学竞赛、C++编程初学者 Q:用 dev C++ 编辑, 从记事本文件读入一列数据, 未知个数, 但是...
西南交通大学C++上机实验答案(2014版)
西南交通大学C++上机实验答案(2014版)_工学_高等教育...某台计算机的编号和该计算机的价格,并输出这些信息。...的编程思路和方 法; 2.掌握循环结构的程序设计,...
C++编程 简单学生信息系统
C++编程 简单学生信息系统 暂无评价|0人阅读|0次下载...{ 2 专业信息"<<endl; 基本信息 2 课程信息"<<...0; } } 输入学生信息 查询学习信息 修改学生信息 ...
noip信息学奥林匹克竞赛初赛阅读程序题c++版本真题练习
noip信息学奥林匹克竞赛初赛阅读程序题c++版本真题练习_学科竞赛_小学教育_教育专区。noip信息学奥林匹克竞赛初赛阅读程序题c++版本。...
信息学C++基础
信息学C++基础 暂无评价|0人阅读|0次下载|举报文档信息学C++基础。C++ 信息学奥林匹克 目 录 第 2 章 C++编程简介 ... 5 2.1 2.2 2.3 2.4 2.5 2...
2013级中山大学信息科学与技术学院计算机科学系《C++程序设计二》期末试卷B及答案
2013级中山大学信息科学与技术学院计算机科学系《C++程序设计二》期末试卷B及答案_工学_高等教育_教育专区。警示 《中山大学授予学士学位工作细则》第六条 考试作弊...
C++课程设计——学生信息管理系统
课程设计说明书 题学班 目: 学生信息管理系统 院: 信息工程学院 级:软件 09...象程序设计的思路和方法; 基本具有利用面向对象的方法以及 C++编程思想来完成...
南京信息工程大学 C++面向对象程序设计—课程设计报告
实施本系统不仅可以减少学 生信息管理部门的工作人员数量,降低成本,而且可以大大...回顾起此次课程设计,至今我仍感慨颇多,的确,自从拿到题目到完成整个 编程,从...
C++实现:简单的学生信息管理系统(控制台程序)
C++实现:简单的学生信息管理系统(控制台程序)_工学_高等教育_教育专区。功能...---以上是基本数据结构的定义, 同时定义了对数据的基本操作。 定义完毕了, 接...
C++学生信息管理系统
c++实现一个学生管理系统的设计,利用所学的 c++知识...的开发,学会在软件开发中用软件工程的 方法和基本...3、加深理解多文档编程的思想,掌握对各个源文件进行...
更多相关标签:
c 编程基础    c语言编程基础    c语言基础编程题    c语言编程基础知识    c 基础考试编程题    c 基础编程题    c 游戏编程基础    c语言基础编程练习题    

All rights reserved Powered by 甜梦文库 9512.net

copyright ©right 2010-2021。
甜梦文库内容来自网络,如有侵犯请联系客服。zhit325@126.com|网站地图