前言
一、结构体
1.结构体的基本知识
2.结构体的声明
3.结构体的自引用
4.结构体变量的定义与使用
5.结构体的内存对齐
6.结构体传参
二、位段
(1)位段的声明和结构是类似的,有两个不同
(2)位段所占用的空间
(3)位段的跨平台
三、枚举
(1)枚举的定义
(2)枚举的优点
(3)枚举的使用
四、联合体
(1)联合体的定义
(2)联合体的特点
前言
结构体常被用于描述相对复杂的对象,其内容可以表示很多用单一数据无法表示的各种数据。
结构体类型不是由系统定义好的,而是需要程序设计者自己定义的。C语言提供了关键字struct来标识所定义的结构体类型。
一、结构体
1.结构体的基本知识
关键字struct和结构体名组合成一种类型标识符,其地位如同通常的int、char等类型标识符,其用途就像 int 类型标识符标识整型变量一样可以用来定义结构体变量。定义变量以后,该变量就可以像定义的其他变量一样使用了;成员又称为成员变量,它是结构体所包含的若干个基本的结构类型,必须用“{}”括起来,并且要以分号结束,每个成员应表明具体的数据类型。
2.结构体的声明
struct tag
{
member-list;
}variable-list;
例:一本书的声明
struct book
{
int num;//字数
char name[20];//书名
char author[24];//作者
char phouse[30];//出版社
};
再上述的条件上可以对结构体进行匿名声明,但结果会导致无法引用该结构体类型,要在另一个结构体中取出该结构体的成员地址时,编译器会直接弹出警告,因为这两个结构体是两个完全不同的类型,并不能直接提取地址。
3.结构体的自引用
(1)不使用typedef时
错误的方式:
struct tag
{
struct tag;
int value;
};
这种类型的声明是错误的,因为在调用这个结构体,在这个结构体的成员中还是会有结构体,会导致在内存分配的时候,因为其内容无限嵌套,导致内存无法为其分配相应的内存单位,从而导致程序的崩溃。
正确的方式:
struct tag
{
struct tag* A;
int value;
};
因为指针的长度是确定的(在32位的机器中指针的长度是4 type,在64位机器中指针的长度是8 type),所以编译器可以确定该结构体的长度。
4.结构体变量的定义与使用
(1)在定义结构体变量的时候,可以对其成员进行一定的初始化;也可以在声明这个结构体之后,对这个结构体类型的变量进行初始化。
1.在声明定义的同时定义变量
struct book
{
int num;
char name[20];
char author[24];
char phouse[30];
};b1,b2
2.在声明定义结构体后,再定义该类型的变量
struct book
{
int num;
char name[20];
char author[24];
char phouse[30];
};
struct book b1,b2;
(2)引用结构体变量中成员的值:结构体变量.成员名。“.”是成运算符,在所有的运算符中的优先级最高。
- 不能企图输出结构体变量名来输出结构体的所有成员,只能分别输出各个成员的值
- 结构体变量成员可以像普通变量一样进行运算\n同类的结构体变量可以相互赋值
- 可以引用结构体变量成员的地址,也可以引用结构体变量的地址,主要用作函数参数,传递结构体变量地址。
5.结构体的内存对齐
(1)结构体的对齐和补齐的规则:
对齐:结构体的第一个成员在结构体的地址偏移量为0的位置,每个成员的起始地址都是最大对齐数的整数倍地址处(对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值)。
补齐:结构体的总字节数必须是其对齐数的整数倍。
(2)修改默认对其数
#pragma pack(8)
这里是将默认对其数改为8.
#pragma pack()
这里是取消自己设置的默认对其数,并将其改为每个编译器自带的默认对其数。
6.结构体传参
结构体传参一般使用传地址的形式,这样有利于充分利用内存;如果使用传结构体的参数过去将会再重新创建一个临时的结构体变量来接受这个参数,这样可能会导致性能的丢失。
二、位段
三、枚举
(1)枚举的定义
enum Day//星期
{
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
四、联合体
(1)联合体的定义
//联合类型的声明
union Un
{
char c;
int i;
};
//联合变量的定义
union Un un;
(2)联合体的特点
1.联合体中的成员是公用一块空间的,所以联合体的大小至少是其联合的最大成员的大小(因为联合体至少有能力去保存最大成员的地址)。