在 C 语言中,结构体(struct)是一种用户自定义的数据类型。它是一种复合类型,可以将不同数据类型的变量组合在一个名称下面,从而方便管理和使用。
C 结构体简介
在现实生活中,一个事物往往具有不同的属性,需要用不同的数据类型才能准确描述。比如一个学生的基本信息一般包括学号、姓名、性别、年龄等。其中学号一般是一个整型,姓名是一个字符数组,性别是一个字符型,年龄又是一个整型。

对于相同类型的多个数据,我们可以使用 “数组” 的方式来表示。但是对于不同类型的多个数据,此时又应该怎么表示呢?这个时候就需要借助结构体类型了。
在 C 语言中,我们可以使用结构体类型的方式来定义同一个事物的多种属性。虽然这些属性值的类型是不一样的,但是它们都是有着密切联系的,都用于描述同一个事物。
语法:
struct 类型名
{
类型1 成员名1;
类型2 成员名2;
……
类型n 成员名3;
};说明:
对于每一个成员来说,它的类型可以是基本类型(如整型、浮点型、字符型),也可以是数组,甚至还可以是另一个结构体类型。
需要特别注意,大括号后面的分号是不能省略的,如果省略就会报错。那么结构体类型是怎么使用的呢?我们来看一个简单例子就懂了。
示例 1:结构体的基本用法
#include <stdio.h>
// 定义一个结构体类型
struct Student
{
int id; // 学号
char name[10]; // 姓名
char gender; // 性别,'m' 表示男,'f' 表示女
int age; // 年龄
};
int main(void)
{
// 定义一个结构体变量
struct Student stu = {1001, "Jack", 'm', 20};
// 获取成员的值
printf("学号:%d\n", stu.id);
printf("姓名:%s", stu.name);
return 0;
}运行结果如下。
学号:1001
姓名:Jack分析:
在这个例子中,我们使用 struct 关键字定义了一个名为 Student 的结构体类型。注意 Student 是一个类型名,并不是一个变量名。类型名和变量名怎么区分呢?比如 int a = 10;,int 就是一个类型名,而 a 就是一个变量名。
结构体类型和基本类型等不一样,int、float、char 等类型是 C 语言自带的,而结构体类型是需要手动自定义的。比如这里的 Student 类型就是我们自定义的一种结构体类型。结构体类型可以看出是一种 “组合型” 的类型,每一个成员都有属于自己的一种基本类型。不过要清楚一点,成员的类型可以相同,也可以不同,并不一定非要全部不同。
对于结构体的类型名,首字母一般大写。当然使用小写也是没关系的,只是不推荐这样做。因为首字母大写可以更加直观地看出来这是一个特殊的类型,以区分于其他数据类型。此外,结构体类型的定义一般放在 main() 函数 的外面,当然放在里面也是可以的。
定义好了一个类型之后,接下来就是使用这个类型来定义一个变量了。对于基本类型来说,我们都是使用 “类型 变量名=值;” 这样的方式来定义一个变量,比如 int a = 10;。对于结构体类型来说,我们同样是使用这种方式来定义一个结构体变量。需要注意的是,结构体变量在声明时需要同时赋值初始化(即赋值),而不能分开来写。
// 正确
struct Student stu = {1001, "Jack", 'm', 20};
// 错误
struct Student stu;
stu = {1001, "Jack", 'm', 20};结构体类型和结构体变量,这两个是不一样的东西,小伙伴们不要搞混了。结构体类型是一种 “类型”,而结构体变量是一个 “变量”。
最后,如果想要获取结构体变量中某一个成员的值,我们可以使用点运算符(.) 来实现,也就是 “变量名.成员名”。比如上面是 stu.id 就是获取 id 成员的值,而 stu.name 就是获取 name 成员的值。
通过上面这个例子,小伙伴们对结构体类型也有一定的了解了。接下来我们再来深入了解一下各个语法细节。
提示: C 语言中的 “结构体(struct)” 与其他语言(如 Python、Java 等)中的 “类(class)” 相似,小伙伴们可以对比理解一下。
C 定义结构体变量
对于结构体类型来说,如果想要定义一个结构体类型的变量,我们主要有以下 3 种方式。
1. 先定义类型,后定义变量
struct Student
{
int id; // 学号
char name[10]; // 姓名
char gender; // 性别,'m' 表示男,'f' 表示女
int age; // 年龄
};
struct Student stu = {1001, "Jack", 'm', 20};2. 定义类型的同时定义变量(带类型名)
struct Student
{
int id; // 学号
char name[10]; // 姓名
char gender; // 性别,'m' 表示男,'f' 表示女
int age; // 年龄
} stu = {1001, "Jack", 'm', 20};3. 定义类型的同时定义变量(不带类型名)
struct
{
int id; // 学号
char name[10]; // 姓名
char gender; // 性别,'m' 表示男,'f' 表示女
int age; // 年龄
} stu = {1001, "Jack", 'm', 20};对于第 2 种方式,我们在定义类型的同时,可以定义多个变量,而不仅仅是一个变量。
对于第 3 种方式,这种方式是不带一个类型名的,但需要在后面紧接着去定义一个结构体变量。这种方式在实际开发中用得比较少,简单了解一下即可。
示例 2:定义多个结构体变量
#include <stdio.h>
// 定义结构体类型
struct Student
{
int id; // 学号
char name[10]; // 姓名
char gender; // 性别,'m' 表示男,'f' 表示女
int age; // 年龄
};
int main(void)
{
// 定义多个结构体变量
struct Student stu1 = {1001, "Jack", 'm', 20};
struct Student stu2 = {1002, "Lucy", 'f', 21};
struct Student stu3 = {1003, "Tony", 'm', 19};
// 获取成员的值
printf("Jack 的学号:%d\n", stu1.id);
printf("Lucy 的学号:%d\n", stu2.id);
printf("Tony 的学号:%d", stu3.id);
return 0;
}运行结果如下。
Jack 的学号:1001
Lucy 的学号:1002
Tony 的学号:1003分析:
在这个例子中,我们定义了 3 个结构体变量:stu1、stu2、stu3,它们都属于 Student 类型,因此都拥有相同的成员(属性):id、name、gender、age。虽然拥有相同的成员,但是成员的值并不一定就是相同的。
C 修改结构体成员的值
对于结构体变量来说,我们可以使用点运算符(.)来获取一个成员的值。如果想要修改一个成员的值,我们同样也是通过点运算符(.)来实现。
语法:
变量名.成员名 = 新值;示例 3:修改成员的值
#include <stdio.h>
struct Student
{
int id; // 学号
char name[10]; // 姓名
char gender; // 性别,'m' 表示男,'f' 表示女
int age; // 年龄
};
int main(void)
{
struct Student stu = {1001, "Jack", 'm', 20};
// 修改成员的值
stu.id = 1002;
// 获取成员的值
printf("学号:%d", stu.id);
return 0;
}运行结果如下。
学号:1002分析:
结构体变量 stu 的 id 成员初始值为 1001,stu.id = 1002; 表示将 id 成员的值修改为 1002。当然了,小伙伴们可以尝试修改一下其他成员的值。
结构体类型其实非常简单,它其实就是将多种数据类型组合成一个混合型的类型,这样我们就可以用它来表示某一个事物的多个属性。其中结构体成员的类型可以相同,也可以不同。成员的类型除了可以是基本类型(如 int、float、char),还可以是数组、指针等。
如果小伙伴们有接触过 Python、Java 等编程语言,会发现结构体类型和面向对象中 “类的定义” 很相似。但是结构体类型和面向对象还是有着本质上的区别的,比如面向对象中一个类除了有属性之外还有方法,而结构体类型是没有方法这种东西的。对于具体某一个功能,我们依旧是使用面向过程的方式来实现。
注意: 对于 int、char 等基本类型的成员,我们可以直接用 “=” 赋值修改。但对于 char 数组类型的成员(如 name),是不能直接用 “=” 赋值的,而必须使用 strcpy() 函数,例如 strcpy(stu.name, "Rose");。
最后,对于结构体类型,我们可以总结出以下非常重要的 4 点。
- 结构体类型是一种 “类型”,结构体变量是一个 “变量”。结构体变量是使用结构体类型来定义的。
- 结构体类型是一种 “组合” 类型,它由多个其他类型的成员组合而成。
- 结构体所有成员的类型可以是相同的,也可以是不同的。
- 通过点运算符来获取或修改一个结构体成员的值,比如 stu.name。
