结构体嵌套:把结构体装进结构体

结构体嵌套,说白了就是一个结构体里面再塞一个结构体。我刚开始学的时候觉得这玩意儿有点绕,后来在项目中处理学生信息时才发现——真香。

举个例子,你要描述一个学生。学生有姓名、年龄,还有家庭住址。地址本身又包含省、市、区、街道。你总不能把地址拆成四个独立字段吧?那代码写出来自己都嫌丑。

struct Address {
    char province[32];
    char city[32];
    char district[32];
    char street[64];
};

struct Student {
    char name[32];
    int age;
    struct Address addr;  // 嵌套结构体
};

这样一写,逻辑就清晰了。访问的时候用 student.addr.city,一层一层点进去,跟剥洋葱似的。

我的习惯:嵌套结构体时,我倾向于把内部结构体定义在外部结构体之前。虽然C语言允许先声明后使用,但顺序写清楚,读代码的人不头疼。

结构体自引用:结构体里藏着自己

自引用,就是结构体里有一个指针,指向跟自己同类型的结构体。你想想看,这玩意儿最经典的应用场景是什么?链表嘛!

struct Node {
    int data;
    struct Node *next;  // 指向下一个节点
};

这里有个坑,我当年踩过。你不能写成 struct Node next; 而不是指针。为什么?因为编译器在解析 struct Node 的时候,它的大小还没确定。你放一个完整的结构体进去,那就成了无限递归——结构体里套结构体,永远算不出大小。

我曾经犯过的错:写二叉树节点时,把左右孩子定义成了结构体变量而不是指针。编译直接报错,我还傻乎乎地查了半天语法书。记住:自引用必须用指针。

自引用在树、图这些数据结构里也随处可见。比如二叉树节点:

struct TreeNode {
    int value;
    struct TreeNode *left;
    struct TreeNode *right;
};

每个节点知道自己左边是谁、右边是谁,整个树就串起来了。

typedef 类型重定义:给结构体起个外号

每次写 struct Student stu; 你不觉得烦吗?反正我烦。尤其是结构体名字一长,敲起来手指头都累。这时候 typedef 就派上用场了。

typedef struct Student {
    char name[32];
    int age;
} Student;  // 以后直接用 Student 就行

更简洁的写法是这样:

typedef struct {
    char name[32];
    int age;
} Student;

匿名结构体 + typedef,一步到位。以后声明变量直接 Student stu;,干净利落。

注意:匿名结构体只能用一次。如果你需要在多个地方引用这个结构体类型,还是老老实实给它起个名字吧。

我在项目中经常用 typedef 给复杂类型起别名。比如函数指针:

typedef int (*CompareFunc)(const void *, const void *);

这样写回调函数的时候,代码可读性直接拉满。

三者结合:一个实际例子

咱们把嵌套、自引用、typedef 揉在一起,写一个简单的链表节点:

typedef struct Node {
    int data;
    struct Node *next;  // 自引用
} Node;

typedef struct {
    Node *head;         // 嵌套指针
    int size;
} LinkedList;

你看,Node 自引用指向下一个节点,LinkedList 嵌套了 Node * 作为头指针。整个链表的结构就出来了。

嗯,这里要注意:自引用里必须用 struct Node *,不能用 Node *。因为 typedef 还没生效呢,编译器还不认识 Node 这个别名。

知识结构图

结构体进阶 结构体嵌套 一个结构体包含另一个 结构体作为成员 例:学生包含地址 结构体自引用 结构体内有指向 自身类型的指针 例:链表、树节点 typedef重定义 给结构体类型 起一个别名 例:typedef struct... 三者结合:定义链表、树等复杂数据结构 注意自引用必须用指针,typedef顺序别搞错

避坑指南

  • 嵌套别太深:超过三层嵌套,代码就难读了。我一般控制在两层以内,再多就拆成指针或者单独的结构体。
  • 自引用必须是指针:这个前面说过了,再强调一遍——不是指针就等着编译报错吧。
  • typedef 和自引用的顺序:自引用里不能用 typedef 之后的别名,因为别名还没定义。老老实实写 struct XXX *
  • 匿名结构体慎用:如果你只需要一个结构体变量,匿名没问题。但要是想定义多个,或者用在函数参数里,还是起个名字吧。
我的一个小技巧:写复杂结构体时,先在纸上画个图。节点之间怎么连、谁包含谁,画清楚了再写代码。这样不容易出错,也方便跟同事沟通。

好了,结构体的嵌套、自引用、typedef 就聊到这儿。这三个东西单独看都不难,但组合起来威力很大。你在项目里遇到复杂数据关系时,想想今天讲的这些,应该能帮你理清思路。


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