【问题标题】:C programming problem in dynamic memory allocation动态内存分配中的C编程问题
【发布时间】:2021-02-16 13:31:14
【问题描述】:

问题应该很简单,但我已经花了好几个小时,看不出我的逻辑有什么问题。输出正常工作,但 Valgrind 打印出应该修复的内存问题。我在while循环中添加了origdest = (char*)realloc(origdest, strlen(origdest) + i * sizeof(char));代码,我的问题是为什么不动态调整内存? Valgrind 给出的确切错误是

==9== Invalid write of size 1
==9==    at 0x1087E2: mystrcat (mystrcat.c:18)
==9==    by 0x10883C: main (mystrcat.c:34)
==9==  Address 0x522d046 is 6 bytes inside a block of size 7 free'd
==9==    at 0x4C31D2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9==    by 0x1087C2: mystrcat (mystrcat.c:17)
==9==    by 0x10883C: main (mystrcat.c:34)
==9==  Block was alloc'd at
==9==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9==    by 0x108811: main (mystrcat.c:31)
char *mystrcat(char *dest, const char *src)
{
    char *origdest = dest;
    
    while(*dest) {
        dest++;
    }
    
    int i = 1;

    while (*src) {
        origdest = (char*)realloc(origdest, strlen(origdest) + i * sizeof(char));
        *dest++ = *src++;  // Copies character and increases/moves pointer
        i++;
    }
    
    *dest = 0;

    return origdest;
}

int main(void)
{
    char *str = malloc(7);
    strcpy(str, "Mydogs");

    str = mystrcat(str, "arecool");
    printf("%s\n", str);
    free(str);
}

【问题讨论】:

  • 重新分配后,您必须假设分配的空间移动了。 dest 指针不再有效。您必须重新确定应将额外材料复制到的位置。

标签: c memory strcat


【解决方案1】:

此声明:

Address 0x522d046 is 6 bytes inside a block of size 7 free'd 是说在这些语句之后调用的 realloc() 导致旧指针指向已释放的内存。

在此段之后:

char *origdest = dest;
    
while(*dest) {
        dest++;
}

编辑以解决评论“代码有什么特别的问题,可以改变什么以使其工作?”

对我上面第一个观察结果的解释是,一旦移动指向已分配内存的指针,就像您所做的那样,内存分配表不再具有该内存的准确位置,从而使该内存无法释放。

您在这里声明的目标是创建strcat() 的版本,因此使用realloc() 是一种合理的方法,但要安全地使用它,首先将新内存分配到临时缓冲区中,然后如果分配失败,则原始内存位置仍然存在,并且可以被释放。
另一个产生重大影响的小变化是i 的初始化方式。如果使用 1,它会将第二个字符串的开头放在内存中更远的位置,在第一个字符串之后留下一个 \0 字符,有效地使其成为结果字符串的结尾。即你永远不会看到字符串的附加部分: 在内存中它看起来像这样:

|M|y|d|o|g|s|\0|a|r|e|c|o|o|l|

然后,当尝试将另一个 NULL 终止符放在连接缓冲区的 和 时,缓冲区溢出,导致未定义的行为。

您的代码的以下改编说明了这些以及其他一些简化:

char *mystrcat(char *dest, const char *src)
{
    char *temp = NULL;
    
    int i = 0;//changed from i = 1 as first location to 
              //copy to is len1, not len1 + 1
              //Note, starting at len1 + 1 would leave a NULL character
              //after "Mydogs", effectively ending the string
    //the following are simplifications for use in realloc()
    int len1 = strlen(dest);
    int len2 = strlen(src);

    //call once rather than in a loop.  It is more efficient.
    temp = realloc(dest, len1+len2+1);//do not cast return of realloc
    if(!temp)   
    {
        //handle error 
        return NULL;
    }
    dest = temp;
    while(*src)
    {
        dest[len1 + i] = *src;
        i++;
        src++;
    }
    dest[len1 + i] = 0;//add null terminator

    return dest;     
}

    int main(void)
    {
        char *temp = NULL;          
        char *str = malloc(7);
        if(str)//always a good idea to test pointer before using
        {
            strcpy(str, "Mydogs");
            temp = mystrcat(str, "arecool");
            if(!temp)
            {
                free(str);
                printf("memory allocation error, leaving early");
                return 0;
            }
            str = temp;
            printf("%s\n", str);
            free(str);
        }
        return 0;
    }

为什么是not correct to cast the return of c-m-realloc() in C

【讨论】:

  • 你的第一句话没有意义。在改变dest 之后,origdest 确实 仍然指向原始分配。问题在于,realloc 之后,dest 现在指向已释放的内存,正如 Valgrind 所报告的那样。
  • 先生,感谢您的存在。给出了主要功能,不应对其进行修改,但在您的帮助下,我能够使一切正常。
  • @John - 如果这解决了您的问题,您可以通过单击空心检查将其标记为已接受。
  • @John - 顺便说一句,如果您被告知要保留主要功能,请询问您的讲师如何处理因调用 malloc() 失败而导致的错误而不测试结果.
  • @trentcl - 感谢您指出错误的措辞。它已被编辑..
【解决方案2】:

这里你移动到原始字符串的末尾:

    while(*dest)
        dest++;

在这里你分配了一些新的内存,但dest 仍然指向原始字符串的结尾。所以你在原始字符串结束后覆盖内存。由于您正在重新分配,原始字符串甚至可能不再存在于您之前写入的位置,因为 realloc 可以将数据移动到一个全新的位置。

    while (*src)
    {
        origdest = (char*)realloc(origdest, strlen(origdest) + i * sizeof(char));
        *dest++ = *src++;  // Copies character and increases/moves pointer
        i++;
    }

【讨论】:

  • 我还是不明白......我不记得我什么时候因为编码问题而感到沮丧,哈哈。有人可以就代码的具体错误以及可以进行哪些更改以使其正常工作提供任何提示吗?谢谢...
猜你喜欢
  • 2012-05-02
  • 2021-03-13
  • 1970-01-01
  • 2011-09-13
  • 1970-01-01
  • 1970-01-01
  • 2014-10-09
  • 2011-01-19
  • 2022-01-22
相关资源
最近更新 更多