【问题标题】:C: realloc() not functioning as expectedC: realloc() 没有按预期运行
【发布时间】:2014-01-05 20:14:49
【问题描述】:

如果我有一个变量str,我想在堆上分配内存,我会使用malloc(),例如:

char* str = (char*)malloc(sizeof("Hello"));

malloc() 正在返回一个void* 指针,这是我的内存所在的内存位置。 所以现在,我可以给它一些数据

str = "Hello";

所以,内存位置现在已满,有 6 个字节。现在,我想增加它的大小,以包含字符串"Hello World"。所以,我使用realloc()。根据man,void* realloc(void *ptr, size_t size) 将:

The realloc() function changes the size of the memory block pointed to by ptr to size bytes. 
The contents will be unchanged in the range from the start of the region up to the minimum of 
the old and new sizes. If  the  newsize is larger than the old size, the added memory will not 
be initialized.

所以我假设它会将void* 返回到新的、现在更大的内存位置,我现在可以用我的新字符串填充它,所以继续与malloc() 相同的逻辑:

str = (char*)realloc(str, sizeof("Hello World"));

但是,这就是问题所在。这将导致:

*** Error in `./a.out': realloc(): invalid pointer: 0x0000000000400664 ***

在 valgrind 中

Invalid free() / delete / delete[] / realloc()

这表明指针str 有问题。所以我决定删除:

str = "Hello";

它编译得很好,代码如下:

char* str = (char*)malloc(sizeof("Hello"));
str = (char*)realloc(str, sizeof("Hello World"));

我知道指向realloc() 的指针必须来自malloc(),但简单地为其分配数据不应导致realloc() 失败,这表明我做错了什么。

那么,我做错了什么?

这是失败的代码:

char* str = (char*)malloc(sizeof("Hello"));
str = "Hello";
str = (char*)realloc(str, sizeof("Hello World"));
// str = "Hello World"; - this is what I would to be able to do.

注意:这段代码是我从一个更大的程序中剥离出来的,只是 为了证明我遇到的问题,所以我删除了检查等。 另外,我对 C 语言非常陌生,因此问题非常简单(抱歉?),但是经过数小时的工作和研究,我仍然无法弄清楚我做错了什么 - 它似乎对其他人来说都很好! .

【问题讨论】:

  • 不要转换malloc或realloc的结果;这不是必需的,在某些情况下它可以掩盖错误。
  • @wildplasser:好的,让我们清理过时的 cmets(包括这个)。

标签: c memory-management dynamic-memory-allocation realloc


【解决方案1】:

在 C 中,你不能像你试图做的那样复制内存块:

str = "Hello";

那是不是有效的字符串副本;相反,它会使你的 malloc 内存下落不明(“泄漏”),并将指针 'str' 更改为指向硬编码的字符串。

此外,因为 str 现在是一个指向硬编码的静态字符串的指针,所以您不能重新分配它。它从来没有 malloc'd 开始!

要解决此问题,您需要将:str = "Hello"; 更改为:

strcpy(str, "Hello");

【讨论】:

    【解决方案2】:
    str = "Hello";
    

    是问题所在。您分配了一个缓冲区并让str 指向它。然后,您需要复制到该缓冲区。像这样:

    strcpy(str, "Hello");
    

    但是你改变了指针的值。

    当您调用 realloc 时,您必须将指针传递给 realloc,该指针由之前对 malloc、realloc 或类似名称的调用创建。但你没有那样做。因为你修改了str。

    【讨论】:

      【解决方案3】:

      malloc() 正在返回一个void* 指针,这是我的内存所在的内存位置。

      到目前为止一切顺利

      所以现在,我可以给它一些数据

      str = "Hello";
      

      您能够为该内存提供一些数据是正确的,但您在这样做的方式上是错误的:您不能将指针重新分配给字符串文字 - 这会造成内存泄漏。相反,您应该将数据复制到内存块中,如下所示:

      strcpy(str, "Hello");
      

      如果您进行赋值而不是复制,则指针不再指向 malloc 返回的内容,因此将该指针传递给 realloc 是非法的。

      【讨论】:

        【解决方案4】:

        这条指令:

        str = "Hello";
        

        不在堆中分配任何内存。

        【讨论】:

        • 不,它不在堆栈上。字符串文字是静态分配的(即,分配的内存存在于程序的整个执行过程中)。
        • @KeithThompson 你是对的,我说错了。我想说他们在代码段中,这样对吗?
        • 什么是“代码段”? C 语言标准只说字符串字面量对应的数组具有静态存储时长;它没有提到细分市场。它很可能在许多实现的代码段中。重要的是它不在堆上(尽管标准也没有使用“堆”这个词)。
        • 好的,现在它是正确的,但它并不完整,因为它实际上并没有解释问题所在。字符串文字不在堆上的事实只是 OP 代码中发生的几件事之一。
        【解决方案5】:

        char* str = (char*)malloc(sizeof("Hello"));

        您正在为str 动态分配内存。 好。你是cast-ing malloc() 的返回值,不好。

        str = "Hello";

        您正在尝试将static 字符串"Hello" 的地址放入str。 为什么?这实际上是覆盖malloc()分配的内存地址。 str 现在包含的不是动态分配的指针。这是一个 static 地址,不符合 realloc()/ free() 的条件。此外,您将自己带入了内存泄漏的区域。我认为你需要strcpy()。

        【讨论】:

        • @KeithThompson 感谢先生提供的信息。已更新。
        • 不,分配不会覆盖malloc 分配的内存。 str = "Hello" 是一个指针赋值,它导致指针 str 指向包含 "Hello" 的静态数组。 malloc 分配的内存不会被覆盖。相反,唯一指向它的指针会丢失,从而导致内存泄漏。见belenky's answer。
        • @KeithThompson 哎呀。我猜是用词不当。我的意思是malloc()分配的内存address被覆盖,如str本身的value(由malloc()返回)被覆盖。我已经提到了泄漏。猜猜这消除了混乱。并再次感谢您的评论。 :-)
        【解决方案6】:

        如果您想避免重新分配内存问题,请使用函数 strdup :

        char *str = strdup("hello");
        str = strdup("hello word");
        

        strdup 返回一个指向包含复制字符串的存储空间的指针。如果不能保留存储,strdup 返回 NULL。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-05-26
          • 1970-01-01
          • 2017-09-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-11-17
          • 2011-11-20
          相关资源
          最近更新 更多