结构体指针传递至两个函数并调用malloc后主结构体未获取数据的技术咨询
问题分析与解决方案
你遇到的核心问题是C语言中指针的按值传递特性,确实需要用双指针(或者其他等价方案)来解决,我来一步步拆解你的疑问:
为什么你的代码没生效?
你提到“如果t的地址为0x1000,传递给first()后引用的地址难道不是0x1000吗?”——这里的误解在于:C语言的函数参数都是按值传递的,哪怕你传的是指针,传递的也只是指针变量的副本。
具体到你的代码流程:
main里定义的T t;是栈上的结构体变量,假设它的地址是0x1000。- 你调用
first(t);的时候,其实是把结构体t的所有值(4个int)拷贝给first的形参t(这是一个指针变量,类型不匹配,编译器应该会报错/警告)——就算忽略类型问题,first里的t是一个独立的指针变量,它的值是0x1000,但这个变量和main里的t完全没关系。 first把这个形参t传给second,second里的t又是一个新的副本指针。你在second里执行t = malloc(20);,只是修改了second里这个副本指针的值,让它指向malloc出来的内存(比如0x3000),但main和first里的指针/结构体完全不受影响。最后memcpy是把数据写到0x3000的内存里,和main里栈上的0x1000地址毫无关系,所以main里的t自然没有数据。
解决方法
根据你的需求,分两种场景给出方案:
场景1:想在函数中给main里的指针分配动态内存并填充数据
这种情况必须用双指针,或者让函数返回指针,因为我们需要修改原指针变量的值:
方案1:双指针实现
#include <stdlib.h> #include <string.h> #include <stdio.h> typedef struct _t { int one; int two; int three; int four; } T; // 假设mydata是预先定义好的T类型数据 T mydata = {1,2,3,4}; void second(T **t) { // *t就是main里的指针变量,修改它的值让它指向malloc的内存 *t = (T*)malloc(sizeof(T)); memcpy(*t, &mydata, sizeof(T)); // 用sizeof更安全,避免硬编码20 } void first(T **t) { second(t); } int main() { T *t = NULL; // 定义指针变量,初始化为NULL first(&t); // 传递指针的地址(双指针) // 现在t指向了填充好数据的内存,可以正常使用 printf("%d %d %d %d\n", t->one, t->two, t->three, t->four); free(t); // 记得释放动态内存 return 0; }
方案2:返回指针实现(更简洁)
如果不想用双指针,可以让函数直接返回malloc的指针:
#include <stdlib.h> #include <string.h> #include <stdio.h> typedef struct _t { int one; int two; int three; int four; } T; T mydata = {1,2,3,4}; T* second() { T *t = (T*)malloc(sizeof(T)); memcpy(t, &mydata, sizeof(T)); return t; } T* first() { return second(); } int main() { T *t = first(); printf("%d %d %d %d\n", t->one, t->two, t->three, t->four); free(t); return 0; }
场景2:只想填充main里已经存在的栈上结构体
如果不需要动态分配内存,只是想把数据拷贝到main里栈上的t中,那根本不需要malloc,直接传递结构体的地址即可(这时候不需要双指针):
#include <string.h> #include <stdio.h> typedef struct _t { int one; int two; int three; int four; } T; T mydata = {1,2,3,4}; void second(T *t) { memcpy(t, &mydata, sizeof(T)); // 直接拷贝到传入的地址(main里t的地址) } void first(T *t) { second(t); } int main() { T t; // 栈上的结构体 first(&t); // 传递结构体的地址,而不是结构体本身 printf("%d %d %d %d\n", t.one, t.two, t.three, t.four); return 0; }
关键总结
- C语言中所有参数都是按值传递的,指针也不例外——传递指针时,函数拿到的是指针的副本,修改副本不会影响原指针。
- 如果要在函数中修改原指针的值(比如让它指向新的内存),必须传递指针的地址(双指针),或者让函数返回新的指针。
- 如果你只是想修改指针指向的内存内容(而不是指针本身的值),传递单指针就足够了。
内容的提问来源于stack exchange,提问作者xf900




