在 C 语言中, 结构体(struct) 是一个或多个变量的集合,这些变量可能为不同的类型,为了处理的方便而将这些变量组织在一个名字之下。由于结构体将一组相关变量看作一个单元而不是各自独立的实体,因此结构体有助于组织复杂的数据,特别是在大型的程序中。
共用体(union),也称为 联合体 ,是用于(在不同时刻)保存不同类型和长度的变量,它提供了一种方式,以在单块存储区中管理不同类型的数据。
今天,我们来介绍一下 C 语言中结构体和共用体的相关概念和使用。
结构体/struct 结构体的定义声明一个结构体类型的一般形式为:
struct 结构体名 { 成员列表 };
其中,成员列表中对各成员都应进行类型声明,即:
类型名 成员名;
例如,我们需要在程序中记录一个学生(student)的数据,包括学号(num)、姓名(name)、性别(sex)、年龄(age)、成绩(score)、地址(addr)等,如下图所示:
如果要表示图中的数据结构,但 C 语言并没有提供这种现成的数据类型,因此我们需要用定义一种结构体类型来表示。
struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; };
上述定义了一个新的结构体类型 struct student (注意, struct 是声明结构体类型时所必须使用的关键及,不能省略),它向编译系统声明,这是一个“结构体类型”,它包括 num 、 name 、 sex 、 age 、 score 、 addr 等不同类型的数据项。
应当说,这里的 struct student 是一个类型名,它与系统提供的标准类型(如 int 、 char 、 float 、 double 等)具有同样的作用,都可以用来定义变量的类型。
结构体变量前面只是声明了一个结构体类型,它相当于一个模型,但其中并无具体的数据,编译系统对其也不分配实际的内存单元。为了能在程序中使用结构体类型的数据,我们应当定义结构体类型的变量,并在其中存放具体的数据。主要以下 3 中方式定义结构体类型变量:
先声明结构体类型,再定义变量名
结构体类型名 结构体变量名;
例如上面我们已经定义了一个结构体类型 struct student ,就可以用它来声明变量:
struct student student1, student2;
定义了 student1 和 student2 为 struct student 类型的变量,它们具有 struct student 类型的结构,后续我们可以对它们进行初始化。
在声明类型的同时定义变量
例如:
struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; } student1, student2;
它的作用与第一种方法相同,即定义了两个 struct student 类型的变量 student1 、 student2 。这种形式的定义的一般形式为:
struct 结构体名 { 成员列表 } 变量名列表;
直接定义结构体类型变量
其省略了结构体名,一般形式为:
struct { 成员列表 } 变量名列表;
关于结构体类型,需要补充说明一点:
类型与变量是不同的概念,不要混淆。我们只能对变量赋值、存取或运算,而不能对一个类型进行赋值、存取或运算。在编译时,对类型是不分配空间的,只对变量分配空间。
简单地说,我们可以 把“结构体类型”和“结构体变量”理解为是面向对象语言中“类”和“对象”的概念 。
此外,结构体里的成员也可以是一个结构体变量。比如我们先声明了一个结构体 struct date :
struct date { int month; int day; int year; };
然后把它应用于声明 struct student 中:
struct student { int num; char name[20]; char sex; int age; float score; struct date birthday; char addr[30]; } student1, student2;
最后,解释一个在阅读大型开源代码(比如 Objective-C Runtime 源码)时容易产生疑问的点:如下两个结构体 SampleA 和 SampleB 声明的变量在内存上其实是完全一样的,原因是因为结构体本身并不带有任何额外的附加信息: