[C语言]结构体介绍与使用(详细)

之前我们学过数组,数组是什么呢?数组是一些同类型的数据的集合,而结构体是不同类型数据的集合

1.1结构体的声明

结构体的声明分完全声明和匿名声明

完全声明

struct tag
{
 member-list; 
}variable-list;
  • struct tag 类型名
  • member - list是成员变量。
  • variable - list 声明结构体后创建的变量(属于全局变量),可以创建多组使用号隔开。

例如,数据库中学生表学生的结构,其中包含名字、学号、成绩。

struct student 
{
	char name[20];
	char students[15];
	double scores;
}stu1;

匿名结构

只能使用一次的结构体声明也只能在声明结构后创建变量。

struct 
{
	char name[20];
	char students[15];
	double scores;
}stu1,stu2;

stu1stu2两个变量的类型是相同的,但是在 该程序中无法再创建一个同类型的变量.
即使有两个相同成员变量的匿名结构体,他们也是不相同的,如图可以看到运行时编译器发生了类型不匹配的警告
在这里插入图片描述

1.2结构体的自引用

结构体的自引用是怎样创建的呢?需要注意的是结构体只能使用结构体指针来完成结构体自引用操作

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

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

结构体变量的定义十分简单,可以声明结构体的同时创建变量如:

struct student 
{
	char name[20];
	char students[15];
	double scores;
}stu1;

声明了student类型的同时创建了变量stu1;
也可自行创建变量

struct student s1;

结构体量的初始化
结构体的初始化可以如数组类似在对大括号里按照结构体成员变量的顺序依次赋值即可。
如:

   struct student s1 = {"zhangsan""zh2222005163951",56.5};

也可以指定成员变量初始化

	struct student stu1 = {.scores = 75.5,.name="hello"};

也和数组类似可以使用不完全初始化。

    s1 = {0}

嵌套结构体则是在大括号里放一个括号

struct Point
{
 int x;
 int y;
}; 
struct num 
{
	int num;
	struct Point;
}
struct num n = {5,{2,3}}; 

1.4 结构体对齐

了解了结构体,那么我们知道结构体大小吗?
在这里插入图片描述

结构体1 占用大小为什么是 8 字节呢?
看看代码2
在这里插入图片描述
代码2 就是 代码1成员变量位置修改了一下,为什么字节又占用飙升到 12 呢?
想要深入探究这个问题,我们需要先知道 结构体内存对齐规则

1.4.1结构体内存对齐

结构体成员不是按照顺序在内存中连续存放的,而是有一定对齐规则。

规则:

  1. 结构体的第一个成员永远放在相较于结构体变量起始位置偏移量为0的位置。
  2. 从第二个成员开始,往后的每个成员都要对齐到某个对齐数的整数倍处
    对齐数:结构体成员自身的大小和默认对齐数的较小值,
    vs上默认对齐数:8,gcc:没有默认对齐数,对齐数就是结构体成员的自身大小
  3. 结构体的总大小,必须是最大对齐数的整数倍
    最大对齐数是:所有成员的对齐数中最大的值
  4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐倍数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

以代码1 为例:
在这里插入图片描述

num成员是结构体第一个成员变量,所以在结构体开辟的内存中从0处开始漂移,又因它属于int类型占用了四个字节,漂移位置从0漂移到4.
ch0的对齐数就是它的字节数,和默认对齐数对比它的对齐数最小,此时漂移位置为4,属于 ch0的对齐数的倍数,占用了4,ch1同理.
最终占用字节为6,而这时结构体成员变量中最大的对齐数为4,而现占的字节内存不属于最大的对齐数的倍数,下漂移两个字节漂移到7位置,现所占字节 8 字节属于最大对齐数的倍数.
最后该结构体占用字节:8字节

代码2 为例:

在这里插入图片描述

ch0是第一个成员变量,所以占用结构体开辟的内存中起始位置.此时漂移到1
num 经过对比,最终对齐数是4,此时漂移数1不是4的倍数,漂移到4开始占用内存
ch1则是占用8这个位置,此时所占字节为 9 字节,不是结构体成员最大对齐数,逻辑下移到直到 是 最大倍齐数的整数倍,所以最终对齐数为 12字节.

嵌套结构体大小:

#include <stdio.h>

struct student
{
	char ch0;
	int num;
	char ch1;
};
struct Node
{
	short sh[3];
	struct student st;
};
int main() {
	printf("%d", sizeof(struct Node));
	return 0;
}

注意:结构体中存在数组时,该数组变量对齐数为数组成员对齐数,当存在指针时,则根据运行环境判断对齐数.
在这里插入图片描述

sh[]是第一个成员变量,但又是一个数组,数组的对齐数则是数组成员对齐数,所以从0开始占用6个字节
st是一个结构体变量,内嵌的结构体变量的对齐数则是该结构体变量中最大成员变量对齐数,6位置,不属于该变量的整数倍,逻辑下移到8处,从该字节开始开辟st数据
最后该字节所占用字节20个字节,20个字节又是成员变量最大对齐数4的整数倍,所以该结构体占用20个字节.

在这里插入图片描述

1.4.2为什么会存在结构体对齐呢?

这是因为结构体的内存对齐是拿空间来换取时间的做法。

在设计结构体的时候,想要对齐和所占空间小

尽量使占用空间相同的变量成员集中在一起.

需要修改默认对齐数可以使用

#pragma pack(8)修改默认对齐数.
#pragma pack()恢复默认对齐数为默认.

1.5 结构体传参

#include <stdio.h>

struct student
{
	char ch0;
	int num;
	char ch1;
}s1 = {'x',5,'c'};
//传值
void foc_1(struct student stTmp) {
	printf("%c", stTmp.ch0);
}
//传址
void foc_2(struct student * stTmp){
	printf("%c", stTmp->ch0);
}
int main() {
	foc_1(s1);
	foc_2(&s1);
	return 0;
}

在使用结构体传参时我们应该注意:

  • 传值既在开辟的函数空间中重新创建一份同类型结构体拷贝,空间开销大
  • 传址调用,既传递内存地址给函数,空间开销小
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值