1. 结构体基础:为什么需要结构体、结构体的定义与声明、结构体变量的初始化

为什么我们需要结构体?

先问大家一个问题:如果你要描述一个学生,需要姓名、学号、年龄、成绩。你会怎么做?

用几个独立的变量?像这样:

char name[20];
int id;
int age;
float score;

嗯,一个学生还行。那如果有100个学生呢?你得写100组这样的变量。更麻烦的是,你要把某个学生的信息传给函数,得传4个参数。想想就头疼。

我早年做嵌入式开发时,遇到过这样一个场景:要管理一个传感器节点的所有状态——温度、湿度、电压、信号强度、时间戳。一开始我用了一堆全局变量,结果代码越写越乱。后来改用结构体,整个代码瞬间清爽了。

结构体的本质,就是把一组相关的数据打包成一个整体。 说白了,就是C语言提供的一种「自定义数据类型」的能力。你可以把不同类型的数据组合在一起,形成一个新的类型。

核心价值: 结构体让数据有了「归属感」。每个数据都知道自己属于哪个对象,代码的可读性和可维护性大幅提升。

结构体的定义与声明

结构体的定义,语法其实很简单:

struct 结构体名 {
    数据类型 成员1;
    数据类型 成员2;
    // ...
};

注意最后的分号,很多人会漏掉。我刚开始学的时候也犯过这个错,编译器报错找了半天。

举个例子,定义一个学生结构体:

struct Student {
    char name[20];
    int id;
    int age;
    float score;
};

这里 struct Student 就是一个新的数据类型。你可以用它来声明变量:

struct Student stu1;      // 声明一个学生变量
struct Student stu2, stu3; // 声明多个

我个人习惯把结构体定义放在头文件里,这样多个源文件都能用。但要注意,结构体定义只是告诉编译器这个类型长什么样,并不分配内存。只有当你用这个类型声明变量时,才会真正分配内存空间。

结构体变量的初始化

初始化结构体变量,有几种常见方式。我按使用频率给大家排个序:

方式一:按成员顺序初始化

struct Student stu1 = {"张三", 1001, 20, 88.5};

这是最直接的方式。花括号里的值按成员定义的顺序依次赋值。但有个坑——如果结构体成员顺序变了,所有初始化代码都得改。我在项目中吃过这个亏,后来就很少用了。

方式二:指定成员初始化(C99起支持)

struct Student stu2 = {
    .name = "李四",
    .id = 1002,
    .age = 21,
    .score = 92.0
};

这种方式更安全,也更清晰。你不需要记住成员的顺序,想初始化哪个就写哪个。没指定的成员会被自动初始化为0(对于指针则是NULL)。

我的建议: 在团队项目中,尽量使用指定成员初始化。代码自文档化,别人一看就知道每个字段的含义。

方式三:先声明,再逐个赋值

struct Student stu3;
strcpy(stu3.name, "王五");
stu3.id = 1003;
stu3.age = 19;
stu3.score = 76.5;

这种方式适合在运行时动态设置值。注意,结构体变量之间可以直接赋值

struct Student stu4 = stu1;  // 拷贝整个结构体

这一点很方便,但要注意:如果结构体里有指针成员,这种浅拷贝会导致多个变量指向同一块内存。我曾经在项目中因为这个问题,排查了一个下午的bug。

结构体的内存布局

这里有个重要的概念——内存对齐。先看个例子:

struct Example {
    char c;    // 1字节
    int i;     // 4字节
    short s;   // 2字节
};

你觉得这个结构体占多少字节?1+4+2=7?不对。实际上,在我的机器上它占12字节。

为什么会这样?因为编译器会在成员之间插入填充字节,让每个成员的地址对齐到它的自然边界。int类型需要4字节对齐,所以char后面会填充3个字节。

成员 偏移量 占用字节
char c 0 1
填充 1-3 3
int i 4 4
short s 8 2
填充 10-11 2

避坑指南: 在嵌入式系统中,如果你需要把结构体直接写入EEPROM或通过通信协议发送,内存对齐会导致数据错位。我曾经在调试一个串口通信协议时,发现接收到的数据总是乱码,最后发现是结构体对齐搞的鬼。解决方案是用 #pragma pack(1) 强制1字节对齐。

知识体系总览

下面这张图,把本章的核心知识点串起来了:

结构体基础 为什么需要结构体 • 数据打包,统一管理 • 函数传参更简洁 • 代码可读性提升 定义与声明 • struct 关键字 + 标签 • 成员列表定义 • 类型声明 vs 变量声明 变量初始化 • 顺序初始化 • 指定成员初始化 • 逐个赋值 内存布局与对齐 • 成员按声明顺序排列 • 编译器插入填充字节 • #pragma pack 控制对齐

小结

结构体是C语言中组织数据的核心工具。它把零散的变量打包成一个整体,让代码更清晰、更易维护。定义时注意分号,初始化时推荐指定成员方式,使用时要留意内存对齐的影响。

嗯,这些基础掌握了,后面讲结构体指针、位域、以及结构体与联合体的配合使用时,你就会觉得顺理成章了。


公众号:蓝海资料掘金营,微信deep3321