⾃定义类型:结构体

 前言

上次我们讲C语言的数据类型分为内置类型自定义类型,自定义类型包括:结构体,联合,枚举,布尔类型(C99引入),那么今天我们就来详细讲解一下结构体。

1.结构体介绍

1.1为什么要有自定义类型

有同学要问,既然C语言已经提供了内置类型,如:char,int,long,short......那么为什么要有自定义类型呢?假如我们要描述一个人,那么我们就要写出他的身高,体重,性别,年龄等等数据。描述⼀本书需要作者、出版社、定价等。为了解决这个问题,C语言便有了自定义类型,让程序员可以⾃⼰创造适合的类型。

1.2结构体的声明

这就是结构体的声明。其中struct是关键字,用来声明结构体,而tag是结构体的标签,用来标识这个结构体类型,可以在后续代码中使用该标签来声明该结构体类型的变量member-list是结构体成员变量variable-list表示可以直接声明一个或多个结构体变量。切记,大括号后面的分号不能丢。

我们通过下面一段代码来理解结构体:

这段代码我们定义了一个结构体person(此时person相当于tag),而这个结构体包含:high,weight,name,age这四个结构体变量,然后我们使用结构体初始化的方式分别初始化了两个person类型的结构体变量p1,p2;并通过printf打印出了这些数据。

通过这段代码我们明白了结构体如何进行初始化。(关于如何打印这些数据我们下文会讲,请先忽略)这时候细心的小伙伴要问了这里p1和p2创建的地方不同,一个是在main函数内部,另一个在结构体末端。

这就是他俩的区别,一个是全局变量一个是局部变量,它俩的生命周期不同。(不知道这个概念的话可以百度一下,也可以在下面留言,如果人数多的话,下篇文章讲解这个知识点)

1.3结构体成员访问操作符

结构体成员访问的方法有两种,一个是通过“.”操作符,一个是通过“->”操作符。

而“.”操作符是直接访问,“->”操作符是通过结构体指针间接访问。上面我们访问的方式就是直接访问。

使⽤⽅式:结构体变量.成员名(上面的p1,p2就是结构体变量,而high,weight就是成员名)

那么“->”操作符如何使用呢?我们来看下面这段代码

这段代码,我们创建了一个结构体指针变量struct person*pa,指向p1,在通过"->"操作符访问结构体成员变量,从而打印出这些数据。

使⽤⽅式:结构体指针->成员名

  接下来我们来看一段综合代码,可以帮助我们更好的理解结构体的定义,结构体成员变量的创建和修改:

为什么我们要用strcpy修改结构体成员变量name呢?

这是因为在C语言中,字符串是字符数组,数组名本质上是数组的首地址,是一个常量指针,是不可修改的。

2.结构体的特殊说明

这个结构体的声明有什么不一样的地方吗?细心的小伙伴肯定能发现它少了tag(标签),那么问题来了

警告:
编译器会把上⾯的两个声明当成完全不同的两个类型,所以是⾮法的。
匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使⽤⼀次。

这个做一下了解即可,现实写代码尽量不要这么写,不然写着写着就会被公司给开除了哈哈。

2.结构体内存对齐

现在我们已经基本了解结构体了,那么新的问题也就来了:结构体的大小是多少?int类型占4个字节,char类型占1个字节,那么结构体类型占多少个字节呢?

计算之前,我们先要了解一个规则:结构体内存对齐。

2.1结构体内存对齐

对齐规则:

1.结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处
2.其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。
对⻬数=编译器默认的⼀个对⻬数与该成员变量⼤⼩的较⼩值。

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

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

结构体成员变量的对其数就是自身的大小,比如int就是4,char对齐数就是1。

笔者也很讨厌这种繁杂的正规解释,我们通过几组练习来了解这个规则:

通过对齐规则,我们可以画出此图,所以S1大小为9吗?(0到8为9个字节)根据第三条规则,这个结构体成员变量的最大对其数为4,故结构体的总大小应该是4的倍数,所以这个结构体所占内存是12个字节,示意图如下:

我们再来一题:

这是解析,答案是8个字节。

3.结构体传参

两个函数,print1和print2,一个传结构体,一个传结构体的地址,哪个更好一点?

答案是:⾸选print2函数。
原因:
函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。
如果传递⼀个结构体对象的时候,结构体过⼤,参数压栈的的系统开销⽐较⼤,所以会导致性能的下降。(这个涉及到函数栈帧的知识,想了解的可以百度学习,对自己的“内功”会有所帮助)
结论:
结构体传参的时候,要传结构体的地址。

如果文章对您有帮助,还望一键三连,谢谢支持!!!

  • 31
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值