结构体
结构体类型的声明
结构是一些值的集合,这些值被称为成员变量。每个结构体的成员变量可以是不同类型的变量。
//结构体的声明
//struct tag
//{
// member-list;
//}variable-list;
//
//举例
struct abc
{
int i;
char j;
};
struct stu
{
char name[20];
int age;
struct abc a;
}stu1;
struct stu stu2;
int main()
{
struct stu stu3 = { "zs",10,{97,'a'} };
return 0;
}
特殊的匿名声明
struct
{
char name[20];
int age;
}stu4;
去掉标签的结构体是能正常声明的,但是在函数中,这个结构体只能使用一次的,它能声明stu4,无法再拿它去声明其他变量(就像不能 struct stu5 这样声明)在使用中也要注意:
struct
{
char name[20];
int age;
}stu4;
struct
{
char name[20];
int age;
}* p;
int main()
{
p = &stu4;
}
在监视里面看,输出结果是没有什么问题,但是编译是报了警告的,它指出stu4与p的类型不兼容,编译器把上面两个声明当成了两个不同的类型,说明使用相同的结构体匿名声明不同的变量,实际是不相同的。
结构的自引用
struct stu
{
char name[20];
int age;
struct stu * stu1;
};
结构体的自引用是只能通过指针来 ,否则会报错
结构体内存对齐
如果要计算结构体的大小,该怎么计算。
结构体的对齐规则
1、第一个成员在结构体变量偏移量为0的地址处。
2、其他结构体成员变量要对其到对齐数(编译器默认的对齐数与该成员类型大小的较小值)的整数倍的地址处。(vs的默认对齐数为8,部分编译器没有默认对齐数。默认对齐数可以通过预处理命令#pragma更改。)
3、每个结构体大小总为该结构体最大对齐数的整数倍。在嵌套了结构体的情况下,嵌套的结构体对齐到自己最大对齐数的整数倍处,这个结构体的大小就是包括嵌套结构体的最大对齐数的整数倍。
修改默认对齐数
结构体传参
struct S
{
int data[1000];
int num;
}s;
//结构体传参
void print1(struct S s)
{}
//结构体地址传参
void print2(struct S* ps)
{}
int main()
{
print1(s);//传结构体
print2(&s); //传地址
return 0;
}
地址传参会优于结构体传参,结构体传参会创建一个相同的副本,会造成较大的时间和空间上的系统开销,地址传参是创建指针指向结构体,性能会比结构体传参好。
位段
位段的空间开辟是以4个字节或者1个字节的方式开辟,所以位段的类型只能是int,unsigned int,signed int,char。
位段的声明与结构大致相同,但位段类型有限制,而且位段的成员名后面有冒号和一个数字(给该成员赋给的bit空间,当没有冒号和数字时,则会开辟这个类型相对应的字节空间)。
struct S
{
char a : 3;
char b : 4;
char c : 5;
char d : 4;
};
位段在内存中存放的特点
和结构体相比,位段可以达到相同的效果且可以更节省空间,但是跨平台可以会导致位段错误。
枚举
枚举类型的定义
枚举就是一一列举
枚举常量都是有默认值的,默认从0开始
也可以在定义的时候,给枚举常量赋给初值来改变默认值
枚举的优点
相比#define定义常变量,枚举可以一次定义多个常变量,并且枚举会有类型检查,除此,便于调试,检查,还可以防止命名污染。
枚举的使用
enum Day
{
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
int main()
{
enum Day a = Mon;
enum Day b = 1;
return 0;
}
这个枚举使用举例,变量a是正确的使用,b的使用在c可以正常运行,在c++的环境下会报错
联合
联合类型的定义
联合也叫共用体,是一种特殊的自定义类型,这种类型变量包含的一系列成员共用一块空间。
联合的特点
联合共用一块空间,这样一个联合的变量大小,至少是最大成员的大小。
从上面的运行结果来看,字符c与i的第一个字节共用了内存。
联合大小的计算
联合的大小至少是最大成员的大小
当最大成员的大小不是最大对齐数的整数倍时,要与最大对齐数的整数倍对齐