【问题标题】:error in using realloc in C/C++在 C/C++ 中使用 realloc 时出错
【发布时间】:2011-10-14 19:25:45
【问题描述】:
char *t = malloc(2);
t = "as";

t = realloc(t,sizeof(char)*6);

我收到错误“无效指针:0x080488d4 *”..

我在使用内存分配函数时遇到奇怪的错误。是否有任何好的 tuts/guides 可以解释我的内存分配功能。 我正在使用 linux..

请帮忙..

【问题讨论】:

  • sizeof(char) 定义为 1。这是您始终可以信赖的少数几件事之一。无需乘以它。
  • 我愿意声明使用 realloc() 可能是一个错误...
  • @MichaelDorgan,这是一个非常大胆的声明。在很多情况下 realloc 就可以了。
  • 我打算这样做。我见过的每一个使用 realloc 的地方都是一个巨大的黑客,可以正确地让你的缓冲区大小开始。是的,有些地方你不会知道你的大小,但通常我会在 for 循环中看到 realloc 或同样蹩脚的东西。此外,在嵌入式领域,realloc 在创建内存碎片方面确实很糟糕。

标签: c realloc


【解决方案1】:

这是你的问题:

char *t = malloc(2);
t = "as";

您可能认为这会将两个字符的字符串"as" 复制到您刚刚分配的缓冲区中。它实际上所做的是丢弃(泄漏)缓冲区,并将指针改为指向字符串常量"as",它存储在机器代码旁边的只读内存中,而不是malloc 堆上。因为它不在堆上,realloc 看着指针说“不行,那不是我的”。 (计算机给你这个错误是对你很好;当你给realloc一个不是mallocrealloc返回的指针时,如果它允许计算机让恶魔飞出你的鼻子想要。)

这就是你想要做的事情:

char *t = malloc(3);
strcpy(t, "as");

请注意,由于隐式 NUL 终止符,您需要三个字符而不是两个字符的空间。

顺便说一句,你永远不需要将任何东西乘以sizeof(char);它是 1 根据定义

【讨论】:

  • 不要使用 strcpy。使用 strncpy。
  • strcpy 在这种情况下是安全的,而strncpy 具有奇怪的语义,这使得它很少是正确的。你真正想要的是strlcpy,这不是标准的耻辱。或者,真的在这种情况下你想要的是strdup,这也是,唉,不是标准的。
【解决方案2】:

这不是你在 C 中分配字符串的方式。

正确的语法是:

char* t = malloc(3);  // Reserve enough space for the null-terminator \0

strncpy(t, "as", 3);
// Copy up to 3 bytes from static string "as" to char* t.
// By specifying a maximum of 3 bytes, prevent buffer-overruns

分配 2 个字节对于 "as" 是不够的。
C 字符串有一个 1 字节的空终止符,因此您至少需要 3 个字节来保存 "as\0"
\0 代表空终止符)

您编写的代码:t = "as"; 使指针 t“放弃”以前分配的内存,而是指向静态字符串 "as"。使用 malloc 分配的内存“泄漏”并且无法恢复(直到程序终止并且操作系统回收它)。

之后,您可以像原来一样拨打realloc
但是,您应该使用t = realloc(t,6);。如果 realloc 因任何原因失败,你就失去了记忆。

首选方法是:

new_t = realloc(t, 6);
if (new_t != NULL)  // realloc succeeded
{   t = new_t;  
}
else
{  // Error in reallocating, but at least t still points to good memory!
}

【讨论】:

  • 请注意,虽然 strncpy 并不总是创建字符串。例如strncpy(t,"foo",3);很乐意将 foo 中的 3 个字母复制到 t ,这很好,它有 3 个字符的空间。但是,在这种情况下,t 最终不会以 nul 终止,因此之后您不能将其视为 C 字符串。
  • strncpy 会告诉你它是否成功复制了一个 C 字符串。在 strncpy(dest, src, n) 之后,如果有足够的空间, (dest[n-1] == '\0') 将为真,如果您的 "foo",3 示例则为假。
【解决方案3】:

您的代码重新分配t,使其指向其他地方

char *t = malloc(2); //t=0xf00ba12
t = "as"; //t=0xbeefbeef
t = realloc(t,sizeof(char)*6); //confused because t is 0xbeefbeef, not 0xf00b412.

改为使用strcpy

char *t = malloc(3); //don't forget about the '\0'
strcpy(t, "as");
t = realloc(t, 6); //now the string has room to breathe

【讨论】:

    【解决方案4】:

    首先,不要那样做:

    char *t = malloc(2);
    

    改为这样做:

    char *t = malloc(2 * sizeof(char));
    /* or this: */
    char *t = calloc(2, sizeof(char));
    

    这似乎不值得努力,但否则在处理大于 1 字节的类型时可能会遇到问题。

    在这一行:

    t = "as";
    

    您正在分配字符串文字"as" 的地址,因此您的指针不再指向您分配的内存。您需要将文字的内容复制到分配的内存中:

    char *t = calloc(3, sizeof(char));
    /* "ar" is 3 char's: 'a', 'r' and the terminating 0 byte. */
    strncpy(t, "ar", 3);
    /* then later: */
    t = realloc(t,sizeof(char)*6);
    

    您也可以只使用 strdup,这样更安全:

    #include <string.h>
    
    char *t = strdup("ar");
    t = realloc(t,sizeof(char)*6);
    

    别忘了释放内存

    free(t);
    

    【讨论】:

      【解决方案5】:
      char *t = malloc(2);
      

      这意味着您已经创建了一个指向可以容纳 2 个字节的内存位置的指针

           +-+-+ 
      t -> | | |
           +-+-+ 
      

      当你这样做时

      t = "as";
      

      现在你让 t 指向其他地方,而不是它最初指向的地方。现在它不再指向堆了

      t = realloc(t,sizeof(char)*6);
      

      现在您将指针指向只读内存并尝试重新分配它。

      当您使用 malloc 时,您会在堆上分配空间。在这种情况下,t 是指向该位置的指针,即块所在的地址。

      为了在那个地方放一些东西,你需要通过取消引用 t 来复制数据,这是通过在 t 前面写 * 来完成的:

      *t = 'a';   // now 'a' is where t points
      *(t+1)='s'; // now 's' is behind a, t still pointing to 'a'
      

      然而在 C 中,字符串总是以 0(ASCII 值)结束,写成 '\0' 所以为了使它成为一个字符串,你需要附加一个 \0

           +-+-+--+ 
      t -> |a|s|\0|
           +-+-+--+ 
      

      为了做到这一点,你需要 malloc 3 个字节,而不是你可以通过写 *(t+2)='\0'; 来添加 \0

      现在 t 可以被视为指向一个字符串,并用于将字符串作为参数的函数中,例如strlen( t ) 返回 2

      【讨论】:

        猜你喜欢
        • 2012-01-09
        • 2011-05-04
        • 1970-01-01
        • 2021-03-04
        • 1970-01-01
        • 1970-01-01
        • 2017-03-18
        • 2012-08-12
        • 2018-05-22
        相关资源
        最近更新 更多