使用和不使用 & 传递指向函数的指针
Passing pointers to functions with and without &
我试图了解在通过引用传递参数时何时需要使用地址运算符 &
(对于介意我不精确的读者,请阅读此为 simulate pass-by -reference) 到函数而不修改函数本身。我将给出两个使用 struct
s 的小例子。 struct
均通过引用传递,但其中一个涉及 &
的使用,而另一个不涉及。在这个特殊情况下的解释可能会涉及 malloc()
在第二个例子中的用法,我可以猜到,但我想要一个更有经验的意见。此外,我的问题更笼统:当我可以在不使用 &
的情况下通过引用传递时,是否存在规则(或至少是经验法则)?
示例 1
#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);
}
示例 2
#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);
}
首先,在 C 中,所有参数都是按值传递的,尽管您可以使用指针来模拟 按引用传递,就像 print_struct
在您的示例中所做的那样.
是否使用&
取决于类型。函数 print_struct
需要一个指向 struct Author
的指针作为它的参数。在第一个示例中,thomas_mann
的类型为 struct Author
,因此您需要 &thomas_mann
,它是指向 struct Author
的指针。在第二个示例中,thomas_mann
是 struct Author *
类型,因此您不需要 &
运算符。
要通过引用传递,你需要传递一个指向你想传递的东西的指针。在您的第一个示例中,您有一个要传递的 struct Author
。要传递指向它的指针,您需要它的地址,因此您需要使用 &
运算符。在你的第二个例子中,你有一个 struct Author*
。这已经是指向您要传递的 struct Author
的指针,因此您只需传递指针本身即可。
这两种方法的主要区别在于你是在栈上分配还是在堆上分配。在 #1 中,您在堆栈上分配了 struct Author
,但在 #2 中,您在堆上分配了它。
&
运算符不是 C 中的 pass-by-reference
运算符,仅在 C++ 中。
在示例 1 中,您将 Author
结构实例的地址传递给函数 print_struct
.
在示例 2 中,您直接将指向 Author
结构实例的指针传递给函数 print_struct
.
两个示例在这种情况下做的事情完全相同,但示例 2 要求程序员更加警惕,因为堆分配是 malloc
而不是堆栈分配。如果您不打算在创建函数的范围之外使用对象,我建议使用示例 1,因为该对象在超出范围后将被清理。示例2不是这样,一不留神可能会导致内存泄漏。
规则真的很简单。你想调用一个函数,它接受一个指向 struct
对象的指针。如果您已经有一个指针 指向您要对其使用该函数的对象,则不需要&
。否则,你会。
"already have a pointer" 是什么意思?
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;
在这种情况下,您可以用 p_thomas_mann
或 &thomas_mann
调用 print_struct
,效果是一样的。
了解 C 没有引用传递 很重要。所有函数参数,无论其类型如何,都通过 value.1 传递。函数 print_struct
的参数通过值传递。该值恰好是指向结构对象的指针,因此可以使用类似于引用参数在通过引用传递的语言,但它实际上并不是语言理论意义上的引用。 (它 是 一个 "reference" 因为这个词在英语中随意使用,虽然。你的困惑是可以理解的,但你必须超越它才能流利地使用 C。)
1 你可能会看到人们谈论 "pass by invisible reference" 但除非你正在实现 C 编译器,或者必须在汇编级别与 C 调用进行互操作的东西约定,你不需要担心这个,因为它是不可见的。
还有一条皱纹:
struct Author a_thomas_mann[1];
这个变量的类型是"array of struct Author
"。因为它具有数组类型,所以 a_thomas_mann
在大多数(但不是所有)上下文中将被视为 &a_thomas_mann[0]
的语法糖。这称为 type decay 并且它会误导人们认为 C 确实具有通过引用传递。同样,它没有。它有一点奇怪的语法糖,只与数组有关。
以下引述来自...我不相信我能在解决问题的这方面做得更好。
First, in C, all arguments are passed by value, although you could use a pointer to simulate pass by reference, as what print_struct
does in your example.
Whether using &
or not depends on the type. The function print_struct
expects a pointer to struct Author
as its argument. In the first example, thomas_mann
is of type struct Author
, so you need &thomas_mann
which is a pointer to struct Author
. In the second example, thomas_mann
is of type struct Author *
, so you don't need &
operator.
看来于浩忘记说一个你没有提供的例子了。
Is there a rule (or a rule-of-thumb at least) when I can pass by reference without using &
?
除上述情况外,当数组用于 sizeof
或 &
address-of 表达式以外的表达式时,它会自动转换为指针。因此,考虑这个例子 #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);
}
... 或者哎呀,如果你想进一步压缩它,你可以从 main
中删除 thomas_mann
,然后像这样调用 print_struct
:
print_struct((struct Author[]){ { .Name = "Thomas Mann"
, .Born = 1875
, .Died = 1955;
, .Notable_Works = "Der Zauberberg" } });
我试图了解在通过引用传递参数时何时需要使用地址运算符 &
(对于介意我不精确的读者,请阅读此为 simulate pass-by -reference) 到函数而不修改函数本身。我将给出两个使用 struct
s 的小例子。 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);
}
示例 2
#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);
}
首先,在 C 中,所有参数都是按值传递的,尽管您可以使用指针来模拟 按引用传递,就像 print_struct
在您的示例中所做的那样.
是否使用&
取决于类型。函数 print_struct
需要一个指向 struct Author
的指针作为它的参数。在第一个示例中,thomas_mann
的类型为 struct Author
,因此您需要 &thomas_mann
,它是指向 struct Author
的指针。在第二个示例中,thomas_mann
是 struct Author *
类型,因此您不需要 &
运算符。
要通过引用传递,你需要传递一个指向你想传递的东西的指针。在您的第一个示例中,您有一个要传递的 struct Author
。要传递指向它的指针,您需要它的地址,因此您需要使用 &
运算符。在你的第二个例子中,你有一个 struct Author*
。这已经是指向您要传递的 struct Author
的指针,因此您只需传递指针本身即可。
这两种方法的主要区别在于你是在栈上分配还是在堆上分配。在 #1 中,您在堆栈上分配了 struct Author
,但在 #2 中,您在堆上分配了它。
&
运算符不是 C 中的 pass-by-reference
运算符,仅在 C++ 中。
在示例 1 中,您将 Author
结构实例的地址传递给函数 print_struct
.
在示例 2 中,您直接将指向 Author
结构实例的指针传递给函数 print_struct
.
两个示例在这种情况下做的事情完全相同,但示例 2 要求程序员更加警惕,因为堆分配是 malloc
而不是堆栈分配。如果您不打算在创建函数的范围之外使用对象,我建议使用示例 1,因为该对象在超出范围后将被清理。示例2不是这样,一不留神可能会导致内存泄漏。
规则真的很简单。你想调用一个函数,它接受一个指向 struct
对象的指针。如果您已经有一个指针 指向您要对其使用该函数的对象,则不需要&
。否则,你会。
"already have a pointer" 是什么意思?
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;
在这种情况下,您可以用 p_thomas_mann
或 &thomas_mann
调用 print_struct
,效果是一样的。
了解 C 没有引用传递 很重要。所有函数参数,无论其类型如何,都通过 value.1 传递。函数 print_struct
的参数通过值传递。该值恰好是指向结构对象的指针,因此可以使用类似于引用参数在通过引用传递的语言,但它实际上并不是语言理论意义上的引用。 (它 是 一个 "reference" 因为这个词在英语中随意使用,虽然。你的困惑是可以理解的,但你必须超越它才能流利地使用 C。)
1 你可能会看到人们谈论 "pass by invisible reference" 但除非你正在实现 C 编译器,或者必须在汇编级别与 C 调用进行互操作的东西约定,你不需要担心这个,因为它是不可见的。
还有一条皱纹:
struct Author a_thomas_mann[1];
这个变量的类型是"array of struct Author
"。因为它具有数组类型,所以 a_thomas_mann
在大多数(但不是所有)上下文中将被视为 &a_thomas_mann[0]
的语法糖。这称为 type decay 并且它会误导人们认为 C 确实具有通过引用传递。同样,它没有。它有一点奇怪的语法糖,只与数组有关。
以下引述来自
First, in C, all arguments are passed by value, although you could use a pointer to simulate pass by reference, as what
print_struct
does in your example.Whether using
&
or not depends on the type. The functionprint_struct
expects a pointer tostruct Author
as its argument. In the first example,thomas_mann
is of typestruct Author
, so you need&thomas_mann
which is a pointer tostruct Author
. In the second example,thomas_mann
is of typestruct Author *
, so you don't need&
operator.
看来于浩忘记说一个你没有提供的例子了。
Is there a rule (or a rule-of-thumb at least) when I can pass by reference without using
&
?
除上述情况外,当数组用于 sizeof
或 &
address-of 表达式以外的表达式时,它会自动转换为指针。因此,考虑这个例子 #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);
}
... 或者哎呀,如果你想进一步压缩它,你可以从 main
中删除 thomas_mann
,然后像这样调用 print_struct
:
print_struct((struct Author[]){ { .Name = "Thomas Mann"
, .Born = 1875
, .Died = 1955;
, .Notable_Works = "Der Zauberberg" } });