我试图了解何时需要使用address-of运算符&
时通过引用传递参数(对于那些介意我不精确的读者,请将其读作模拟传递引用)函数而不修改函数本身。我将使用struct
给出两个小例子。在struct
中,&
都是通过引用传递的,但其中一个涉及malloc()
的使用而另一个则不涉及。在这个特殊情况下的解释可能会涉及在第二个例子中使用&
,我可以猜到它,但我想要一个更有经验的意见。此外,我的问题更为笼统:当我可以通过引用而不使用#include <stdio.h>
#include <stdlib.h>
struct Author {
char *Name;
int Born;
int Died;
char *Notable_Works;
};
void print_struct(struct Author *thomas_mann);
int main()
{
struct Author thomas_mann;
thomas_mann.Name = "Thomas Mann";
thomas_mann.Born = 1875;
thomas_mann.Died = 1955;
thomas_mann.Notable_Works = "Der Zauberberg";
print_struct(&thomas_mann);
return EXIT_SUCCESS;
}
void print_struct(struct Author *thomas_mann)
{
printf("%s was born in %d and died in %d.\n",
thomas_mann->Name, thomas_mann->Born, thomas_mann->Died);
printf("His most notable work includes ‘%s’.\n",
thomas_mann->Notable_Works);
}
时,是否有规则(或至少是经验法则)?
#include <stdio.h>
#include <stdlib.h>
struct Author {
char *Name;
int Born;
int Died;
char *Notable_Works;
};
void print_struct(struct Author *thomas_mann);
int main()
{
struct Author *thomas_mann = malloc(sizeof(struct Author));
if (!thomas_mann) {
fprintf(stderr, "memory allocation failed");
exit(EXIT_FAILURE);
}
thomas_mann->Name = "Thomas Mann";
thomas_mann->Born = 1875;
thomas_mann->Died = 1955;
thomas_mann->Notable_Works = "Der Zauberberg";
print_struct(thomas_mann);
free(thomas_mann);
return EXIT_SUCCESS;
}
void print_struct(struct Author *thomas_mann)
{
printf("%s was born in %d and died in %d.\n",
thomas_mann->Name, thomas_mann->Born, thomas_mann->Died);
printf("His most notable work includes ‘%s’.\n",
thomas_mann->Notable_Works);
}
例2
def deep_access(x,keylist):
val = x
for key in keylist:
val = val[key]
return val
s = 'key2.key21.key211'
print deep_access(x,s.split('.'))
答案 0 :(得分:3)
规则非常简单。您想调用一个带有指向struct
对象的指针的函数。如果已经指向要使用该功能的对象的指针,则不需要&
。否则,你这样做。
我的意思是&#34;已经有一个指针&#34;?
struct Author *thomas_mann;
在这种情况下,您已经有一个指针,因为变量thomas_mann
的类型为struct Author *
,这是一个指针。我已经删除了初始化,因为你初始化它的内容并不重要; 它已经是一个指针,因为它的类型。
struct Author thomas_mann;
在这种情况下,您还没有指针。变量thomas_mann
的类型为struct Author
,而不是指针类型。
struct Author thomas_mann;
struct Author *p_thomas_mann = &thomas_mann;
在这种情况下,您可以使用print_struct
或p_thomas_mann
来呼叫&thomas_mann
,效果会相同。
了解 C没有通过引用传递非常重要。所有函数参数,无论其类型如何,都由 value 传递。 1 函数print_struct
的参数按值传递。该值碰巧是结构对象的指针,因此它可以使用类似于如何在已通过引用传递的语言中使用reference-argument ,但它实际上并不是语言理论意义上的参考。 (它是 a&#34;引用&#34;因为这个词在英语中是随便使用的。你的混乱是可以理解的,但你必须超越它才能熟练使用C语言。)
1 你可能会看到人们在谈论&#34;通过不可见的引用&#34;但除非您正在实现C编译器,或者必须在汇编级别与C调用约定进行互操作,否则您不必担心这一点,因为它是不可见的。
还有一个皱纹:
struct Author a_thomas_mann[1];
此变量的类型为&#34; struct Author
&#34;数组。因为它有一个数组类型,a_thomas_mann
在大多数(但不是全部)上下文中将被视为&a_thomas_mann[0]
的语法糖。这被称为类型衰变,它可能误导人们认为C确实通过引用传递。再说一遍,它没有。它有一些奇怪的语法糖只与数组有关。
答案 1 :(得分:1)
首先,在C中,所有参数都是按值传递的,尽管您可以使用指针来模拟按引用传递,就像print_struct
在您的示例中所做的那样。
是否使用&
取决于类型。函数print_struct
期望指向struct Author
的指针作为其参数。在第一个示例中,thomas_mann
的类型为struct Author
,因此您需要&thomas_mann
,它是指向struct Author
的指针。在第二个示例中,thomas_mann
的类型为struct Author *
,因此您不需要&
运算符。
答案 2 :(得分:1)
以下引用来自Yu Haos answer ......我不相信我可以更好地解决问题的这一方面。
首先,在C中,所有参数都是按值传递的,尽管您可以使用指针来模拟按引用传递,就像
print_struct
在您的示例中所做的那样。是否使用
&
取决于类型。函数print_struct
期望指向struct Author
的指针作为其参数。在第一个示例中,thomas_mann
的类型为struct Author
,因此您需要&thomas_mann
,它是指向struct Author
的指针。在第二个示例中,thomas_mann
的类型为struct Author *
,因此您不需要&
运算符。
似乎俞昊忘记了一个你还没有提供的例子。
我可以在不使用
&
的情况下通过引用传递规则(或至少是经验法则)吗?
除了前面提到的,当一个数组用于表达式sizeof
或&
地址以外的表达式时,它将被静默转换为指针。因此,请考虑此示例#3:
#include <stdio.h>
#include <stdlib.h>
struct Author {
char *Name;
int Born;
int Died;
char *Notable_Works;
};
void print_struct(struct Author *thomas_mann);
int main()
{
struct Author thomas_mann[] = { { .Name = "Thomas Mann"
, .Born = 1875
, .Died = 1955;
, .Notable_Works = "Der Zauberberg" } };
print_struct(thomas_mann);
return EXIT_SUCCESS;
}
void print_struct(struct Author *thomas_mann)
{
printf("%s was born in %d and died in %d.\n",
thomas_mann->Name, thomas_mann->Born, thomas_mann->Died);
printf("His most notable work includes ‘%s’.\n",
thomas_mann->Notable_Works);
}
......或者哎呀,如果你想进一步压缩它,可以从thomas_mann
删除main
,然后像这样调用print_struct
:
print_struct((struct Author[]){ { .Name = "Thomas Mann"
, .Born = 1875
, .Died = 1955;
, .Notable_Works = "Der Zauberberg" } });
答案 3 :(得分:0)
要通过引用传递,您需要将指针传递给要传递的事物。在第一个示例中,您要传递struct Author
。要传递指向它的指针,您需要其地址,因此您需要使用&
运算符。在第二个示例中,您有一个struct Author*
。这已经是你要传递的struct Author
的指针,所以你可以直接传递指针。
这两种方法的主要区别在于您是在堆栈还是堆上进行了分配。在#1中,您在堆栈上分配了struct Author
,但在#2中,您在堆上分配了它。
答案 4 :(得分:0)
&
运算符不是C中的pass-by-reference
运算符,仅在C ++中。
在示例1中,您将Author
结构的实例的地址传递给函数print_struct
。
在示例2中,您直接将指向Author
结构的实例的指针传递给函数print_struct
。
在这种情况下,两个示例都完全相同,但是示例2要求程序员更加警惕,因为使用malloc
而不是堆栈分配进行堆分配。如果您不打算使用函数范围之外的对象,我建议使用示例1,因为对象将在超出范围后进行清理。这不是示例2的情况,并且可能在不注意时泄漏到内存泄漏。