【问题标题】:Confused on pass-by-reference对传递引用感到困惑
【发布时间】:2015-10-19 15:28:15
【问题描述】:

考虑下面我尝试以 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 &lt;&lt; *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,就像我预期的那样。但是,我不明白为什么。我有点困惑为什么在顶部分层一个额外的指针可以解决我的问题。

谢谢!

【问题讨论】:

  • 黄金法则:参数总是按值传递。您只更新了指针的本地副本。它没有传播回调用者,因为它是按值传递的,kaboom。请注意在工作版本中您没有更改 number 参数的方式。你改变了 *number,就像你应该做的那样。
  • 我正在开发一个与嵌入式 C 对话的 C++ 应用程序,我认为这就是它令人困惑的原因。
  • C 不支持按引用传递。
  • VS-compiler 接受 C 的引用传递

标签: c memory-management memory-leaks pass-by-reference


【解决方案1】:

C 没有传递引用。除数组外,所有参数均按值传递。

在您的第一个版本中,您通过值传递变量thing。在increment 函数中,它分配内存并将其分配给局部变量number。但这对调用者的变量没有影响,因为只传递了它的值,而不是对变量的引用。所以当increment 返回时thing 仍然是未初始化的,并且通过它间接导致未定义的行为。

如果一个函数需要修改调用者的变量,调用者必须传递一个指向变量的指针,而不仅仅是值。这就是你在第二个版本中所做的。然后函数可以通过指针间接更新变量。

当您在 C++ 中使用引用时,这基本上就是在幕后发生的事情。在 C 中,您必须显式编写额外的间接级别。

【讨论】:

  • 啊,哇,谢谢!我正在 C 程序之上开发一个 C++ 程序,所以这个程序花了我一段时间才弄清楚。感谢您的简单解释。
  • "除数组外,所有参数均按值传递。"所有参数都是按值。不能有数组类型的参数。
  • @newacct 你不能有数组类型的参数,但你可以使用数组作为参数,而且它不会被复制。由于它被转换为指针,它的行为很像按引用传递,因为函数中数组的更改会影响调用者的变量。
【解决方案2】:

也许您正在寻找的是这样的:

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包含thingmain中的地址。那么你可以改变number指向的东西(即thing),然后当你返回时thing已经被修改了。

这与您的第二个示例略有不同,因为没有进行动态内存分配,我相信这就是您的目标。

【讨论】:

    【解决方案3】:

    在示例的上下文中说通过引用传递意味着传递指向对象的指针。

    指针本身就是程序中的对象

    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 );
        //...
    

    我希望现在更清楚了。:)

    【讨论】:

      【解决方案4】:

      您发布的第二种方式是正确的方式。第一种方法不起作用的原因是您试图修改 numbernumber 实际上已按值传递。因此,尽管您已经实际上通过引用将变量thing 传递给increment,但thing地址 已通过值传递给increment

      【讨论】:

        猜你喜欢
        • 2016-03-25
        • 2012-04-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多