我们知道,在 C 中,函数参数传递只有两种方式,值传递、引用传递。
值传递的时候,会把对应的值复制一份传到函数中,形参和原变量是不同的两个变量,而引用传递只是把原变量的地址传递给形参,形参根据这个地址拿到对应的变量。
引用传递的时候,我们需要通过解引用 (*xxx)
的方式拿到变量,这个时候我们就拿到了原始变量,我们在函数中所有针对该变量的操作都是针对原始变量的操作,因为它们是同一个变量。
那这个规则对结构体变量来说是否还适用呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #include <stdio.h>
typedef struct User { char *name; int age; } User;
void test1(User user) { user.name = "name1"; printf("test1: user address = %p\n", (void*)&user); printf("test1: name address = %p\n", (void*)&user.name); }
void test2(User *user) { user->name = "name2"; printf("test2: user address = %p\n", (void*)&user); printf("test2: name address = %p\n", (void*)&user->name); }
int main() { User user = {.age = 23, .name = "name"}; printf("origin: user address = %p\n", (void*)&user); printf("origin: name address = %p\n", (void*)&user.name);
test1(user); printf("test1: user.name = %s\n", user.name);
test2(&user); printf("test2: user.name = %s\n", user.name);
return 0; }
|
输出:
1 2 3 4 5 6 7 8
| origin: user address = 0x7ffee7aae798 origin: name address = 0x7ffee7aae798 test1: user address = 0x7ffee7aae760 test1: name address = 0x7ffee7aae760 test1: user.name = name test2: user address = 0x7ffee7aae768 test2: name address = 0x7ffee7aae798 // 和原始 user 的地址一致 test2: user.name = name2
|
有人会发现
printf("test2: user address = %p\n", (void*)&user);
输出的地址并不是原始 user
的地址,这是为什么呢?
其实实际上 void test2(User *user)
test2(&user);
这两句还是值传递,只是传递的值是一个指针的地址。而上面的打印
&user
的地址实际上
是打印保存这个指针地址变量的地址,听起来有点拗口,但实际上就是这样,我们在
test2
内拿到了一个地址,我们会根据这个地址拿到原始的变量。
如何证实这一点呢?
在 test2
里面加上这一行,获取解引用后的
user
的地址,发现指向是原始 user
的地址。
1
| printf("test2: user address = %p\n", (void*)&(*user)); // 0x7ffee7aae798
|
结论:值传递、引用传递的规则对于结构体变量传参同样适用。