17自定义类型:结构体
位段的成员共有同一个字节的,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位置处就没有地址,内存中每个字节分配一个地址,一个字节内部的bit位是没有地址的。如果嵌套了结构体的情况,嵌套的结构题成员对其到自己成员中最大的对齐数的整数倍处,结构体的整体大小就是使用最大对齐数的整数倍。2 剩余的空间,不足下一个成员使用的时候,是浪费还是继续使用,也是不确定的,但是在vs环境,是浪费。//数组|
![[Pasted image 20251126163743.png]]
```
| |
|---|
|//struct Book|
||//{|
||// char name[20];|
||// char author[20];|
||// float price;|
||// char id[13];|
||// //...|
||//}b3, b4;//全局变量|
||//|
||//struct Book b2;//全局变量|
||//|
||//int main()|
||//{|
||// struct Book b1;//局部变量|
|// struct Book arr[5];//数组|//数组也是可以的
||//|
||// return 0;|
||//}|
|||
```
![[Pasted image 20251126164536.png]]
匿名,结构体没有名字,但是可以创建变量s依旧可以使用一次,不能再使用创建其他变量,打印
可以用s.c, 也可以用s->c,一样的
```
/struct
//{
// char c;
// int i;
// double d;
//} s = {'x', 100, 3.14};
//
//int main()
//{
// printf("%c %d %lf\n", s.c, s.i, s.d);
//
// return 0;
//}
//typedef struct
//{
// char c;
// int i;
// double d;
//}S;
//
//int main()
//{
// S s;
// return 0;
//}
//没意义,但是可以的
```
#结构体的自引用
链表
数据结构,数据在内存种存储组织和结构
数据结构有多种,线性,顺序表,链表,栈,队列
树形,二叉树
图
![[Pasted image 20251126165602.png]]
![[Pasted image 20251126165859.png]]
定义一个节点包含数据和下一个数据的地址
就是数据域和指针域
最后一个空指针
```
| |
|---|
|//struct Node|
||//{|
||// int data;//数据|
||// struct Node* next;//指针|
||//};|
||//|
```
![[Pasted image 20251126172906.png]]
米的天,为什么
结构体内存对齐
![[Pasted image 20251126215913.png]]
前提引入
```
|//struct S|
||//{|
||// char c1;//1|
||// int i;//4|
||// char c2;//1|
||//};|
|||
```
%zd打印无符号整型
![[Pasted image 20251126220201.png]]
规则(为什么是12)
四条规则
偏移量
![[Pasted image 20251126220335.png]]
![[Pasted image 20251126221231.png]]
打印12个字节
这个怎么说,结构体的第一个成员对其结构体变量起始位置偏移量为0的地址,
其他成员变量对其到(对齐数)的整数倍的地址处
对齐数就是与编译器的对齐数比较较小的值
结构体总大小为最大对齐数的整数倍
9不是4的倍数,12是,那就是打印出12
那么其实真实的浪费了六个字节
```
| |
|---|
|//struct S2|
||//{|
||// char c1;|
||// char c2;|
||// int i;|
||//};|
```
打印8个字节
![[Pasted image 20251126222515.png]]
```
| |
|---|
|//struct S3|
||//{|
||// double d;//8 8 8|
||// char c; //1 8 1|
||// int i; //4 8 4|
||//};|
```
```
| |
|---|
|//struct S4|
||//{|
||// char c1;|
||// struct S3 s3;|
||// double d;|
||//};|
```
![[Pasted image 20251126224116.png]]
如果嵌套了结构体的情况,嵌套的结构题成员对其到自己成员中最大的对齐数的整数倍处,结构体的整体大小就是使用最大对齐数的整数倍
在嵌套的结构体里取最大的对齐数,8,不是直接取16
所以32是8的倍数
**为什么存在内存对齐**
![[Pasted image 20251127092837.png]]
对齐后,读一次(在4的倍数那里读取)就能得到数据
需要既满足对齐,又满足节省空间
用存放位置安排,把小的成员集中在一起
#修改默认对齐数
# pragma pack(1)//设置默认对齐数
# pragma pack()//取消设置默认对齐数,还原成默认
```
| |
|---|
|//#pragma pack(1)|//可以改成2的次方,这是2的零次方
||//struct S|
||//{|
||// char c1;//1 1 1|
||// int i; //4 1 1|
||// char c2;//1 1 1|
||//};|
| |
|---|
|//#pragma pack()|
||//|
||//|
||//int main()|
||//{|
||// printf("%zd\n", sizeof(struct S));|
||//|
||// return 0;|
||//}|
```
#结构体传参
```
| |
|---|
|//int main()|
||//{|
||// struct S s = { {1,2,3,4,5}, 100, 3.14 };|
||// //print1(s);|
||// print2(&s);|
||//|
||// return 0;|
||//}|
```
![[Pasted image 20251127094930.png]]
```
| |
|---|
|/struct S|
||//{|
||// int arr[1000];|
||// int n;|
||// double d;|
||//};|
||//|
// //void print1(struct S tmp)
//{
// int i = 0;
// for (i = 0; i < 5; i++)
// {
// printf("%d ", tmp.arr[i]);
// }
// printf("%d ", tmp.n);
// printf("%lf\n", tmp.d);
//}
//
| |
|---|
|/void print2(const struct S* ps)|
||//{|
||// int i = 0;|
||// for (i = 0; i < 5; i++)|
||// {|
||// printf("%d ", ps->arr[i]);|
||// }|
||// printf("%d ", ps->n);|
||// printf("%lf ", ps->d);|
||//}|
||//|
//int main()
//{
// struct S s = { {1,2,3,4,5}, 100, 3.14 };
// //print1(s);
// print2(&s);
//
// return 0;
//}
```
![[Pasted image 20251127224613.png]]
优先选择第二个函数,因为如果传的是结构体对象,结构体过大参数压栈的协同开销比较大,会导致性能下降
所以结构体传参尽量传的是结构体的地址
#位段式结构
位段是基于结构体实现的
位段的声明和结构是类似的,但也有不同
1 位段的成员必须是int unsigned int 或者signed int,
2 位段的成员名后边有个冒号和数字
```
| |
|---|
|/位段式的结构|
||//struct S|
||//{|
||// int _a:2;|
||// int _b:5;|
||// int _c:10;|
||// int _d:30;|
||//};|
```
位段式结构
1 申请到的的一块内存中,从左往右还是从右往左使用,是不确定的,在vs环境种是从右往左
2 剩余的空间,不足下一个成员使用的时候,是浪费还是继续使用,也是不确定的,但是在vs环境,是浪费
![[Pasted image 20251127205602.png]]
![[Pasted image 20251127205625.png]]
这个3怎么来的
三是三个字节,是使用三个字节
3* 8=24个比特位
![[Pasted image 20251127205725.png]]
这个图是重点
下面的620304是16进制的地址
![[Pasted image 20251127205821.png]]
刚好小端存放
位段式结构的好处就是节省空间
位段的跨平台问题
一堆不确定
![[Pasted image 20251127225506.png]]
#位段的注意事项
位段的成员共有同一个字节的,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位置处就没有地址,内存中每个字节分配一个地址,一个字节内部的bit位是没有地址的
所以不能对位段的成员使用取地址&符号,这样就不能使用是scanf直接给位段的成员输入值,之呢个是先输入放在一个变量中,然后赋值的位段大的成员
```
| |
|---|
|//int main()|
||//{|
||// struct A sa = { 0 };|
||// //scanf("%d", &(sa._b));//这是错误的|
||//|
||// //正确的示范|
||// int b = 0;|
||// scanf("%d", &b);|
||// sa._b = b;|
||//|
||// return 0;|
||//}|
```
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)