为何直接传char*无法在函数内malloc赋值,结构体中char*却可行?
C语言指针传值与结构体指针的差异分析
第一段代码的报错原因
先看这段运行报错的代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> void func(char* dest, const char* src) { dest = malloc(strlen(src) + 1); strcpy(dest, src); } int main() { char* name0; char* name1 = "Jam"; func(name0, name1); puts(name0); free(name0); return 0; }
问题根源在于C语言的参数传值机制:
- 当把
name0传给func的dest参数时,C会创建一个name0的副本,函数内的dest和main里的name0是完全独立的两个指针变量。 - 函数里执行
dest = malloc(...)只是修改了这个副本的指向,main中的name0还是未初始化的野指针。 - 后续
puts(name0)会访问野指针指向的非法内存,触发运行错误;free(name0)对野指针操作,同样会引发异常。
第二段代码的解决原理
再看这段能正常运行的代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> struct st { char* name; }; void func(struct st* st1, const struct st* st2); int main(void) { struct st name0, name1; name1.name = "Jam"; func(&name0, &name1); puts(name0.name); free(name0.name); name0.name = NULL; exit(0); } void changename(struct st* st1, const struct st* st2) { st1->name = malloc(strlen(st2->name) + 1); if(st1->name == NULL) exit(1); strcpy(st1->name, st2->name); }
核心逻辑是传递结构体指针,直接修改原结构体的成员变量:
- 传给
changename的是name0的地址(&name0),函数内的st1是指向原结构体的指针,而非副本。 st1->name直接访问原结构体name0中的name指针成员,执行st1->name = malloc(...)时,修改的是原结构体里name变量的指向,main中的name0.name会同步获取到新分配的内存地址。- 因此后续
puts(name0.name)能正确访问合法内存,free也能正常释放资源,不会出现野指针问题。
本质区别总结
- 直接传
char*时,函数操作的是指针的副本,无法改变外部原指针的指向; - 传结构体指针时,函数通过指针直接操作原结构体的成员(包括其中的
char*),修改的是原成员的指向,外部能直接感知到变化。
内容的提问来源于stack exchange,提问作者James Halliday
相关产品推荐
相关产品推荐

