第七章 结构与联合
7.1 结构的定义(P195)struct Person { //个人资料、结构体
char name[10]; //数据成员 姓名
bool sex; //性别
int age; //年龄
float pay; //工资
};
7.2.1 用结构类型名定义变量格式举例(P198)
struct Arith {
char op;
int a,b;
};
设整型变量
int xx=40;
可定义结构变量如下:
Arith x,y; //x,y为Arith型结构变量
Arith z1={'+',10,xx},z2={'*',60},z3=z1;
动态变量
Arith *p=new Arith;
动态数组
Arith *p=new Arith[n];
7.2.2 定义结构类型的同时定义变量(P200)struct AAA {
char s[20];
int top;
}a1={"MicroSoft",0},a2=a1,*ap;
7.2.3 定义无名结构类型的同时定义变量(P200)struct BBB {
char name[10];
struct { //无名结构
int yy,mm,dd; //无名结构的成员
}birth; //无名结构变量
}bx={"xxk",{55,3,27}};
7.3 结构成员的访问操作
结构变量运算符(P201)
结构变量用(=)、(.)、(->)运算符访问结构的成员。
赋值运算符(=)、直接成员运算符(.)、间接成员运算符(->)。
例如:x.a; //x中的成员变量a
vec[5].name; //vec[5]元素的成员变量name
例7.1 人员记录的结构
struct Person { //个人资料、结构体
char name[10]; //数据成员 姓名
bool isMale; //性别
int age; //年龄
fooat pay; //工资
};
设计程序用结构数组存储人员记录
14: Peson a[MaxPersons];
20: Peson x;
22: cin>>x.name;
38: cout<<a[i].name;
7.4 结构与函数
结构类型作为函数的参数类型和返回值。(P211)
例7.5 按学号查找学生记录的结构数组。
s[i].num:s数组元素i结构成员(学号)
x.num:x结构成员(给定学号)
4:stuct Student{...}; //学号、姓名、成绩
6:int search(Student s[ ],int n,Student x)
//s数组,元素个数,给定x结构(学号、姓名、成绩)
10:if(strcmp(s[i].num,x.num)= =0)
11:return i
15:void main( )
17:Student a[5]={{"ch231","王广敏",69},...};
21:Student x={"ch231"};
22:int k=search(a,5,x);
23:if(k>=0)
24: cout<<a[k].num;
7.5 结构与链表(P215)
| 表头 指针f |
表头结点 无前驱结点 |
-> | 前驱结点 | -> | 结点 | -> | 后继结点 | -> | 最后结点 无后继结点 |
/ | ||||
| 值域 data |
指针域 next |
值域 data |
指针域 next |
值域 data |
指针域 next |
值域 data |
指针域 next |
值域 data |
||||||
| 48 | 指下一 结点 |
56 | 指下一 结点 |
72 | 指下一 结点 |
80 | 指下一 结点 |
83 | ||||||
链表:通过指针域把结点依次链接起来。
7.6 结构与操作符重载
1.操作符重载(P220)
系统定义了基本数据类型的操作符,例如:整型的+,>>,<<。
重载函数自定义的数据类型的操作符,例如:分数的+,>>,<<。
例7.9 用常规函数对分数相加。
1.分数相加 n1/d1+n2/d2=(n1*d2+n2*d1)/d1*d2
2.辗转相除法求最大公约数,例如:求450,105的公约数
r=m%n=450%105=30
r1=n%r=105%30=15 (最大公约数)
r2=r%r1=30%15=0
3.求最大公约数的程序段分析
| 分数 | nume/deno | x | 赋值 | 辗转相除 |
| 分子 | nume | x.nume | m=x.nume | m=n |
| 分母 | deno | x.deno | n=x.deno | n=r 公约数 |
| 余数 | r | m%n | n%r r=0 |
4:struct Fraction{ //分数类型
5: int nume; //分子
6: int deno; //分母
9:void FracSimp(Fraction &x)
12: int m,n,r;
13: m=x.nume;n=x.deno;
14: r=m%n;
15: while(r!=0){
17: m=n;n=r;
18: r=m%n;
20: 化简x 除n
34: Fraction FracAdd(const Fraction &a,const Fraction &b){
36: Fraction c;
37: c.nume=a.nume*b.deno+b.nume*a.deno; //分子
38: c.deno=a.deno*b.deno; //分母
39:FracSimp(c);
69: void main( ){
71: Fraction a,b,c;
74: c=FracAdd(a,b);
例7.10 用重载操作符函数对分数相加(P224)
13: Fraction operator +(const Fraction &a,const Fraction &b){
15: Fraction c;
16: c.nume=a.nume*b.deno+b.nume*a.deno; //分子
17: c.deno=a.deno*b.deno; //分母
18:FracSimp(c);
64: void main( ){
66: Fraction a,b,c;
68: c=a+b;
7.7 联合
7.7.1 联合的定义和访问
1.结构定义(P231)
struct stype{
char ch;
int gr;
int * pt;
double db;
};
结构变量:stype x;
结构对象x的存储空间:1+4+4+8=17
同一时刻可访问结构中的所有成员,结构成员可顺序初始化。
2.联合定义(P231)
union utype{
char ch;
int gr;
int * pt;
double db;
};
联合变量:utype y;
联合对象y的存储空间:max(1+4+4+8)=8
同一时刻只可访问联合中的一个成员,
联合成员只可初始化第一个数据成员。
3.匿名联合(P232)
在联合类型定义中,不给类型名和变量,
联合中的成员可直接使用。
例如:struct ABC {
char ch;
union { //不给类型名
int ia; //匿名联合中的数据成员
float fa; //可作为结构ABC的成员直接使用
}; //不给变量
ABC * pa;
} x,*px=&x;
7.7.2 使用联合举例
例7.12 用数组保存职工记录(P232)
| 类别
(kind) |
职级
(匿名联合类型union) |
| 1干部 | 局级(juji) |
| …… | |
| 科员(keyuan) | |
| 2教师 | 教授(jiaoshou) |
| 副教授(fujiaoshou) | |
| …… | |
| 3工人 | 1级 |
| …… | |
| 8级 |
struct Workers { //职工记录类型
char num[6]; //编号:01001--12020
char name[12]; //姓名
char sex; //性别:m,f
short kind; //类别:1,2,3
union { //职级
char cadre[8]; //干部职级:科员(keyuan)
char teacher[12]; //教师职级:副教授(fujiaoshou)
short worker; //工人职级:1~8级
};
};
//向结构数组a中输入n个职工记录(P234)
void Input(Workers a[ ],int n) {
for(int i=0;i<n;i++){
cin>>a[i].num>>a[i].name>>a[i].sex;
cin>>a[i].kind;
switch(a[i].kind){ //根据类别输入的职级
case 1:
cin>>a[i].cadre;
break;
8.1 类的定义
8.1.1 类的定义格式(P245)
1.数据类型
| 基本数据类型 | 整型、字符型、枚举型、实型、符号常量、常值变量 |
| 数组 | 一维数组、二维数组、字符数组、字符串 |
| 其它类型 | 指针、结构、联合、类 |
2.结构有数据成员,类增加了函数成员。
| 数据类型 | 属性 | 行为(操作) | 定义变量 |
| 结构struct | 数据成员公有public | 无 | 结构变量 |
| 类class | 数据成员私有private | 成员函数 | 对象 |
8.1.2 定义格式举例(P245)
1. struct CA{ //结构
int a; //数据成员公有
int b;
}ax; //定义变量ax
2. class CB{ //类
int a; //数据成员私有
int b;
}bx; //定义对象bx
3. class CC{ //类
int a; //数据成员私有
public: //函数成员公有
void Init(int aa){a=aa};
int GetData( ){return a;}
}cx; //定义对象cx
对象用(.)运算符访问类的成员。
赋值:cx.Init(x)--Init(int aa)--a=aa;
取值:cx.GetDAta--a--cx.a;
4. class CD{ //类
char * a;
int b; //数据成员私有
public: //函数成员公有
void Init(char *aa,int bb){ //初始化 a,b
a=new char[strlen(aa)+1];
strcpy(a,aa);
b=bb;
}
char * Geta( ){return a;} //取数 a,b
int Getb( ){return b;}
void Output( ){cout<<a<<' '<<b<<endl;} //显示 a,b
}dx; //定义对象dx
5.取最大数(P247)
| 三个数 | a=3 | b=5 | c=7 |
| 取最大数 | d=5 | c=7 | |
| 取最大数 | e=7 | ||
class CE{
private:
int a,b;
int getmax( ){return(a>b ? a:b);}
public:
int c;
void SetValue(int x1,int x2,int x3){ //置数
a=x1;
b=x2;
c=x3;
}
int GetMax( ){
int d=getmax( );
return (d>c? d:c);
}
} ex,*ep=&ex;
8.1.3 类的定义与使用说明(P248)
1.对象操作(访问类成员):外部访问—公有成员—私有成员。
2.类成员能访问类中的其它成员。
3.this指针:类成员函数中有所属类的指针参数。
this:指向类对象的指针,* this:类对象本身。
1.成员函数放在类外定义(P249)
class CE{
private:
int a,b;
int getmax( ); //成员函数声明
public:
int c;
void SetValue(int x1,int x2,int x3);
int GetMax( );
} ex,*ep=&ex;
int CE::getmax( ){return(a>b? a:b);}
类用(::)运算符访问类的成员。
类CE的(:: 类区分符)成员函数getmax( )放在类外定义
2.类定义:含成员函数原形,存放在头函数.h中;(P250)
类实现:成员函数在类外定义,存放在程序文件.cpp中
用户只管成员函数调用格式和功能,不用管其实现。
例8.1 用类来实现分数的定义和有关运算(P251)
3: class Fraction{ //分数类
4: int nume; //分子
5: int deno; //分母
6: public:
7:void FracSimp( ){ //把*this化简为最简分数
8: int m,n,r;
9: m=x.nume;n=x.deno;
10: r=m%n;
11: while(r!=0){
12: m=n;n=r;
13: r=m%n;
36: Fraction operator +(Fraction &x){
//返回两个分数*this(nume/deno)和x(x.nume/x.deno)之和
39: Fraction c;
40: c.nume=a.nume*b.deno+b.nume*a.deno; //分子
41: c.deno=a.deno*b.deno; //分母
42:c.FracSimp( );
71: void main( ){
73: Fraction a,b,c; //类对象a,b,c
74: a.InitFraction(7,12); //用类对象a的成员函数赋初值
77: c=a+b;
8.2 构造函数
1.构造函数(P254)
与类同名,为类对象中的数据成员赋初值,公用成员。
例8.2 数组大小可在定义Array的对象时指定,
数组空间由调用程序提供。
4:class Array{ //定义数组类
int * a; //定义指向整型数组的指针
int n; //定义数组长度
7:public:
Array( ) {a=NULL;n=0;} //无参构造函数,构造空数组
10:Array(int aa[ ],int len) {n=len;a=aa;}
//有参构造函数,构造指向aa数组
8.2.2 拷贝构造函数
1.拷贝构造函数(P259)
构造函数的参数为同类对象引用。通过调用拷贝构造函数,
可定义与已有对象相同的对象。
例如:class A { }a;
A b(a); //或 A b=a;
调用A的拷贝构造函数,以对象a作为初值初始化对象b。
2. 系统默认的拷贝构造函数(P259)
例如:X(X &x){ //引用形参x 类X,对象x
* this=x; //把x对象空间的内容拷贝到当前对象空间
}
8.2.3 赋值操作符的重载(P261)
8.3 析构函数(P262)
1. 析构函数与类同名,函数名前加(~)号。
2. 构造函数是对象生成时调用。析构函数是对象撤消时调用,
用来删除对象中由指针成员指向的动态分配的存储空间。
例如:~Array( ) {delet [ ]a; }
3. 类X的默认析构函数 ~X( ) { }
8.4 友元函数和友元类(P265)
1. 把类A外的函数B或类B说明为友元函数和友元类,
函数B或类B可以直接访问类A的私有成员。
8.5 类的继承(P272)
1.基类:被继承类、父类,例如:建筑物。
2.派生类:继承类、子类,继承父类的数据成员和函数成员,
例如:房屋、桥梁。
8.5.1 派生类定义的格式(P272)
1. 定义派生类的格式:
class 派生类名:基类表{成员表};
继承基类操作符:(:)
例如:class PXL : JLB {private: ; public: ;}
2. 派生类包括(P273)
继承基类的私有成员、保护成员、公有成员;
新定义的私有成员、保护成员、公有成员。
8.8 模板类(P293)
1.模板函数:带类型参数的函数。
模板类:带类型参数的类。
模板结构:带类型参数的结构。
例:用实参类型int代替模板类TT
#include<iostream.h>
template<class TT> //模板类TT,实际类型由实参决定
class FF{
TT a1,a2,a3; //TT当已定义的类型
public:
FF(TT b1,TT b2,TT b3){
a1=b1;a2=b2;a3=b3;
}
TT sum( ){return a1+a2+a3;}
};
void main( ){
FF<int>x(2,3,4),y(5,7,9); 用实参类int代替模板类TT
cout<<x.Sum( )<<' '<<y.Sum( )<<endl; //输出:9 21
9.1 C++流的概念
9.1.1 C++流的体系结构(P307)
1. 数据的输入和输出(I/O)包括:
标准输入和输出(标准I/O):键盘和显示器;
文件输入和输出(文件I/O):磁盘;
字符串输入和输出(串I/O):内存字符串存储空间。
2. I/O类的继承关系
输入(i)、输出(o)、文件(f)、
字符串(string)、流(stream)、基类(base)。
| 基类 ios |
|||
| 输入流 istream |
文件流基类 fstreambase |
字符串流基类 strstreambase |
输出流 ostream |
| 输入文件流 ifstream |
输出文件流 ofstream |
输入字符串流 istrstream |
输出字符串流 ostrstream |
| 输入输出流 iostream |
文件流 fstream |
字符串流 strstream |
输入输出流 iostream |
3. I/O 类库:iostream.h, fstream.h, strstrea.h
9.1.2 预定义流对象(P309)
cin标准输入,cout标准输出
9.1.3 提取操作符>>和插入操作符<<
键盘 cin>>内存>>cout 显示器
从键盘提取数据流到内存,把内存数据流插入到显示器。
9.2.2 输入输出的数制状态控制
1.设置数制状态操纵符(P313)
dec十进制, oct八进制, 十六进制hex。
9.2.3 输入输出的宽度控制(P314)
setw(in n)
9.2.8 填充字符(P316)
setfill(char c)
9.2.11 插入换行符(P316)
endl ('\n')
9.2.12 插入字符串结束符(P317)
ends ('\0')
9.2.15 跳过前导空白字符(P317)
ws
9.3 文件操作(P319)
| 名称 | 形式 | 特点 |
| 文本文件 数值2577 |
字符文件(ASCII码) 4个字节 32 35 37 37H 二进制 0011 0010B |
有格式适合显示打印, 可读字符 |
| 二进制文件 数值2577 |
字节文件(二进制数) 短整型,2个字节 0000 1010 0001 0001B 0A 11H |
无格式适合数据处理, 速度快 |
| 内存文件 | 字节文件(二进制数) | 文本文件数值2577 要经ASCII码转换成 内存的二进制数 |
9.3.3 文件流状态判定(P323)
is_open 流对象与打开文件联系?
dood( ); 操作成功;
fail( ); 操作失败;
bad( ); 非法操作;
eof( ); 文件尾;
9.4 字符串流(P337)
1. 字符串流类定义在strstrea.h中,
包括:输入字符串流(istrstream),
输出字符串流类(ostrstream),输入输出字符串流类(strstream)
2. 文件有文件结束符标志,
字符串流对应的字符数组由用户规定结束符。
1.数据类型
| 基本数据类型 | 整型、字符型、枚举型、实型、符号常量、常值变量 |
| 数组 | 一维数组、二维数组、字符数组、字符串 |
| 其它类型 | 指针、结构、联合、类 |
2.操作符
| 操作符 | 举例 | 页 |
| 一元操作符:取正(+)、取负(-) | +3,-4 | 27 |
| 单目操作符:增1(+ +)减1(- -) | i++ | 29 |
| 二元操作符:加(+)、减(-) | k+=3 | 29 |
| 三目操作符:(?:) | y=x>10?33:3 | 40 |
| 逗号操作符:(,) | x=(i++,j); | 44 |
| 取地址操作符:(&) | p=&k; | 148 |
| 间接访问操作符:(*) | y=* px | 148 |
| 访问结构成员操作符:(.) | x.a | 201 |
| 访问对象成员操作符:(.) | cx.Init(x) | 247 |
| 访问类成员操作符:(::) | int CE::getmax( ) | 249 |
| 继承基类操作符:(:) | class Y:X{ } | 272 |
| 提取操作符:(>>) | cin>>x | 311 |
| 插入操作符:(<<) | cout<<x | 311 |
二、填空题
2. 'A'的ASCII码65
ch=14*5+2;
ch=72-65;
距离‘A’7个字符是‘H’。
7. * p=25;
*(p+1)=46;
(* P)++; * p的值25+1=26
而*(p++)的值是46
8. 二维数组a[M][N](P88,P95,P159)
按先行(M)后列(N)存储数据
设 int a[3][5]
| 0列 | 1列 | 2列 | 3列 | 4列 | |
| 0行 | a[0][0] | a[0][1] | a[0][2] | a[0][3] | a[0][4] |
| 1行 | a[1][0] | a[1][1] | a[1][2] | a[1][3] | a[1][4] |
| 2行 | a[2][0] | a[2][1] | a[2][2] | a[2][3] | a[2][4] |
a[i]的地址为 a+(i*N)*sizeof(a[0][0]),i行N列a数组元素长度
或 a+i*sizeof(a[i]),i行a[i]一维数组长度
a[2]的地址为 &a[0][0]+2*5*4
三、阅读程序
1. 求偶数和
if(s>50)break;
if(i%2= =0)s+=i; 求偶数和
i:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
s:2+4+6+8+10+12+14
2. 统计字符'a'‘b'
char a[ ]="abcd abc abfg acd"; //字符中不能空格
int i1=0,i2=0,i=0;
while(a[i]){ //a[i]非空
if(a[i]= ='a')i1++; //统计'a'
if(a[i]= ='b')i2++; //统计'b'
i++;
}
3. 输出三个数字换一行
int a[9]={2,4,6,8,10,12,14,16,18};
if(i+1)%3= =0)cout<<endl;
4. 数字交换
void LE(int * a,int * b){
int x=* a;
* a=* b;* b=x;
}
viod main( ){
int x=10,y=25;
LE(&X,&Y); //变量地址通过引用参数传递(P176)
}
5. 构造函数(P255)
class A{
int a,b; //4.私有成员a
public:
A( ){a=b=0;} //无参构造函数
A(int aa,int bb){ //有参构造函数,2.形参
a=aa;b=bb; //3.赋值给私有成员a
cout<<a<<' '<<b<<endl; //5.输出
}
};
void main( ){
A x ,y(2,3),z(4,5); //1.实参
}
四、阅读函数
1.计算序列数的和
double p=1,s=1;
for(int i=1;i<=n;i++){
p* =x; //等比序列
s+=p/(i+1); //等差序列
}
| i | 1 | 2 | ....... | n |
| p/(i+1) | 1*x/(1+1) | x*x/(2+1) | ||
| s | 1+(1/2)x | 1+(1/2)x+(1/3)x*x |
2. 求键入数的平均值
cin>>x;
while(x!=-1){ //x=-1结束循环
n++;y+=x; //求x的和存入y,n记录x的个数
cin>>x;
}
if(n= =0)return y;
else
return y/n; //求键入数的平均值
}
3. 升序排列数组的元素
void WA(int a[ ],int n){
for(int i=0;i<n-1;i++){
int k=i;
for (int j=i+1;j<n;j++)
if(a[j]<a[k])k=j; //升序排列数组的元素
int x=a[i];a[i]=a[k];a[k]=x;
}
}
| 3 | 大数 a[i] |
小数 a[i+1] |
a[n-1] | |
| x | 4 1 | 1 | ||
| 5 | 大数 a[k] |
2 | 小数 a[j] |
4. 读字符串并显示