【问题标题】:Function hierarchy and C pointers initialization problem函数层次结构和 C 指针初始化问题
【发布时间】:2011-08-19 08:55:49
【问题描述】:

我正在将我的一个项目从 C++ 转换为 C,并且事情进展顺利,因为我一开始并没有使用很多 C++ 功能。但是我遇到了一个特殊的问题,我设法在一个小型测试程序中复制了该问题。对我来说没有意义,所以我会尝试用代码来解释。

typedef struct foo
{
    int num1;
    float num2;
    char* name;
}foo;

//This function allocates and initializes a foo object
foo* Initfoo()
{
    foo* f = malloc(sizeof(foo));
    f->num1 = 1024;
    f->num2 = 3.14;

    f->name = malloc(100);
    strcpy(f->name,"eleos re paidia");

    //Just before returning here by checking the f pointer we can see
    // it is initialized correctly
    return f;
}



 void afunctest(foo* f)
 {
    ///... suppose this function does stuff before ...

    //here it initializes the foo pointer
    f = Initfoo();
    ///...and after here suppose the function also does more stuff..

    //by checking at this point in the program the pointer is still initialized 
    //correctly to   what InitFoo initialized it to
    int asd =5;
 }


int main()
{

    foo* f = 0;

    //should do stuff and also initialize the foo* f
    afunctest(f);

    //when we check here the pointer f is still 0 as if afunctest() function never ran
    int asd = 5;

    return 0;
}

所以基本上简单地说,我们声明了一个 foo 指针并将其初始化为零。然后我们将该指针传递给 afunctest() 函数,该函数应该做一些事情并初始化它以供以后使用。在 afunctest() 函数内部,它似乎已正确初始化,但一旦我们回到 main(),它的值仍然为 0,就好像该函数从未运行过一样。

起初我认为这是我原始程序中的一个非常复杂的错误,因为它变得非常复杂,但能够在这里复制它意味着我错过了与 C++ 相比在 C 中使用指针的一些基本知识。你能指出这一点吗?我究竟做错了什么?提前感谢您的任何反馈。

P.S.:我的编译器是 Windows 7 下的 GCC。

【问题讨论】:

  • 我敢打赌你对应的 C++ 函数有不同的签名,否则它也不会在那里工作......

标签: c pointers


【解决方案1】:

您正在更改 f 的本地副本。这对调用者没有影响。

void afunctest(foo* f)
{
    f = Initfoo(); /* No effect for the caller of afunctest
}

试试这样的:

void afunctest(foo **f)
{
    /* ... */
    *f = Initfoo();
}

/* In main. */
foo* f = 0;
functest(&f);

顺便还有一个C FAQ: Pass pointer Init

【讨论】:

  • 哦,所以 C 总是按值传递。很高兴知道。然后有很多代码来检查类似的错误。谢谢,现在说得通了。
  • 谢谢。常见问题解答也确实如您所说的那样进行了解释。感觉真的很愚蠢,我已经不知道了。
  • @Lefteris:请注意,这与 C++ 中的相同。如果您明确指定参数是引用(使用&),C++ 仅通过引用传递。通常,C++ 引用更像是指针而不是原始值,因此 foo *&f 参数通常会转换为 foo **f 而不是 foo *f
  • 是的,我知道 C++ 就是这样做的。我可能在我的项目中混淆了函数中的参数,并且没有观察引用并将它们转换为双指针。现在我知道并且很高兴发现了一个重大错误:)
【解决方案2】:

解决方案实际上很简单——记住 C 总是按值传递,所以当你在 afunctest 函数中设置 f 时,它不会在主函数中更新你的 f。

为此,您需要像这样使用 **f:

void afunctest(foo** f)
 {

    //here it initializes the foo pointer
    *f = Initfoo();

 }

然后这样称呼它:

int main()
{

    foo* f = 0;

    //should do stuff and also initialize the foo* f
    afunctest(&f);

    return 0;
}

【讨论】:

  • 感谢您的回答。现在说得通了。必须检查我所有的代码,然后检查传递指针的函数层次结构。
【解决方案3】:

C 是按值传递的。如果你想从afunctest() 中改变f,你需要传递一个指针给它并操作值它指向。

例如:

#include <stdio.h>

static void fn (int x, int *y) {
    x = 42;     // Changes local copy of x, doesn't affect a.
    *y = 42;    // Changes value *pointed to* by local y (which is b in caller).
}

int main (void) {
    int a = 1;
    int b = 1;
    fn (a, &b); // Pass a and *address of* b.

    printf ("%d %d\n", a, b);
    return 0;
}

输出结果:

1 42

就您拥有的代码而言,那将是:

void afunctest (foo **f) {
    *f = Initfoo();
}

int main (void) {
    foo* f = 0;
    afunctest (&f);
    return 0;
}

【讨论】:

  • 哦,所以 C 总是按值传递。很高兴知道。然后有很多代码来检查类似的错误。谢谢,现在说得通了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多