目录
那么这时候我们就要考虑一个问题:在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到哪?
声明一个结构体类型
声明一个学生类型 通过学生类型来创建学生变量
描述学生:属性:名字 电话 性别 年龄
struct stu
{
char name[20];//名字
char tele[12];//电话
char sex[10];//性别
int age;//年龄
}s4,s5,s6;//全局变量
struct stu s3;//全局变量
int main()
{
struct stu s1;
struct stu s2;//局部变量
return 0;
}
结构体的自我引用方式
struct Node
{
int data;
//struct Node n;//这里是不对的 不可以在直接存放下一个结构体
struct Node* next;//可以存放下一个结构体的地址
};
结构体重命名
typedef struct Node
{
int data;
//struct Node n;//这里是不对的 不可以在直接存放下一个结构体
struct Node* next;//可以存放下一个结构体的地址
}Node;//将结构体类型重命名为Node
//struct Node s1
//Node s2
//对于创建新的结构体以上两种都是可以的
结构体变量的定义和初始化及访问
struct s
{
char a;
int b;
double c;
char arr[20];
};
int main()
{
//创建结构体变量
struct s s1 = {'a',66,3.14,"nihao1"};
printf("%c %d %f %s",s1.a,s1.b,s1.c,s1.arr);
return 0;
}
结构体大小计算
//结构体内存对齐
struct t1
{
char c1;
char c2;
int a;//8字节
};
struct t2
{
char c1;
int a;
char c2;//12字节
};
struct t3
{
double b;
char c;
int i;//16字节
};
int main()
{
struct t1 t1 = {0};
printf("%d\n",sizeof(t1));//8字节
struct t2 t2 = {0};
printf("%d\n",sizeof(t2));//12字节
struct t3 t3 = {0};
printf("%d\n",sizeof(t3));//16字节
return 0;
}
结构体的对齐规则:
1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。对齐数 = 编译器默认的一个对 齐数 与 该成员大小的较小值。
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
对于struct t1 struct t2 struct t3来说
struct t4
{
char c1;
struct t3 t3;
double d;//32字节
};
int main()
{
struct t4 t4 = {0};
printf("%d\n",sizeof(t4));//32字节
return 0;
}
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
那么要为什么存在内存对齐?
1. 平台原因(移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2. 性能原因:
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
比如:对于创建的结构体s来说 我们要对整型a进行读取
struct s
{
char c;
int a;
};
总体来说:结构体的内存对齐是拿空间来换取时间的做法。
因此在我们创建结构体变量时 我们可以通过修改默认对齐数 来达到我们想要的效果
比如:
1、当我们设置的默认对齐数为4时
#include <stddef.h>
#pragma pack(4)//设置默认对齐数为4
struct s
{
char c;//1
//3
double d;//8
};
#pragma pack()//取消设置的默认对齐数
那么sizeof(s)就是12个字节
2、当我们设置的默认对齐数为8时
#include <stddef.h>
#pragma pack(8)//设置默认对齐数为4
struct s
{
char c;//1
//7
double d;//8
};
#pragma pack()//取消设置的默认对齐数
sizeof(s)就是16个字节
那么这时候我们就要考虑一个问题:在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到哪?
答案是:
让占用空间小的成员尽量集中在一起。
比如:
struct t1
{
char c1;
char c2;
int a;//8字节
};
struct t2
{
char c1;
int a;
char c2;//12字节
};
以上两个结构体存放的数据类型一样 struct t1大小为8字节 struct t2大小为12字节
结构体传参
#include <stdio.h>
//结构体传参
struct s
{
int a;
char c;
double b;
};
void Init (struct s* ps)
{
ps -> a = 10;
ps -> c = 'q';
ps -> b = 3.14;
}
void Print1(struct s tmp)
{
printf("%d %c %f\n",tmp.a,tmp.c,tmp.b);
}
void Print2(const struct s* pb)
{
printf("%d %c %f\n",pb->a,pb->c,pb->b);
}
int main()
{
struct s s = {0};
Init(&s);
Print1(s);
Print2(&s);
return 0;
}