C语言中的自定义类型之结构体

1.结构体基础知识

结构体是一些值的集合,这些值成为成员变量。结构体的每个成员可以是不同类型的变量。

2.结构体的声明

struct tag//struct是结构体声明的关键字,tag是自己起的名字
{
	member_lists;//结构体类型的成员变量
}(variable_lists);//结构体定义的类型变量,在结构体声明的时候可以省略

例如描述一个人

struct people
{
	char name[20];//姓名
	int age;//年龄
	char sex[5]//性别
	int tel[15];//电话
}p1;//p1是由此结构体定义出的变量,在结构体声明的时候可以省略

3.结构体的不完全声明

在结构体声明的时候可以不完全声明

//匿名结构体类型
struct
{
	int a;
	char b;
	double c;
}x;//只定义x这一个结构体变量,以后声明的这个结构体都不能再被使用。

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

有了结构体类型,那么定义结构体变量就像是定义字符型变量或者整型变量一样简单,同时,在初始化的时候,也很简单。

struct S1
{
	char name[20];
	int age;
	char sex[5];
};

int main()
{
	struct S1 s={"张三"20"男"};//定义并初始化一个结构体类型的变量
	return 0;
}

5.结构体的内存对齐

结构体定义以后,内存就会为结构体开辟相应的空间,那么,结构体在内存中是如何储存的,这就是一个很有意思的话题,也就是结构体的内存对齐。

struct N1
{
	char a;
	char b;
	int c;
};

struct N2
{
	char a;
	int c;
	char b;
};

以上定义的结构体从形式上来看,在内存中占用的空间应该是相同的,因为在结构体中都是定义了两个char类型的数据,一个int类型的数据,但是结果真的就是这样吗?
下面这个是运行结果:
在这里插入图片描述
我们可以很直观的看出,N1和N2占用的内存空间是不同的,为什么会这样呢,这就涉及到结构体中一个很有意思的内容:结构体的内存对齐。
首先需要掌握内存对齐的规则:
1.结构体内的第一个成员在结构体变量偏移量为0的地址处。
2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数=编译器默认的一个对齐数与该成员大小的较小值。
vs中默认的对齐数大小为8
3.结构体总大小为结构体内部成员最大对齐数(每一个成员都有一个对齐数)的整数倍。
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数的(含嵌套结构体的对齐数)的整数倍。

这些规则是什么意思呢,我们在下面一条一条解释。
以N1为例
struct N1
{
char a;
char b;
int c;
};
首先,结构体的第一个成员在结构体变量偏移量为0的地址处
在内存中开辟空间后,结构体的第一个变量是a,这样就会顶着开辟的内存空间(下简称内存空间)的首地址来放a,a占一个字节。

其次其他成员的变量要对齐到对齐数的整数倍处。
放置完a后开始放置b,b占一个字节,那b的对齐数就是1,而VS编译器的对齐数是8,所以,b的整体对齐数是1,这样就会顶着a来进行放置。
放置完b就开始放置c,c的对齐数为4,而放置完a,b以后,此时的偏移地址为2,并不是c对齐数的整数倍,所以就要丢掉两个字节的空间,从偏移地址为4的地方开始放置c,c占四个字节。

结构体的总大小为结构体内部成员最大对齐数的整数倍
N1结构体中,内部成员最大对齐数为c,对齐数为4,第二步放置完c以后,内存中占了8个字节,8是4(4是c的对齐数)的倍数,那么N1这个结构体的总大小就是8.

分析完N1,我们开始分析N2
struct N2
{
char a;
int c;
char b;
};
首先放置a,a占一个字节,从开辟内存中占一个字节,下一步放置c,c占4个字节,但此时的偏移地址为1,不是4的倍数,那么就会舍弃3个字节的空间,开始从偏移地址为4的地方开始放置,放置完成后,总共8个字节。
放置完c,开始放置b,b占一个字节,可以顶着c放置,那么放置完a以后结构体就占9个字节,但是结构体内部的最大对齐数为4,9显然不是4的倍数,所以又要占3个字节,所以N2的总的内存空间的大小为12。

6.结构体的自引用

结构体其实也存在自引用的现象,比如说一开始定义了一个结构体,又想在定义的结构体中引用自己,是需要怎么做呢。

struct Node
{
	int data;
	struct Node next;
};

上面的这个自引用是否正确呢,如果正确,那么sizeof(struct Node)是多少?

上面的这个自引用是不正确的,因为这样自引用的话是无法来计算Node这个结构体的内存大小的。
正确的自引用方式是下面的方式:

struct Node
{
 int data;
 struct Node* next;
};

我们都知道,指针的大小为4或者8个字节,这样用指针进行自引用的话,就可以很好的计算出Node的大小了。

以上就是结构体的一些知识,其实结构体这个东西博大精深,要研究好还需要下一定的功夫,我这篇文章只是抛砖引玉,也欢迎各个小伙伴进行批评指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C语言结构是一种自定义数据类型,可以将不同类型的变量组合在一起,形成一个新的数据类型结构定义的基本形式如下: ```c struct 结构名 { 数据类型 成员名1; 数据类型 成员名2; // ... }; ``` 其结构名是用户自定义的名称,成员名是结构每个成员的名称,数据类型可以是任意C语言的数据类型,包括基本数据类型和自定义数据类型结构变量的定义方式如下: ```c struct 结构名 变量名; ``` 读取结构的成员变量可以通过“.”运算符来实现,例如: ```c #include <stdio.h> struct Person { char name[20]; int age; }; int main() { struct Person p; printf("请输入姓名:"); scanf("%s", p.name); printf("请输入年龄:"); scanf("%d", &p.age); printf("姓名:%s,年龄:%d\n", p.name, p.age); return 0; } ``` 枚举是一种特殊的数据类型,用于定义一组常量。枚举的定义方式如下: ```c enum 枚举名 { 常量名1, 常量名2, // ... }; ``` 其,枚举名是用户自定义的名称,常量名是枚举每个常量的名称。枚举常量的值默认是从0开始自动递增的,也可以手动指定值。例如: ```c #include <stdio.h> enum Weekday { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }; int main() { enum Weekday today = Tuesday; printf("今天是星期%d\n", today + 1); return 0; } ``` 联合是一种特殊的数据类型,它的成员变量共享同一块内存空间。联合的定义方式如下: ```c union 联合名 { 数据类型 成员名1; 数据类型 成员名2; // ... }; ``` 其,联合名是用户自定义的名称,成员名是联合每个成员的名称,数据类型可以是任意C语言的数据类型,但所有成员的大小不能超过联合的大小。例如: ```c #include <stdio.h> union Number { int i; float f; }; int main() { union Number n; n.i = 123; printf("int: %d, float: %.2f\n", n.i, n.f); n.f = 3.14; printf("int: %d, float: %.2f\n", n.i, n.f); return 0; } ``` 以上就是C语言定义数据类型结构、枚举、联合的基本用法和注意事项。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

嵌入式进阶之路

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

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

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

打赏作者

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

抵扣说明:

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

余额充值