2

我正在尝试创建一个链接列表,您可以在其中更新节点中的数据,但无论我尝试什么,C 似乎都不允许我更新 void 指针的值(或者更确切地说它指向的位置) . 这是我的测试代码:

void newData(void * d)
{
    char data[] = "world";

    d = &data;
}

int main()
{
        char testData[] = "hello";
        void * testPointer = &testData;

        printf("TestData is %s\n", (char *)testPointer);

        // Modify the data
        newData(&testPointer);

        printf("TestData is %s\n", (char *)testPointer);
}

仅输出::

TestData is hello
TestData is hello

我在这里遗漏了一些明显的东西吗?我也尝试过使用指向指针的指针,但无济于事。

4

3 回答 3

7

我想你需要

void newData(void ** d) 
{
    char data[] = "world";
    *d = &data;  
}     

但是,这有它自己的问题,因为“世界”是堆栈本地的,并且在您从 newData 返回后将无效。

于 2011-02-08T20:29:33.960 回答
4

这有两个问题:

char data[] = "world";

可能是作为函数堆栈帧的一部分创建的。数组降级为指针。因此,当函数调用时ret,它应该已经清理了它的堆栈并且那个地址的内存已经消失了。如果这里有任何操作有效,那是因为你还没有覆盖内存。

你能做什么?声明它static是一种保证(至少根据c99)程序生命周期存在的解决方案(即它不会在堆栈上而是在数据段中分配,并且c库在main之前为您分配它)。但是,由于我怀疑这只是一个演示,因此值得指出的是:

char data[] = "world";
memcpy(d, data, 5);

完全有效,因为您正在复制内容而不是指向值。

newData(&testPointer);

你在这里犯了一个简单的错误。在汇编中,指针是一个内存地址,其中包含另一个内存地址。当您将指针传递给函数时,您希望传递该内存地址,以便在调用该函数时指针的内容(内存地址)以新指针的形式复制到堆栈中。当然,这两个指针都指向同一个东西,这就是你最终实现按引用传递类型的东西的方式。如果您不相信我,请在调试器中观看。

但是,您正在做的是传递指针的地址,因此您正在创建一个指向指向值的指针的指针。想象一下这样的记忆:

|Address|Value
|0x120  |0x121    <-- this is what you're passing with &testPointer
|0x121  |0x122    <-- this is a pointer; it contains the address of a value
|0x122  |h        <-- this is a value.
|0x123  |e
|0x124  |l
...

我希望这能让它更清楚。在我的简单记忆中,您是通过0x120而不是0x121. 你当然可以取消引用两次,但为什么呢?简单的解决方案就是像这样传递指针:

newData(testPointer);
于 2011-02-08T20:49:30.510 回答
1

我觉得稍微改一下代码就可以解决问题:

void newData(void ** d)
{
    char* data = "world";

    *d = data;
}
于 2015-05-19T09:05:57.473 回答