一、先看代码:顺序表的基本结构

我们定义的顺序表结构体 SL 包含三个成员:
- a :指向动态数组的指针
- size :有效数据个数
- capacity :数组的容量(可存储的最大元素数)
头文件 SeqList.h 中声明了初始化函数 SLInit ,注意这里最终用的是 传指针(传址) 的版本:
// SeqList.h
#define INIT_CAPACITY 4
typedef int SLDataType;
typedef struct SeqList {
SLDataType* a; // 动态数组指针
int size; // 有效数据个数
int capacity; // 空间容量
}SL;
// 注释掉的是“传值”版本,最终用的是“传址”版本
// void SLInit(SL sl);
void SLInit(SL *ps);
二、踩坑现场:“传值”初始化为什么没用?
最开始我写的是 传值版本 的 SLInit ,代码长这样:
// 错误的“传值”初始化(已注释)
void SLInit(SL sl) {
sl.a = NULL;
sl.size = 0;
sl.capacity = 0;
}
然后在 test 函数中调用:
SL seq_list;
SLInit(seq_list); // 直接传结构体变量(传值)
结果运行后发现 seq_list 的成员根本没被初始化——这是为什么?
原因是:C语言中函数参数默认是“值传递”,会拷贝一份参数的副本到函数栈帧中。
当我们把 seq_list 传给 SLInit 时,函数里操作的是 sl ( seq_list 的副本),而 原始的 seq_list 完全没被修改。函数执行完,副本 sl 被销毁,相当于“白忙活一场”。
三、正确姿势:“传址”才能真正修改结构体
要想修改 原始结构体变量,必须传它的 地址(指针),让函数直接操作原始变量的内存。
最终正确的 SLInit 是 传址版本:
// 正确的“传址”初始化
void SLInit(SL* ps) {
ps->a = NULL; // 通过指针访问结构体成员(->)
ps->size = 0;
ps->capacity = 4; // 初始容量设为INIT_CAPACITY(4)
}
调用时传结构体的地址:
SL seq_list;
SLInit(&seq_list); // 传地址(&取地址)
此时函数里的 ps 是 seq_list 的指针,通过 ps->a 、 ps->size 访问的是 原始变量 seq_list 的内存,修改才能真正生效。
四、总结:传值 vs 传址的核心区别
方式 本质 能否修改原始变量 用法场景
传值(SL sl) 拷贝副本 ❌ 不能 仅读取结构体内容,不修改时用
传址(SL *ps) 操作原始变量的内存 ✅ 能 需要修改结构体时必须用
1059

被折叠的 条评论
为什么被折叠?



