基本类型只能存一个值,数组只能存一堆同类型。想表达一个学生有姓名、学号、成绩,三个不同类型绑在一起?结构体(struct)就是干这个的:它能把好几个不同类型的成员装进一个大变量。
结构体是什么
C 语言的结构体是一种特别的大变量,里面装着好几个有名字的小变量。它也是后面对象、类思想的源头。结构体的典型用途:
- 数据的序列化、持久化。
- 作为单个参数,把一堆相关的值打包传进、传出函数。
- 搭链表、二叉树这类复杂数据结构。
最经典的入门示例是点,一个实体里装着 x、y 两个坐标:
struct point {
int x;
int y;
};注意结尾有分号,结构体的定义是一整条语句。现在用它:
struct point p;
p.x = 10;
p.y = 5;
draw(p); /* 一个参数就把两个坐标带过去了 */对比一下没有结构体的苦日子:
int x = 10;
int y = 5;
draw(x, y); /* 传两个参数才表达一个点 */访问结构体成员用点运算符 .。
p 是一个大变量,里面装着有名字的小变量 x、y,通过点运算符分别访问。
typedef:给类型起个别名
每次写 struct point 太长。typedef 能给它换个短名字:
typedef struct {
int x;
int y;
} point;这样再定义点就不用写 struct 关键字了:
point p;
p.x = 10;
p.y = 5;结构体还能装指针,这样它就能存字符串,或指向另一个结构体(这才是它最值钱的地方):
typedef struct {
char *brand; /* 品牌,char 指针即字符串 */
int model; /* 车型年份 */
} vehicle;
vehicle mycar;
mycar.brand = "Ford";
mycar.model = 2007;结构体指针与箭头运算符
结构体变量用 .,结构体指针要用 ->(上一章按引用传参已经见过):
point p;
point *ptr = &p;
p.x = 1; /* 直接访问 */
(*ptr).x = 2; /* 解引用后访问 */
ptr->x = 3; /* 简写,等价于 (*ptr).x */记忆法:实际对象用点,对象指针用箭头。
声明、初始化、成员访问
惯例是从声明到访问一口气走完。下面这段把结构体声明、初始化、成员访问、sizeof 全演示一遍:
#include <stdio.h>
struct Student {
int rollNo;
float height;
char firstLetter;
};
int main() {
struct Student stu1;
stu1.rollNo = 21;
stu1.height = 1.75f;
stu1.firstLetter = 'X';
printf("学号 %d,身高 %.2f,姓名首字母 %c\n",
stu1.rollNo, stu1.height, stu1.firstLetter);
/* 一行初始化:按成员顺序给值 */
struct Student stu2 = {30, 1.82f, 'M'};
printf("第二个学生学号 %d\n", stu2.rollNo);
printf("一个 Student 占 %zu 字节\n", sizeof(struct Student));
return 0;
}结构体 vs 数组:一处关键区别
- 数组:同类型、连续、按下标访问,快,但只能一种类型。
- 结构体:可以由不同类型拼成,灵活,但有内部对齐(成员之间可能留空隙,下一节讲到 sizeof 时会发现它不一定等于成员直接相加)。
下一篇看它的近亲,共用体 union,它俩最大的分歧就在内存布局。