结构体的声明,嵌套定义以及引用
#include <stdio.h>
struct stu_st //结构体的声明
{
char name[20];
int age;
}; //定义结构体变量p
struct xs_st //结构体的声明
{
int am;
struct stu_st p; //结构体的嵌套定义
}n1 = { 1,{{"xiaowenfang"},26}}; // 结构体的嵌套初始化,初始化时要按照声明类型顺序对应存放数据
int main()
{
printf("%d %s %d\n",n1.am,n1.p.name,n1.p.age);//结构体成员的引用
}
结构体的内存对齐---计算结构体的大小
结构体内存对齐原因:结构体的内存对齐是拿空间来换取时间的做法。设计结构体的时候让占用空间小的成员尽量集中在一起。
内存对齐的规则:
1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的值为8
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
简单总结:位置/类型大小能整除
例子:非嵌套结构体大小的计算
![](https://i-blog.csdnimg.cn/blog_migrate/f524270a868e9085e3bf0aedd21aa3de.png)
c1----------- char 1字节
c2------------int 4字节
d-------------double 8字节
编译器对齐数 8,分别与数据类型相比较 ,数据类型小因此选择 数据类型大小来作为除数。
成员存放:起始位置为0 开始存放c1-----1/4 2/4 3/4 都不能整除----4/4可以整除,因此c2从位置4开始存放------存放d时,8/8能整除,因此d从位置8 开始存放。
计算结构体大小-----首先选出最大对齐数8------存放大小为16---存放大小/最大对齐数 16/8可以整除,因此结构体总大小为16。
嵌套结构体大小的计算:
![](https://i-blog.csdnimg.cn/blog_migrate/f14f922bb7593c5f2414593fad411cd5.png)
![](https://i-blog.csdnimg.cn/blog_migrate/75aea5352ec0caa49ece7ada56f78417.png)
c1-----char--- 1
s4-----struct S4---16
d------double-----8
含有嵌套结构体的成员存放:起始位置0,存放c1------存放嵌套的结构体时,要找嵌套结构体中的最大对齐数8,并与位置作比较找到能整除的位置,1/8,2/8...7/8都不能整除,8/8可以,因此从位置8开始存放s4-----d的对齐数最小为8,位置24/8整除所以从位置24存放d------此时所占空间一直到位置31,找出所有结构体中的最大对齐数,包括嵌套结构体 ,最大对齐数为8----31/8不能整除,向下找位置32/8可以整除-----结构体的大小为33。
结构体传参
函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。
如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的
下降。
结论:结构体传参,传递地址。
struct S
{
int data[1000];
int num;
};
struct S s = {{1,2,3,4}, 1000};
//结构体传参
void print1(struct S s)
{
printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
printf("%d\n", ps->num);
}
int main()
{
print1(s); //传结构体
print2(&s); //传地址
return 0;
}
![](https://i-blog.csdnimg.cn/blog_migrate/3ad409ef15d6c3e1d54ad81568d580e1.png)
结构体数组
结构体数组是一个数组,由若干个相同类型的结构体变量组成的集合。
定义:struct 结构体名 数组名[ 元素个数 ]
![](https://i-blog.csdnimg.cn/blog_migrate/07e1066d7a5fe9ebab93672d495979c8.png)
#include <stdio.h>
#define max 10 //使用宏定义,使max = 10
typedef struct student //使用typedef 将struct student 结构体重新起名为 stu_st
{
char a;
int b;
char p[10];
} stu_st;
int main()
{
stu_st prog[max] = //定义一个结构体数组
{
{12,52,"qwert"},
{13,53,"qwer"},
{11,51,"qwe"}
};
printf("%s\n",prog[0].p);// 引用数组内结构体的元素。引用方式: 数组名 [下标] . 成员
return 0;
}
结构体指针
结构体指针变量用来存放结构体的地址。
定义方法:
struct 结构体名 * 指针变量名
引用方法:
(*指针变量名).成员
指针变量名->成员 常用
![](https://i-blog.csdnimg.cn/blog_migrate/154c9de6a81b36d20a6e17094948f192.png)
typedef在结构体中的用法--重命名结构体名和指针名
#include<stdio.h>
#define max_st 100
//定义一个结构体 struct stde,结构体变量为s1,s2。
//第一种方式
struct stde
{
int a;
char na[max_st];
float b;
}s1,s2;
//第二种方式
struct stde
{
int a;
char na[max_st];
float b;
}; //定义一个结构体
struct stde s1, s2;//定义结构体变量 s1 s2
//第三种方式
typedef struct stde
{
int a;
char na[max_st];
float b;
}stde_st;//使用typedef 将struct stde 重新命名为 stde_st
stde_st s1, s2;//通过 定义两个结构体变量名 s1,s2。
//重命名结构体指针
typedef struct //匿名结构体
{
int a;
char na[max_st];
float b;
}*point_st;//相当于将 struct * 重命名为point_st
point_st p; //相当于struct * p,定义一个结构体指针变量p
//总结:typedef struct{
// }结构体的重命名; 通常与匿名结构体一起使用
// struct 结构体名 {
// }变量名;