C 结构体指针
更新时间:2026-08-26。本文是
languages/c/主题入门层第 45 篇。结构体可以很大(几十字节),直接搬来搬去很浪费;结构体指针只占 8 字节,还能指向堆上的动态对象——更重要的是,结构体指针是链表的起点。
本文要回答的问题
- 怎么声明结构体指针、怎么访问成员?
- 结构体在堆上怎么创建和释放?
- 自引用结构体是什么?链表节点怎么写?
一、声明与箭头访问
c
struct Student {
int id;
char name[32];
};
struct Student s = {1001, "alice"};
struct Student *p = &s; // 指向栈上的 s
p->id = 2001; // 等价 (*p).id = 2001
printf("%d %s\n", p->id, p->name);-> 在结构体基础提过,这里是主场:拿到结构体指针,一律用 -> 访问成员。
二、指向堆上的结构体
配合 malloc,结构体可以活在堆上,生命周期由你控制:
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student {
int id;
char name[32];
};
int main(void) {
struct Student *p = malloc(sizeof(struct Student)); // 堆上分配
if (p == NULL) return 1; // 判空!malloc 可能失败
p->id = 1001;
strcpy(p->name, "alice");
printf("%d %s\n", p->id, p->name);
free(p); // 用完释放!
return 0;
}三步曲:malloc 分配 → -> 使用 → free 释放。漏 free 就是内存泄漏;free 后还用就是悬垂指针(NULL 与野指针讲过)。
三、自引用结构体:链表的种子
结构体成员可以是指向同类型结构体的指针——这是链表、树的基础:
c
struct Node {
int data;
struct Node *next; // 指向下一个节点(自引用)
};c
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node *next;
};
int main(void) {
struct Node n1 = {10, NULL};
struct Node n2 = {20, NULL};
n1.next = &n2; // n1 → n2 → NULL
// 顺着链表走
for (struct Node *p = &n1; p != NULL; p = p->next) {
printf("%d ", p->data); // 10 20
}
printf("\n");
return 0;
}为什么成员是 struct Node *next 而不是 struct Node next?如果是后者,Node 里套 Node,Node 里又套 Node……无限递归,编译器无法确定大小。指针占固定 8 字节,问题消失。"结构体内包含指向自己的指针"就是自引用结构体,链表的定义方式。
四、结构体指针作为函数参数
c
void update_score(struct Student *s, float new_score) {
s->score = new_score; // 直接改外部结构体
}
void print_student(const struct Student *s) { // 只读:加 const
printf("%d %s\n", s->id, s->name);
}| 参数形式 | 拷贝量 | 能否修改 | 适用 |
|---|---|---|---|
struct Student s | 整个结构体 | 不能 | 小结构体、快照语义 |
const struct Student *s | 8 字节 | 不能 | 只读大结构体(推荐) |
struct Student *s | 8 字节 | 能 | 需要修改 |
经验法则:结构体超过 16 字节就传指针;只读加 const,既省拷贝又明确意图。
五、常见坑对照
| 坑 | 现象 | 对策 |
|---|---|---|
| malloc 后忘判空 | 解引用 NULL | 判空 |
| 忘 free | 内存泄漏 | 谁分配谁释放 |
| free 后还用 | 悬垂 | 置 NULL + ASan |
p.id 写错 | 编译错误 | 指针用 -> |
| 自引用写错(非指针成员) | 编译错误 | struct Node *next |
六、与本站主线衔接
一句话总结
结构体指针用 -> 访问成员;malloc + free 三步曲管堆上结构体的生命周期;自引用(成员是指向自己的指针)是链表/树的种子;函数参数里大结构体传指针、只读加 const——结构体指针一掌握,数据结构的世界就打开了。