结构体
1.定义结构体类型
结构体允许将不同类型的数据元素组合在一起形成一种新的数据类型,其声明形式为:
struct 结构体类型名 {
成员列表
};
结构体类型声明一般放在程序文件开头,此时这个声明是全局的。在全局作用域内,该声明处处可见,因此同作用域内的所有函数都可以使用它。结构体类型声明也可以放到函数内部,此时这个声明是局部的。
说明:
(1)结构体类型和普通数据类型(如int、char、double等)一样是类型名称,而不是该类型的一个实体,因此不会为结构体类型分配存储空间。
(2)结构体类型声明时成员可以又是是结构体类型。(即可以嵌套)
2.结构体类型实例化
定义结构体对象称为结构体类型实例化(instance),实例化会根据数据类型为结构体对象分配内存单元。定义结构体对象有两种形式。
1)先声明结构体类型再定义对象
struct atudent;
student a,b;
2)声明结构体类型的同时定义对象
DATE { //日期类型
int year,month,day; //年,月,日 整型
} d1,d2; //定义结构体对象
3.结构体对象的内存形式
实例化结构体对象后,对象会得到存储空间
struct STUDENT { //学生信息类型
int no; //声明一个整型数据成员表示学号
char name[21]; //声明一个字符串数据成员表示姓名
char sex; //声明一个字符数据成员表示性别
int age; //声明一个整型数据成员年龄
char qq[11]; //声明一个字符串数据成员表示QQ号
double score; //声明一个浮点型数据成员表示成绩
};
可以在结构体对象定义时进行初始化
struct STAFF { //职员信息类型
int no; //工号,整型
char name[21]; //姓名,字符串
char sex; //性别,字符型
DATA birthday; //出生日期,结构体类型
double salary; //薪水,浮点型
};
STAFF s1={1001,"Li Min",'M',{1980,10,6},2700.0};
STAFF s2={1002,"Ma Gang",'M',1978,3,22,3100.0};
4.结构体对象成员引用
使用结构体对象主要是引用它的成员,一般形式为:
结构体对象名.成员名
STAFF a,b;
a.no=10002; //将10002赋值给a对象中的no成员
b.salary=a.salary+500.0; //在表达式中可以引用对象成员
a.no++; //按优先级等价于(a.no)++
- 如果成员本身又是一个结构体对象,就要用成员引用运算符, 一级一级地引用。
- 不能将一个结构体对象作为整体进行输入或输出,只能对结 构体对象中的成员逐个进行输入或输出。 (但可以自定义函数或者重载运算符实现)
- 结构体对象可以进行赋值运算,但不能对进行算术运算、关 系运算等,
5.结构体和数组、指针、函数
结构体和数组。数组元素可以是结构体类型,成为结构体数组。如:
struct POINT { //点类型
int x,y; //平面上点的x、y坐标
};
POINT points[100]; //表示100个点的数据对象
一维数组结构体初始化,处置必须按照内存形式做到类型,顺序一一对应。
struct RECT { //矩形框类型
int left,top,right,bottom;
};
RECT rects[3]={{1,1,10,10}, {5,5,25,32},{100,100,105,200}};
引用结构体数组成员需要将数组下标运算、对象成员引用运算结合起来操作:
rects[0].left=10;
结构体类型中可以包含数组成员,数组成员类型既可以是 基本数据类型,又可以是指针类型或者结构体类型。
struct TRIANGLE { //三角形类型
POINT p[3];//由3个平面上的点描述三角形
};
TRIANGLE tri;
tri.p[0].x=10,tri.p[0].y=10;
//结构体对象.数组成员[下标表达式].成员名
结构体和指针。结构体对象各成员的地址:&对象名.成员名。
int *p1; //指向no成员的指针类型是int*
char *s1,*s2; //指向name、sex成员的指针类型是char*
STAFF m; //结构体对象
p1=&m.no; //取no成员的地址
DATE *p2; //指向birthday成员的指针类型是DATE*
s1=m.name; //name成员是数组,数组名即是地址
s2=&m.sex; //取sex成员的地址
p2=&m.birthday; //取birthday成员的地址
结构体对象的地址:&对象名。例如
struct STAFF m, *p; //指向结构体对象的指针
p=&m; //取结构体对象的地址
假设p是指向结构体对象的指针,通过p引用结构体对象成员有两种
方式:
①对象法:(*p).成员名;
②指针法:p->成员名。
更常用第二种方式,->为指针成员引用运算符。
struct STAFF *p;
p->no=10002; //将10002赋值给对象中的no成员,指针成员引用运算结果是左值(即成员本身)
p->salary=p->salary+500.0; //在表达式中引用指针指向的成员
p->no++; //按优先级等价于(p->no)++
如果成员本身又是一个结构体对象指针,就要用指针成员引用运算符一级一级的引用成员。
DATE d={1981,1,1};
TEACHER { //教师信息类型
int no; //工号
char name[21]; //姓名
DATE *pbirthday; //出生日期
} a={1001,"Li Min",&d}, *p=&a;
p->no=10001; //通过指针p引用a的no成员
p->pbirthday->year=2008; //通过指针p->pbirthday引用d的year成员
结构体和函数
结构体对象作为入参,使用值传递的函数:
struct DATA {
int data; //整型成员
char name[10]; //数组成员
};
void fun1(DATA x); //函数原型
void fun2(){
DATA a={1,"LiMin"};
fun1(a); //函数调用
}
结构体题数组作为入参,使用地址传递。函数调用实参是数组名,形参必须是同类型的结构体数组。使用地址传递方式,形参数组的首地址和实参数组完全相同。
void fun3(DATA X[]); //函数原型
void fun4(){
DATA A[3]={1,"LiMin",2,"MaGang",3,"ZhangKun"};
fun3(A); //函数调用
}
将结构体指针作为函数参数,采用地址传递方式
void fun5(DATA *p); //函数原型
void fun6(){
DATA a={1,"LiMin"};
fun5(&a); //函数调用
}
函数的返回类型可以是结构体类型。
DATA fun8(){
DATA a={1,"LiMin"};
return a; //返回结构体对象,复制到临时对象中
}
void fun9(){
DATA b;
b=fun8(); //函数返回结构体对象,并且赋值
}
共用体
union A {
int m,n; //整型成员
char a,b; //字符成员
};
结构体和共用体:
结构体内存长度是所有内存长度之和。可以用sizeof求他们的内存长度。
定义共用体对象时可以进行初始化,但只能按一个成员给予初值,
union A x={ 5678 }; //正确,只能给出1个初值
union A y={5,6,7,8}; //错误,试图给出4个初值(结构体做法)
由于成员是共享存储空间的,使用共用体对象成员时有如下特点:
- 修改一个成员会使其他成员发生改变,所有成员存储的总是最后 一次修改的结果;
- 所有成员的值是相同的,区别是不同的类型决定了使用这个值的全部或是部分;
- 所有成员的起始地址值是相同的,因此通常只按一个成员输入、 初始化;
共用体可以用来测试大小端:
void checkCPU()
{
union MyUnion{
int a;
char c;
}test;
test.a = 1;
if (test.c == 1)
cout << "little endian" <<endl;
else cout << "big endian" <<endl;
}
枚举类型
枚举类型是由用户自定义的由多个命名枚举常量构成的类型
enum DAYS {MON,TUE,WED,THU,FRI,SAT,SUN};
- 可以在(仅仅在)声明枚举类型时,为命名枚举常量指定值。
enum COLORS {RED=10,GREEN=8,BLUE,BLACK,WHITE};
则RED为10、GREEN为8、BLUE为9、BLACK为10、WHITE为11。
- 命名枚举常量是一个整型常量值,也称为枚举器,在枚举类
型范围内必须是唯一的。命名枚举常量是右值不是左值。
RED=10; //错误,RED不是左值,不能被赋值
GREEN++; //错误,GREEN不是左值,不能自增自减
typedef
可以用typedef声明一个新类型名来代替已有类型名,其形式为:
►其中已有类型名必须是已存在的数据类型的名称,新类型名是标识
typedef 已有类型名 新类型名;
符序列,习惯上用大写标识;如果是多个新类型名,用逗号(,)作为间隔。最后以分号(;)结束。例如:
typedef unsigned char BYTE; //按计算机汇编指令习惯规定的字节型
typedef unsigned short WORD; //按计算机汇编指令习惯规定的字类型
typedef unsigned long DWORD; //按计算机汇编指令习惯规定的双字类型