C语言中的结构体
用户自定义的可用的数据类型,它允许您存储不同类型的数据项。
文章目录
一、结构体类型
结构体类型 char short ....... 内置类型 - (C语言自己的数据类型)复杂对象
复杂类型
自定义类型 : 结构体、枚举、联合体
声明一个结构体类型
声明一一个学生类型,通过学生类型来创建学生变量(对象)
描述学生 : 属性名字 + 电话 + 性别 + 年龄
struct Stu
{
char name[20];//名字
char tele[12];//电话
char sex[10];//性别
int age;
};
结构体的使用和初始化
创建结构体局部变量
struct stu s1;
全局变量
struct Stu
{
//成员变量
char name[20];
short age;
char tele[12];
char sex[5];
}s1,s2;//全局结构体变量
初始化结构体和打印 . 调用成员变量操作符
结构体变量.成员名
struct S s1 = { 'Alicesa','1231344', '0' ,'0',21 };
printf("%c %c %c %d\n", s.name,
s.tele, s.sex, s.age);
结构体的重命名(typedef)
typedef struct Stu
{
//成员变量
char name[20];
short age;
char tele[12];
char sex[5];
}Stu2;//重新起名字
二.结构体指针
创建结构体指针
(结构体指针)Stu * ps=&s(创建的结构体局部变量)
结构体变量->成员名访问
printf("name: %s\n", ps->name);
printf("age : %d\n", ps->age);
printf("tele: %s\n", ps->tele);
printf("sex : %s\n", ps->sex);
结构体的传参
Print1(s)(传参数传的是整个结构体的临时拷贝)和Print2(&s)(传入的是地址结构地址)
Print1(s)(传参数传的是整个结构体的临时拷贝这种操作是会压栈的)
压栈图
先进的后面出,后进的先出,如果你要拿先进的数据,进必须然后后面的数据进行出栈操作操作拿到你要的栈地的数据
结构体指针类型
struct
{
int a;
char b;
}*psa;
匿名结构体类型
struct
{
int a;
char b;
}x;
通过x调用
三.结构体的自引用
struct Node
{
int data;//4
struct Node* next;//struct Node node2//自己包含自己是不行的,不然是一直(类似递归)内存是巨大的
//4/8//下一个Node节点的地址//例struct Node node2;//链表
};
在一个结构体里保存着另一个的相同结构体类型的地址,而在另一个的结构体又保存着另一个的相同类型的结构体类型的指针,形成数据结构的链表形式和链表一样
结构体的嵌套
struct T
{
double weight;
short age;
};
struct S
{
char c;
//结构体的嵌套
struct T st;
int a;
double d;
char arr[20];
}
结构体嵌套的初始化
结构体的初始化2
struct S s = { 'C', {55.6, 30}, 100, 3.14, "hello bit" };
printf(" %lf\n", s.st, s.st.weight );
四. 结构体的内存对齐
结构体的内存对齐1.第一个成员在与结构体变量偏移量为0的地址处。
2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数与该成员大小的较小值。
●VS中默认的值为8
3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4.如果嵌套了结构体的情况, 嵌套的结构体对齐到自己的最大对齐数的整数倍处, 结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
例题
struct S1
{
char c1;//1.第一个成员在与结构体变量偏移量为0的地址处。就是char类型,1
int a;//int类型是4个字节,对齐数是8作比较,较小值是4,。//2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处
//开始是 4的倍数是1*4/ //距离第一个字节到第4个偏移量 对齐到4的倍数开始分布空间,
char c2;2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。1/8,较小值1,1*1的数1占一个空间
//1+7+1=9
//3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。4
//9不是4的整数被,最近整数倍的就是12个字节
};
解析图
结构体嵌套
struct S3
{
double d;//8
char c;
int i; //4
};
struct S4
{
char c2;//一开始1,此时零0偏移量到1
struct S3 s3;//最大对齐数是8找到8的倍数,从偏移量1开始浪费7个偏移量到8偏移量开始分布空间16个字节此时的偏移量到24
double d;//此时偏移量是24,8的倍数所以直接分布24+8=32
//3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。是8
//32刚好又是8的倍数所以内存是32
//};
修改默认对齐数
//修改默认对齐数
//设置默认对齐数位4
#pragma pack(4)
//取消设置
#pragma pack()
为什么需要结构体对齐
先假设不存在内存对齐的情况
32位的机器(二进制),32根地址线32个数据线
每次读取一4个字节(32个比特位)
例由于一次性取4个字节的(32个比特位)如果说char类型和int类型没有对齐的情况下5字节第一次读4字节那么读取int的时候就要读取两次
第一次是char一字节和int的3字节组成的4字节。第二次读取int剩余的一个字节(光是数据读取两次)
图解
所以内存对齐可以大大提升内存访问速度,是一种用空间换时间的方法。
内存不对齐会有可能导致每次读取数据都会读取两次,使得内存读取速度减慢
总结
我们既要满足对齐, 又要节省空间, 如何做到:
让占用空间小的成员尽量集中在一 起。