Wavier_zsk头像
c语言中有关于结构体的相关知识封面图

c语言中有关于结构体的相关知识

1.结构体的声明

结构体的关键字是--struct,一般来说我们需要声明一个结构体需要以下几个代码

其中tag是结构体的名字,member-list是成员变量,variable-list是创建的struct tag类型的变量

2.结构体变量创建和初始化

结构体的特殊声明

如上图结构体tge名称被省略了,但是匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使⽤⼀次

结构体的自引用

如图,这是一个结构体将自己作为了一个成员变量来引用,但是用sizeof(struct node)你会发现这个结构体的所占的字节是无限大的,因为每次调用时,就会创建一个新的成员变量,所以这种写法是错误的

正确的写法是这样的

其中data 是数据域,node* next 是指针域,通过创建一个指针变量,就可以实现存储数据的目的

而一个指针变量在32位环境下所占就是4个字节,在64位环境下占8个字节,所以我们可以很轻易的算出这个结构体的字节为8或12个字节

2.结构体的内存对齐

2.1 对⻬规则
⾸先得掌握结构体的对⻬规则:
1. 结构体的第1个成员对⻬到和结构体变量起始位置偏移量为0的地址处。
2. 从第2个成员变量开始,都要对⻬到某个对⻬数的整数倍的地址处。对⻬数 = 编译器默认的⼀个对⻬数 与 该成员变量⼤⼩的较⼩值。
- VS 中默认的值为 8
- Linux中 gcc 没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩
3. 结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的
整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构
体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。
解释:对其数就是数据类型所占字节数,比如int类型就是4,double类型就是8,char就是1

下面我们来做几个练习

解释一下就是

char c1对齐数是1 比 8还是1 放第一个偏移处

int i对齐数 4比8 就是4 放在第4偏移处中间3个字节空间就浪费了

char c2对齐数还是1,就放i后面

又因为

结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的
整数倍。最大的是4,所以整体大小就是4的倍数,前面一共占9个字节不够,补到12个字节。
所以 struct s1就占12个字节了

练习2

struct S3
{
double d;
char c;
int i;
};
printf("%d\n", sizeof(struct S3));
//练习4-结构体嵌套问题
struct S4
{
char c1;
struct S3 s3;
double d;
};
printf("%d\n", sizeof(struct S4));

这个自己做,算先s3,s4有多大

为什么存在内存对齐

这是一个用空间换时间的做法

数据结构(尤其是栈)应该尽可能地在⾃然边界上对⻬。原因在于,为了访问未对⻬的内存,处理器需要
作两次内存访问;⽽对⻬的内存访问仅需要⼀次访问。假设⼀个处理器总是从内存中取8个字节,则地
址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对⻬成8的倍数,那么就可以
⽤⼀个内存操作来读或者写值了。否则,我们可能需要执⾏两次内存访问,因为对象可能被分放在两
个8字节内存块中。
那在设计结构体的时候,我们既要满⾜对⻬,⼜要节省空间,如何做到:
让占⽤空间⼩的成员尽量集中在⼀起,也可以用联合体union或是位段来节省空间

修改最大对齐数

#pragma 这个预处理指令,可以改变编译器的默认对⻬数。
#include <stdio.h>
#pragma pack(1)//设置默认对⻬数为1
struct S
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的对⻬数,还原为默认
int main()
{
//输出的结果是什么?
printf("%d\n", sizeof(struct S));
return 0;
}

结构体传递参数

结构体传递参数一般用三种操作符,分别为 . -> *,

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;
}
结论:结构体传参的时候,要传结构体的地址。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/Wavier_zsk/article/details/156830205

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--