C语言 结构体
C语言结构体(Struct)从本质上讲是一种自定义的数据类型,只不过这种数据类型比较复杂,是由 int、char、float 等基本类型组成的。
结构体(Struct)
1 | struct 结构体名{ |
结构体是一种集合,它里面包含了多个变量或数组,它们的类型可以相同,也可以不同,每个这样的变量或数组都称为结构体的成员(Member)。
1 | struct stu{ |
像 int、float、char 等是由C语言本身提供的数据类型,不能再进行分拆,我们称之为基本数据类型;而结构体可以包含多个基本类型的数据,也可以包含其他的结构体,我们将它称为复杂数据类型或构造数据类型。
结构体变量
1 | struct stu stu1, stu2; |
定义了两个变量 stu1 和 stu2,它们都是 stu 类型。
也可以在定义结构体的同时定义结构体变量:
1 | struct stu{ |
定义了两个变量 stu1 和 stu2,它们都是 stu 类型。
成员的获取和赋值
结构体和数组类似,也是一组数据的集合,整体使用没有太大的意义。数组使用下标[ ]获取单个元素,结构体使用点号.获取单个成员。获取结构体成员的一般格式为:
1 | 结构体变量名.成员名; |
通过这种方式可以获取成员的值,也可以给成员赋值:
1 |
|
运行结果:
1 | Tom的学号是12,年龄是18,在A组,今年的成绩是136.5! |
除了可以对成员进行逐一赋值,也可以在定义时整体赋值,例如:
1 | struct{ |
不过整体赋值仅限于定义结构体变量的时候,在使用过程中只能对成员逐一赋值,这和数组的赋值非常类似。
结构体数组
所谓结构体数组,是指数组中的每个元素都是一个结构体。
结构体指针
当一个指针变量指向结构体时,我们就称它为结构体指针。
1 | struct 结构体名 *变量名; |
定义结构体指针的实例:
1 | //结构体 |
结构体和结构体变量是两个不同的概念:结构体是一种数据类型,是一种创建变量的模板,编译器不会为它分配内存空间,就像 int、float、char 这些关键字本身不占用内存一样;结构体变量才包含实实在在的数据,才需要内存来存储。
获取结构体成员
通过结构体指针可以获取结构体成员,一般形式为:
1 | (*pointer).memberName |
或者
1 | pointer->memberName |
第一种写法中,.的优先级高于_,(pointer)两边的括号不能少。如果去掉括号写作_pointer.memberName,那么就等效于(pointer.memberName),这样意义就完全不对了。
第二种写法中,->是一个新的运算符,习惯称它为“箭头”,有了它,可以通过结构体指针直接取得结构体成员;这也是->在C语言中的唯一用途。
上面的两种写法是等效的,我们通常采用后面的写法,这样更加直观。
结构体指针作为函数参数
结构体变量名代表的是整个集合本身,作为函数参数时传递的整个集合,也就是所有成员,而不是像数组一样被编译器转换成一个指针。如果结构体成员较多,尤其是成员为数组时,传送的时间和空间开销会很大,影响程序的运行效率。所以最好的办法就是使用结构体指针,这时由实参传向形参的只是一个地址,非常快速。
位域(位段)
有些数据在存储时并不需要占用一个完整的字节,只需要占用一个或几个二进制位即可。例如开关只有通电和断电两种状态,用 0 和 1 表示足以,也就是用一个二进位。正是基于这种考虑,C语言又提供了一种叫做位域的数据结构。
在结构体定义时,我们可以指定某个成员变量所占用的二进制位数(Bit),这就是位域。请看下面的例子:
1 | struct bs{ |
:
后面的数字用来限定成员变量占用的位数。成员 m 没有限制,根据数据类型即可推算出它占用 4 个字节(Byte)的内存。成员 n、ch 被:
后面的数字限制,不能再根据数据类型计算长度,它们分别占用 4、6 位(Bit)的内存。
C语言标准规定,位域的宽度不能超过它所依附的数据类型的长度。通俗地讲,成员变量都是有类型的,这个类型限制了成员变量的最大长度,
:
后面的数字不能超过这个长度。
C语言标准还规定,只有有限的几种数据类型可以用于位域。在 ANSI C 中,这几种数据类型是 int、signed int 和 unsigned int(int 默认就是 signed int);到了 C99,_Bool 也被支持了。
位域的存储
无名位域
位域成员可以没有名称,只给出数据类型和位宽,如下所示:
1 | struct bs{ |
无名位域一般用来作填充或者调整成员位置。因为没有名称,无名位域不能使用。
上面的例子中,如果没有位宽为 20 的无名成员,m、n 将会挨着存储,sizeof(struct bs) 的结果为 4;有了这 20 位作为填充,m、n 将分开存储,sizeof(struct bs) 的结果为 8。