【C语言入门】自定义类型:结构体

✨✨欢迎大家来到Celia的博客✨✨

🎉🎉创作不易,请点赞关注,多多支持哦🎉🎉

所属专栏:C语言

个人主页Celia's blog~

目录

​编辑

前言

一、结构体的意义

二、结构体的声明

2.1 普通声明

 2.2 特殊声明

三、结构体类型的初始化和成员访问

 3.1 初始化

 3.2 赋值

四、结构体内存对齐

 4.1 结构体的对齐规则

 4.2 修改默认对齐数

五、结构体实现位段


 

前言

  在C语言中,分为内置类型和自定义类型,内置类型譬如int,char等,自定义类型分为结构体,联合体和枚举类型。本篇文章将会详细介绍自定义类型中的结构体类型。

一、结构体的意义

  我们想要描述一个事物单一的特点时,可以用int变量(比如价格),char类型变量(比如人名)等,但是如果我们想要详细的描述一个物品、人的特点的时候,用单一的类型变量会显得很单薄,并不能把事物全面的描述出来,这时,我们可以声明自定义类型:结构体。

二、结构体的声明

2.1 普通声明

struct str
{
	int a;
	char b;
	short c;
	char d;
	long long e;//这里是结构体成员,可以拥有不同类型的变量
};//一定要有分号

struct等同于告诉编译器,要声明一个结构体变量,str是结构体的类型名,struct stu加在一起,就是一个新的结构体类型,与int,char是一个级别的存在。

 2.2 特殊声明

  我们在声明结构体类型变量时,可以省略自定义的结构体类型名,如下所示:

//匿名结构体类型
struct 
{
	int a;
	char b;
	short c;
	char d;
	long long e;
}x;

匿名结构体类型变量如果没有进行重命名的话(typedef)通常情况下只能使用一次,且不可以进行取地址赋值给指针的操作。

三、结构体类型的初始化和成员访问

  在介绍之前,我们需要明确如何访问结构体的成员:

  • 结构体访问操作符:.  (点)
  • 结构体指针访问操作符:-> (箭头)

 3.1 初始化

#include<stdio.h>
struct str
{
	int a;
	char b;
	short c;
	char d;
	long long e;
};
int main()
{
	struct str s = { 1,'a',12 ,'m',11223344};//这里在主函数里声明一个结构体类型变量s
	return 0;
}
struct str
{
	int a;
	char b;
	short c;
	char d;
	long long e;
}s = { 1,'x',12,'m',11223344 };

以上是两种初始化的方式

 3.2 赋值

struct str
{
	int a;
	char b;
	short c;
	char d;
	long long e;
}s;//这里直接在声明的时候,创建了一个结构体变量s
int main()
{
	s.a = 1;//使用结构体访问操作符 . 来对结构体中的变量进行赋值
	s.b = 'x';
	s.c = 12;
	s.d = 'm';
	s.e = 11223344;
	return 0;
}
struct str
{
	int a;
	char b;
	short c;
	char d;
	long long e;
}s;//这里直接在声明的时候,创建了一个结构体变量s
int main()
{
	struct str* p = &s;//创建一个结构体指针,指向结构体变量s
	p->a = 1;
	p->b = 'x';
	p->c = 12;
	p->d = 'm';
	p->e = 11223344;//使用结构体指针访问操作符 -> 对结构体成员进行赋值
    return 0;
}

以上是两种访问结构体成员的方式

四、结构体内存对齐

  在我们对结构体有了初步的认识后,我们可能会想一个问题,结构体包含那么多不同类型的变量,它的大小是如何计算的呢,是把结构体成员的大小直接加和吗?我们来看下面的代码:

#include<stdio.h>
struct str
{
	int a;//4个字节
	char b;//1个字节
	short c;//2个字节
	char d;//1个字节
	long long e;//8个字节
};
int main()
{
	struct str s = { 1,'a',12 ,'m',11223344 };
	printf("%zd", sizeof(s));//输出结果是什么呢,是简单的4+1+2+1+8吗???
	return 0;
}

答案是24,这是为什么呢?

 4.1 结构体的对齐规则

  • 结构体的第一个成员对齐到和结构体变量起始位置偏移量为0的地址处
  • 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处
    对齐数 = 编译器默认对齐数 和 该成员 变量大小的较小值
    - VS默认对其数为8
    - Linux中gcc没有默认对齐数,对齐数就是成员变量的大小
  • 结构体总大小为最大对齐数(结构体每个成员都有对齐数,所有对齐数中最大的)的整数倍
  • 如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,该结构体的大小为自身的最大对齐数,整个结构体的大小就是结构体最大对齐数(包括嵌套的结构体)的整数倍

 我们来单独看一下这个结构体:

struct str
{
	int a;//4个字节
	char b;//1个字节
	short c;//2个字节
	char d;//1个字节
	long long e;//8个字节
};

  • a为第一个成员,对齐到偏移量为0的地址处存储
  • b的类型为char,对齐数为默认对齐数(8)与变量大小(1)的较小值,为1,4是1的整数倍,所以b对齐到偏移量为4的地址处存储
  • c的类型为short,对齐数为2,5不是2的倍数,向下寻找,6为2的倍数,所以c对齐到偏移量为6的地址处存储
  • d的类型为char,对齐到偏移量为8的地址处存储
  • e的类型为longlong,对齐数为8,向下寻找至16为8的倍数,所以e对齐到偏移量为16的地址处存储
  • 这时整个结构体的大小为24字节,是最大对齐数(longlong - 8)的整数倍,整个结构体的大小就为24字节

 4.2 修改默认对齐数

#pragma pack(1)

 我们可以使用这个预处理指令来修改默认对齐数的值,把想要修改的值填入pack后的括号内就可以了。

五、结构体实现位段

struct str
{
	char a : 1;//位段
	char b : 2;
	char c : 3;
	char d;
}s;
struct str
{
	int a : 1;//位段
	int b : 2;
	int c : 3;
	int d;
}s;
  • 位段的成员可以是int,unsigned int,signed int,或者是char等类型。
  • 位段在空间是是按照需要以4个字节(int)或者1个字节(char)来开辟的,VS是从右向左进行空间分配的。
  • 位段涉及很多不确定因素,是不跨平台的。
  • 这种创建结构体成员的方法可以限制每个结构体成员的大小(bit位),比如a的大小为1个bit,b的大小为2个bit,c的大小为3个bit,d是一个普通字符变量,大小为8bit。

具体存储方式(以char类型为例):

#include<stdio.h>
struct str
{
	char a : 1;
	char b : 2;
	char c : 3;
	char d;
}s;
int main()
{
	printf("%zd", sizeof(s));
	return 0;
}

大小果然为2个字节

  • 19
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Celia~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值