对传递引用感到困惑
Confused on pass-by-reference
考虑以下示例,我试图以 C 方式传递引用:
// Function prototypes
void increment(unsigned* number);
int main()
{
unsigned* thing;
increment(thing);
cout << *thing;
return 0;
}
void increment(unsigned* number)
{
number = (unsigned*) malloc(sizeof(unsigned));
*number = 1;
}
我在第 cout << *thing
行遇到程序崩溃。是的,我在这里使用 C++,但我想尝试 C 版本的传递引用,因为我的主要项目是在 C 中。
我通过如下更改代码修复了它:
// Function prototypes
void increment(unsigned** number);
int main()
{
unsigned* thing;
increment(&thing);
cout << *thing;
return 0;
}
void increment(unsigned** number)
{
*number = (unsigned*) malloc(sizeof(unsigned));
**number = 1;
}
现在可以正常运行了,输出为 1,正如我所料。但是,我不明白为什么。我有点困惑为什么在顶部放置一个额外的指针可以解决我的问题。
谢谢!
C 没有传递引用。除数组外,所有参数均按值传递。
在您的第一个版本中,您按值传递变量 thing
。在 increment
函数中,它分配内存并将其分配给局部变量 number
。但这对调用者的变量没有影响,因为传递的只是它的值,而不是对变量的引用。因此 thing
在 increment
returns 时仍未初始化,并且通过它间接导致未定义的行为。
如果函数需要修改调用者的变量,调用者必须传递指向变量的指针,而不仅仅是值。这就是您在第二个版本中所做的。然后函数可以通过指针间接更新变量。
这实质上就是您在 C++ 中使用引用时在幕后发生的事情。在 C 中,您必须明确编写额外的间接级别。
您发布的第二种方式是正确的方式。第一种方法不起作用的原因是当 number
实际上已按值传递时,您正试图修改 number
。因此,尽管您 已经 实际上通过引用将变量 thing
传递给了 increment
,[=12= 的 地址 ] 已按值传递给 increment
。
也许您正在寻找的是这样的东西:
void increment(unsigned* number);
int main()
{
unsigned thing;
increment(&thing);
cout << thing;
return 0;
}
void increment(unsigned* number)
{
*number = 1;
}
在C语言中,所有的函数参数都是按值传递的。因此,您不能更改函数中的值并期望在调用者中反映出来。但是如果传入的值是一个指针,你可以改变它指向的内容。在本例中,thing
的地址被传递给 increment
。那么在increment
中,number
包含main
中thing
的地址。那么你可以更改 number
指向的内容(即 thing
),然后当你 return thing
被修改时。
这与您的第二个示例略有不同,因为没有进行动态内存分配,我相信这正是您的目标。
在您的示例上下文中说按引用传递意味着传递指向对象的指针。
在您的程序中,指针本身就是一个对象
int main()
{
unsigned* thing;
//...
因此,要通过引用传递类型为 unsigned*
的对象 thing
,您必须传递指向该对象的指针
void increment(unsigned** number);
int main()
{
unsigned* thing;
increment(&thing);
//...
我想如果引入一个typedef,你会更清楚。想象一下下面的例子
typedef unsigned* T;
void increment( T* number);
int main()
{
T thing;
increment( &thing );
//...
我希望现在更清楚了。:)
考虑以下示例,我试图以 C 方式传递引用:
// Function prototypes
void increment(unsigned* number);
int main()
{
unsigned* thing;
increment(thing);
cout << *thing;
return 0;
}
void increment(unsigned* number)
{
number = (unsigned*) malloc(sizeof(unsigned));
*number = 1;
}
我在第 cout << *thing
行遇到程序崩溃。是的,我在这里使用 C++,但我想尝试 C 版本的传递引用,因为我的主要项目是在 C 中。
我通过如下更改代码修复了它:
// Function prototypes
void increment(unsigned** number);
int main()
{
unsigned* thing;
increment(&thing);
cout << *thing;
return 0;
}
void increment(unsigned** number)
{
*number = (unsigned*) malloc(sizeof(unsigned));
**number = 1;
}
现在可以正常运行了,输出为 1,正如我所料。但是,我不明白为什么。我有点困惑为什么在顶部放置一个额外的指针可以解决我的问题。
谢谢!
C 没有传递引用。除数组外,所有参数均按值传递。
在您的第一个版本中,您按值传递变量 thing
。在 increment
函数中,它分配内存并将其分配给局部变量 number
。但这对调用者的变量没有影响,因为传递的只是它的值,而不是对变量的引用。因此 thing
在 increment
returns 时仍未初始化,并且通过它间接导致未定义的行为。
如果函数需要修改调用者的变量,调用者必须传递指向变量的指针,而不仅仅是值。这就是您在第二个版本中所做的。然后函数可以通过指针间接更新变量。
这实质上就是您在 C++ 中使用引用时在幕后发生的事情。在 C 中,您必须明确编写额外的间接级别。
您发布的第二种方式是正确的方式。第一种方法不起作用的原因是当 number
实际上已按值传递时,您正试图修改 number
。因此,尽管您 已经 实际上通过引用将变量 thing
传递给了 increment
,[=12= 的 地址 ] 已按值传递给 increment
。
也许您正在寻找的是这样的东西:
void increment(unsigned* number);
int main()
{
unsigned thing;
increment(&thing);
cout << thing;
return 0;
}
void increment(unsigned* number)
{
*number = 1;
}
在C语言中,所有的函数参数都是按值传递的。因此,您不能更改函数中的值并期望在调用者中反映出来。但是如果传入的值是一个指针,你可以改变它指向的内容。在本例中,thing
的地址被传递给 increment
。那么在increment
中,number
包含main
中thing
的地址。那么你可以更改 number
指向的内容(即 thing
),然后当你 return thing
被修改时。
这与您的第二个示例略有不同,因为没有进行动态内存分配,我相信这正是您的目标。
在您的示例上下文中说按引用传递意味着传递指向对象的指针。
在您的程序中,指针本身就是一个对象
int main()
{
unsigned* thing;
//...
因此,要通过引用传递类型为 unsigned*
的对象 thing
,您必须传递指向该对象的指针
void increment(unsigned** number);
int main()
{
unsigned* thing;
increment(&thing);
//...
我想如果引入一个typedef,你会更清楚。想象一下下面的例子
typedef unsigned* T;
void increment( T* number);
int main()
{
T thing;
increment( &thing );
//...
我希望现在更清楚了。:)