首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >结构体

结构体

作者头像
code-child
发布2023-05-30 11:36:27
发布2023-05-30 11:36:27
9370
举报
文章被收录于专栏:codechildcodechild

结构体

为什么要创建结构体类型?在我们处理复杂对象的时候,比如描述一个人的时候,它有名字,性别,身高,体重等一些方面的特征。用结构体打包描述的时候就比较方便。

结构体类型的声明

结构体类型的关键字struct。 声明的基本模板为:

struct 标签 { 成员; }变量; 结构体的成员可以是不同的类型。

结构体类型的特殊声明: 匿名结构体类型,它只能使用一次。

代码语言:javascript
复制
cstruct
{
	int a;
	char b;
}x;
struct
{
	int a;
	char b;
}*p;

p=&x这样写是错误的,在编译器看来,它们俩是不同的类型。

看下面这两种:

代码语言:javascript
复制
cstruct
{
	int a;
	int b;
}x;
这里的x是一个结构体类型的全局变量
typedef struct
{
	int a;
	int b;
}x;
这里的x是结构体类型。
typedef struct stu
{
	int a;
	int b;
}*put,stu;
这里的put等价于struct stu*类型
stu等价于struct stu类型

结构的自引用

例如:

代码语言:javascript
复制
ctypedef struct node
{
	int x;
	struct node* p;
}node;
这个自引用就是正确的。
typedef struct node
{
	int x;
	node* p;
}node;
这种就是错误的,这个问题的出现就和先有鸡还是先有蛋的问题一样。
不能知道是先重命名了还是先创建的。

结构体变量的定义和初始化

  • 结构体变量的定义
代码语言:javascript
复制
cstruct student
{
	char name[20];
	int age;
}a,b;
//这种是一边声明,一边定义变量的,这里的变量a,b为全局变量
struct student c;
//这种定义的变量是全局变量
int main()
{
	struct student d;
	//这里的d为局部变量
	return 0;
}
  • 简单的初始一下:(应该没有难道吧)
代码语言:javascript
复制
cstruct student
{
	char name[20];
	int age;
}a={"zhangshan",20}, b={"wuanwu",18};
struct student c={"hh",0};
int main()
{
	struct student d={"sb",88};
	return 0;
}

🟥结构体内存对齐

如何计算结构体的大小,就需要知道它在内存中是如何储存的。 而结构体在内存中存在结构体对齐的现象。

1.第一个成员变量放在偏移量为0的位置 2.后面的成员放在偏移量为对齐数的整数倍的位置。 3.对齐数:编译器默认的一个对齐数与成员大小的较小值 vs的默认对齐数位8 4.结构体的总大小为每个成员默认最大对齐数的整数倍。 5.如果含有结构体嵌套的情况,镶嵌的那个结构体的对齐数是里面成员的最大对齐数。

  • 下面仔细讲解一下:
代码语言:javascript
复制
c	struct S1
	{
		char c1;
		int i;
		char c2;
	};
	printf("%d\n", sizeof(struct S1));

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

	struct S3
	{
		double d;
		char c;
		int i;
	};
	printf("%d\n", sizeof(struct S3));

	struct S4
	{
		char c1;
		struct S3 s3;
		double d;
	};
	printf("%d\n", sizeof(struct S4));

按上面的分析:可知结构体的大小分别为:12,8,16,32 运行看一下情况:

修改默认对齐数

我们用pragma修改默认对齐数

例子:

代码语言:javascript
复制
c#pragma pack(4)
//这里面的数字表示的是默认对齐数
struct p
{
	int a;
	int b;
	char c;
};
#pragma pack()

结构体传参

在结构体传参的时候,最好选择传址调用,有两个好处 1.可以减少对空间的浪费 2.可以对里面的数据进行修改

简单的例子:

代码语言:javascript
复制
c#include <stdio.h>
struct student
{
	char name[20];
	int age;
};
void f(struct student* p)
{

}
int main()
{
	struct student p;
	f(&p);
	return 0;
}

结构体实现位段

位段的实现和结构体类似,只不过位段的成员的类型只能是 unsigned int或者int类型,char类型的也可以。 每个成员名后面要加上:和数字

举个简单的例子:

代码语言:javascript
复制
cstruct stu
{
	int a : 4;
	int b : 2;
};

后面的数字表示bite位。位段不存在对齐。 位段不具有跨平台性: 1.位段中没有规定在内存使用的过程中,是从左使用还是从右使用。 2.不能满足下一个成员使用的空间是舍弃还是保留的问题没有规定。 3.int位段中无符号还是有符号的问题没有规定

结构体实现位段的内存分配

代码语言:javascript
复制
cstruct 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;

枚举

枚举类型的关键字为enum,枚举就是把所有的可能列举出来。 里面的叫做枚举常量。它们也是有值的,如果没有给他们初始化。默认第一个是0,后面的依次增加。

例子:

代码语言:javascript
复制
cenum colour
{
	//注意后面是逗号,
	red,//值是0
	yellow,//值是1
	green//值是2
};
代码语言:javascript
复制
cenum colour
{
	red=2,//这种不是赋值,而是给这个常量一个初始值。
	yellow=5,
	green//它的值为6
};

联合(共用体)

联合类型的定义

关键字union。 里面的成员都是占用同一块空间。

例子:

代码语言:javascript
复制
cunion people
{
	char a;
	int b;
};

联合大小的计算

联合体可能是最大类型所占空间的大小。 当结构体的大小不是最大对齐数的整数倍时,需要对齐。

例子:

代码语言:javascript
复制
cunion Un1
{
	char c[5];
	//开辟了5个字节的空间
	int i;
	//i占4个大小的空间,开辟的空间够用
	//共5个字节的空间,但是不是4的整数倍,存在内存对齐,
	//最终为8个字节的大小
};
union Un2
{
	short c[7];
	int i;
	//开辟的14个字节的空间也不是4的整数倍,需要对齐。
	//最终的大小为16个字节
};
int main()
{
	printf("%d\n", sizeof(union Un1));
	printf("%d\n", sizeof(union Un2));
	return 0;
}

看结果:

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-05-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 结构体
    • 结构体类型的声明
    • 结构的自引用
    • 结构体变量的定义和初始化
    • 🟥结构体内存对齐
    • 修改默认对齐数
    • 结构体传参
    • 结构体实现位段
  • 结构体实现位段的内存分配
  • 枚举
  • 联合(共用体)
    • 联合类型的定义
    • 联合大小的计算
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档