【问题标题】:How do I modify a pointer to void through a function?如何通过函数修改指向 void 的指针?
【发布时间】:2011-06-23 16:57:18
【问题描述】:

我正在尝试创建一个链表,您可以在其中更新节点中的数据,但无论我尝试什么,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

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

【问题讨论】:

  • 参数类型错误,应该是void**。
  • 或者直接称它为`newData(testPointer);'?
  • ` void * testPointer = &testData;` 此语句中不需要地址运算符。当您将数组分配给指针时,会分配数组的地址。因此,您可以改为void * testPointer = testData;。您的程序中还有其他语句可以执行此操作。

标签: c pointers void void-pointers


【解决方案1】:

我认为你需要

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

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

【讨论】:

  • 不过,我认为如果他将其更改为 const char* data = "world";因为“world”将是二进制文件中的硬编码字符串。
  • 这是否意味着我需要为新值分配更多空间,还是有更简单的方法?我只是想更改 testPointer 中的字符串。
  • @Lewis:没有字符串“内部”测试指针。 C 风格的字符串不是这样工作的。 C 风格的字符串本质上是一个指向某个字符序列的第一个字符的指针。所以这个字符序列一定是存在的。当您将文字分配给 char 指针 (char* data = "world") 时,包含 "world\0" 的 char 序列由编译器隐式创建,并存储在程序数据中。所以赋值只是把之前分配的数据的地址赋给变量。
  • 好的,感谢您的帮助 :)。所以只是为了确认,我肯定需要一个指向指针的指针吗?我得到了一个头文件,它的接口只有一个指针,但我怀疑它可能是错误的。
【解决方案2】:

这有两个问题:

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

【讨论】:

  • 正如另一个答案的评论中解释的那样,局部变量'data'在堆栈上,但“world\0”存在于程序的数据段中,所以data[] =“world " 是有效的。
  • 另一种理解方式是:'data'是栈上的局部变量,但它指向的位置不在栈上。
【解决方案3】:

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

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

    *d = data;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-19
    • 2016-12-18
    • 2013-07-19
    • 2020-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多