C 结构体基础
更新时间:2026-08-26。本文是
languages/c/主题入门层第 43 篇(由原《数组、字符串与结构体》拆出)。到目前为止,一个变量只能装一种类型。结构体打破这个限制:把不同类型的成员打包成一个"新类型"——学生有学号+姓名+成绩,不再是三个散变量,而是一个Student。
本文要回答的问题
- 结构体怎么定义、怎么访问成员?
- 结构体变量赋值是"复制"还是"共享"?
- 什么时候用
.、什么时候用->?
一、定义与访问
c
#include <stdio.h>
#include <string.h>
struct Student {
int id; // 学号
char name[32]; // 姓名
float score; // 成绩
};
int main(void) {
struct Student s1; // 声明结构体变量
s1.id = 1001;
strcpy(s1.name, "alice"); // 字符串成员要 strcpy,不能直接 =
s1.score = 92.5;
printf("%d %s %.1f\n", s1.id, s1.name, s1.score);
return 0;
}要点:
- 定义在函数外(
struct Student是类型名,全局可用); - 访问成员用点号
.:s1.id; - 字符串成员不能直接赋值:
s1.name = "alice"是错的(数组不能赋值),要用strcpy或初始化; - 定义时结尾的分号不能省:
struct Student { ... };。
二、初始化:四种姿势
c
struct Student s1 = {1001, "alice", 92.5}; // 1. 按声明顺序
struct Student s2 = {.id = 1002, .score = 88}; // 2. 指定成员(C99,推荐)
struct Student s3 = {1003}; // 3. 部分初始化:其余补 0
struct Student s4 = {0}; // 4. 全 0指定初始化(.成员 = 值)是 C99 特性,顺序随意、只填要填的,工程上最推荐——成员顺序调整也不影响。
三、赋值是拷贝
c
struct Student a = {1001, "alice", 92.5};
struct Student b = a; // 逐个成员复制一份
b.score = 60; // 改 b 不影响 a
printf("%.1f\n", a.score); // 92.5:a 毫发无损结构体赋值 = 成员逐一复制(包括 name 数组整个拷过去)。所以 b = a 安全,两个变量完全独立。这一点和数组完全不同(数组名不能整体赋值)。
四、. vs ->:有指针就有箭头
c
struct Student s = {1001, "alice", 92.5};
struct Student *p = &s;
s.id = 2001; // 结构体变量:用 . 访问
(*p).id = 2001; // 指针解引用后用 . (老写法)
p->id = 2001; // 指针:用 -> (等价的简写)| 场景 | 写法 |
|---|---|
| 结构体变量 | s.id |
| 结构体指针 | p->id |
| 指针解引用再取成员 | (*p).id(与上面等价) |
-> 就是"解引用 + 取成员"的合体。函数里拿到结构体指针时,几乎都写 ->。
五、结构体作为函数参数:传值还是传指针
c
void print_student(struct Student s) { ... } // 传值:整体拷贝
void print_student(const struct Student *s) { ... } // 传指针:只传地址| 方式 | 拷贝量 | 能否修改原值 |
|---|---|---|
传值 struct Student s | 整个结构体(大!) | 不能 |
传指针 const struct Student *s | 8 字节 | 不能(const) |
传指针 struct Student *s | 8 字节 | 能 |
结构体一大的,传指针(尤其是只读时加 const)。几字节的小结构体传值无所谓。性能和取舍见高手层结构体与性能。
六、常见坑对照
| 坑 | 现象 | 对策 |
|---|---|---|
| 定义结尾忘分号 | 编译错误 | }; 不能省 |
字符串成员直接 = | 编译错误 | 用 strcpy/初始化 |
| 传大结构体值 | 性能差 | 传指针 |
p->id 写 p.id | 编译错误 | 指针用 -> |
数组成员比较用 == | 永远不等 | 用 strcmp |
七、与本站主线衔接
一句话总结
结构体把不同类型打包成一个类型:. 访问成员、-> 是"指针解引用+取成员"的合体;赋值=逐成员拷贝;初始化用指定成员(.id = ...)最稳——打包数据是 C 组织复杂信息的第一步,链表、文件记录、网络报文全在它上面。