目录
- C语言结构体传参
- 1. 普通传参
- 1.1 测试代码
- 1.2 测试结果
- 1.3 结果分析
- 2. 单指针传参
- 2.1 修改结构体数据
- 2.1.1 测试代码
- 2.1.2 测试结果
- 2.1.3 结果分析
- 2.2 修改结构体地址
- 2.2.1 测试代码
- 2.2.2 测试结果
- 2.2.3 结果分析
- 3. 双指针传参
- 3.1 测试代码
- 3.2 测试结果
- 3.2 结果分析
C语言结构体传参
结构体传参包括三种传参方式
- 普通传参:函数接收到结构体参数后,会复制一份原来的结构体作为形参供函数使用,而函数内的任何操作都是对拷贝结构体的修改,不会影响到原本的结构体变化。
- 单指针传参:函数接收的是一个结构体的地址,该指针指向的是结构体起始地址,也就相当于传入了结构体内所有变量的地址,函数接收到该结构体指针后,我们就可以根据地址访问结构体中每个变量的真实数据,在函数内对结构体内数据的操作,都会影响到原本结构体内数据的变化
- 双指针传参:函数接收的是结构体指针变量的地址,因为一级指针代表的是结构体的地址,在函数中能够操作结构体内的数据,则二级指针指向的是结构体的地址,则同理我们可以根据二级指针访问修改结构体的地址
即通过一级指针,对结构体内数据的操作会影响到原本结构体内数据的变化
而通过二级指针,对结构体地址的操作会影响到原本结构体地址的变化,例如为结构体分配空间
1. 普通传参
1.1 测试代码
#include #include typedef struct Node{ int age; struct Node *next;} Node;// 普通传参void test(Node p){ printf("test():\n"); printf("数据: p.age = %d\n", p.age); printf("地址: p = %x, p->next = %x\n\n", &p, p.next); // 在函数内定义一个新的结构体 Node q; q.age = 3; q.next = NULL; // 修改结构体内的数据 p.age = 2; p.next = &q; printf("数据: p.age = %d\n", p.age); printf("地址: p = %x, p->next = %x\n", &p, p.next); printf("数据: q.age = %d\n", q.age); printf("地址: q = %x, q->next = %x\n\n", &q, q.next);}int main(){ Node p; p.age = 1; p.next = NULL; printf("main():\n"); printf("数据: p.age=%d\n", p.age); printf("地址: p=%x, p->next=%x\n\n", &p, p.next); test(p); printf("main():\n"); printf("数据: p.age=%d\n", p.age); printf("地址: p=%x, p->next=%x\n\n", &p, p.next); return 0;}
1.2 测试结果
1.3 结果分析
由结果可得,通过普通传参
- 函数内的操作对原结构体没有影响
- p结构体的地址、数据均未发生变化
其流程如下图:
2. 单指针传参
2.1 修改结构体数据
2.1.1 测试代码
#include #include typedef struct Node{ int age; struct Node *next;}Node;// 单指针传参,修改结构体数据void ModifyData(Node *p){ printf("ModifyData:\n"); printf("数据: p.age = %d\n", p->age); printf("地址: p = %x, p->next = %x\n\n", p, p->next); // 在函数内定义一个新的结构体 Node q; q.age = 3; q.next = NULL; // 修改数据(age,next) p->age = 2; p->next = &q; printf("数据: p.age = %d\n", p->age); printf("地址: p = %x, p->next = %x\n\n", p, p->next); printf("数据: q.age = %d\n", q.age); printf("地址: q = %x, q->next = %x\n\n", &q, q.next);}int main(){ Node p; p.age = 1; p.next = NULL; printf("main():\n"); printf("数据: p.age = %d\n", p.age); printf("地址: p = %x, p->next = %x\n\n", &p, p.next); ModifyData(&p); printf("main():\n"); printf("数据: p.age = %d\n", p.age); printf("地址: p = %x, p->next = %x\n\n", &p, p.next); return 0;}
2.1.2 测试结果
2.1.3 结果分析
通过ModifyData()函数,由以上测试结果可得
- p结构体内的数据发生了变化
- p结构体的原地址没有发生变化
所以通过结构体的地址,我们可以找到数据的真实地址,进而修改真实数据
2.2 修改结构体地址
2.2.1 测试代码
#include #include typedef struct Node{ int age; struct Node *next;}Node;// 单指针传参, 尝试修改结构体地址Node *ModifyAddress(Node *p){ printf("ModifyAddress():\n"); printf("数据: p.age = %d\n", p->age); printf("地址: p = %x, p->next = %x\n", p, p->next); printf("形参指针变量p的地址 = %x\n\n", &p); // 尝试为指针重新分配地址,并修改原本结构体内部数据 p = (Node *)malloc(sizeof(Node)); p->age = 4; p->next = NULL; printf("数据: p.age = %d\n", p->age); printf("地址: p = %x, p->next = %x\n", p, p->next); printf("形参指针变量p的地址 = %x\n\n", &p); // 返回修改后的结构体指针p return p;}int main(){ Node p; p.age = 1; p.next = NULL; printf("main():\n"); printf("数据: p.age = %d\n", p.age); printf("地址: p = %x, p->next = %x\n\n", &p, p.next); Node *new_p = ModifyAddress(&p); printf("main():\n"); printf("数据: p.age = %d\n", p.age); printf("地址: p = %x, p->next = %x\n", &p, p.next); printf("数据: new_p.age = %d\n", new_p->age); printf("地址: new_p = %x, new_p->next = %x\n\n", new_p, new_p->next); return 0;}
2.2.2 测试结果
2.2.3 结果分析
由以上结果可得,在调用函数体内修改结构体的地址,对原结构体A没有任何影响,因为在调用函数体内修改了形参p的地址,就代表了指针p指向了另一片结构体空间B,如果修改结构体B的内容,这对结构体A来说完全就是八竿子打不着。
由上图我们可以知道,我们在函数内重新开辟了一个新的结构体空间 [731250],而通过动态开辟的空间在函数调用完毕后是不会被释放的,所以在函数调用完毕后,我们仍然可以通过地址 [731250] 访问该结构体的数据,而如果不再使用,我们应该及时释放掉该空间free()
3. 双指针传参
3.1 测试代码
#include #include typedef struct Node{ int age; struct Node *next;} Node;// 双指针传参void test(Node **p){ printf("test:\n"); printf("数据: p.age = %d\n", (*p)->age); printf("地址:p = %x, (*p) = %x, (*p)->next = %x\n", p, (*p), (*p)->next); printf("指针p的地址 = %x\n\n", &p); // 在函数内定义一个新的结构体 Node q; q.age = 3; q.next = NULL; // 为结构体(*p)重新分配地址,并修改变量数据 (*p) = (Node *)malloc(sizeof(Node)); (*p)->age = 2; (*p)->next = &q; printf("数据: p.age = %d\n", (*p)->age); printf("地址:p = %x, (*p) = %x, (*p)->next = %x\n", p, (*p), (*p)->next); printf("指针p的地址 = %x\n\n", &p); printf("数据: q.age = %d\n", q.age); printf("地址: q = %x, q->next = %x\n\n", &q, q.next);}int main(){ Node *p; // 为指针结构体p分配地址 p = (Node *)malloc(sizeof(Node)); p->age = 1; p->next = NULL; printf("main():\n"); printf("数据: p.age = %d\n", p->age); printf("地址: p = %x, p->next = %x\n", p, p->next); printf("指针p的地址 = %x\n\n", &p); test(&p); printf("main():\n"); printf("数据: p.age = %d\n", p->age); printf("地址: p = %x, p->next = %x\n", p, p->next); printf("指针p的地址 = %x\n\n", &p); return 0;}
3.2 测试结果
3.2 结果分析
由结果可得,通过双指针传参,我们可以对结构体的数据和地址都做出实际修改。
其流程如下图: