C语言——结构体详解

1.结构体定义

是由一系列具有相同类型或不同类型的结果构成的数据集合,称为结构体

1.1结构体声明:

类型1:

struct 结构体名

{

成员列表;

(数据类型 成员名1;)...

};//分号不可省略

类型2:

typedef struct 结构体名

{

成员列表:

}别名;(意为把结构体的数据类型起一个别名)

类型3:

匿名结构体类型(不表明结构体名)

struct 

{

int a;

char b;

double c;

}x;

若没有对结构体类型重命名的话,基本只能使用一次。

注意
1.struct指出下面是结构体类型

2.最后分号不可以少

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

#include <stdio.h>
struct Stu
{
 char name[20];//名字
 int age;//年龄
 char sex[5];//性别
 char id[20];//学号
};
int main()
{
 //按照结构体成员的顺序初始化
 struct Stu s = { "张三", 20, "男", "20230818001" };
 printf("name: %s\n", s.name);
 printf("age : %d\n", s.age);
 printf("sex : %s\n", s.sex);
 printf("id : %s\n", s.id);
 
 //按照指定的顺序初始化
 struct Stu s2 = { .age = 18, .name = "lisi", .id = "20230818002", .sex = "⼥
 printf("name: %s\n", s2.name);
 printf("age : %d\n", s2.age);
 printf("sex : %s\n", s2.sex);
 printf("id : %s\n", s2.id);
 return 0;
}

3.结构体成员访问

格式:结构体名.成员名 或者 结构体名->成员名

3.1结构体变量和指针

结构体类型可以定义结构体类型指针

访问成员方式:1.(*p).成员名 (.优先于*,所以(*p)的两边括号不能少)

                          2.  p->成员名(->指向符)

4.结构体的自引用(链表)

//定义一个链表的节点
struct Node
{
int data;
struct Node* next;
}

上述代码中,*不可以省略,否则因为⼀个结构体中再包含⼀个同类型的结构体变量,这样结构体变量的⼤⼩就会⽆穷的⼤。

链表示意图

5.结构体传参(结构体和函数)

注意:结构体传参的时候,要结构体的地址

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;
}

为了节省空间和时间,首选printf2函数,借助指针来便捷处理

6.结构体内存对齐(计算结构体的大小)

6.1对齐规则

1.第一个成员在结构体偏移量为0的地址处

2.其他成员变量要对齐的某个数字(对齐数)的整数倍的地址数

对齐数=编译器默认的对齐数与该成员大小的较小值

VS 中默认的值为 8
- Linux中 gcc 没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩

3.结构体总大小为最大对齐数(每个成员都有一个对齐数)的整数倍

4. 如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构
体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。

6.2 使用原因

直接原因:为了更高的访问效率和更好的缓存优化,是拿空间换取时间的做法

根本原因:对当前因地址总线限制而导致的内存寻址“不自由”的一种“妥协”

struct S1
{
 char c1;
 int i;
 char c2;
};
printf("%d\n", sizeof(struct S1));

上述代码输出结果为12,因为int类型占4个字节,所以对齐数为4,尽管char类型只占1个字节,但分配空间时,仍然分配了四个空间的位置,如图所示

6.3修改默认对齐数

#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;
}
结构体在对⻬⽅式不合适的时候,我们可以⾃⼰更改默认对⻬数,效果如图所示(对齐数改为1时)

7.结构体实现位段

7.1位段声明

1. 和结构体类似,但成员必须是 int 或char

2. 位段的成员名后有一个冒号和一个数字

struct A
{
 int _a:2;
 int _b:5;
 int _c:10;
 int _d:30;
}

7.2 位段的内存分配

位段的空间上是按照需要以4个字节( int )或者1个字节( char )的⽅式来开辟的
struct S
{
 char a:3;//冒号后面的数字即为占几个比特的意义
 char b:4;
 char c:5;
 char d:4;
};
struct S s = {0};
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;

注意:位段的几个成员共有同一个字节,

这样有些成员的起始位置并不是某个字节的起始位置,那么这些位
置处是没有地址的,所以不能对位段成员使用&操作符。只能先输入存放进一个变量中,再赋值给位段的成员。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值