【问题标题】:C: Concatenating Dynamically Allocated StringsC:连接动态分配的字符串
【发布时间】:2021-04-03 21:17:34
【问题描述】:

我搜索了一个适用的答案,但我找不到。我很清楚我无法解决这个问题是由于不熟悉 C。

我正在开发一个将一个动态分配的字符串连接到另一个的函数,它似乎在内存泄漏和 valgrind 领域之外工作;但是,当我使用 valgrind 运行它时,很明显我有一些我无法找到的明显内存泄漏。这似乎是我如何使用 realloc 的问题。

代码如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void dynamCat(char *dest, const char *src) {

    size_t len = strlen(dest)  + strlen(src) + 1;

    printf("strLen: %ld\n", len);

    char *tmp = realloc(dest, len);

    if(tmp == NULL){
        fprintf(stderr, "strAppend: realloc messed up\n");
        free(tmp);
        return;
    } else {
       dest = tmp;
    }

    strcat(dest, src);
}

int main (int argc, char *argv[]) {

        char *one = malloc(4);
        strcpy(one, "tee");

        char *two = malloc(4);
        strcpy(two, "hee");

        printf("one: %s\n", one);
        printf("two: %s\n", two);

        dynamCat(one, two);

        printf("one: %s\n", one);
        printf("two: %s\n", two);

        //freeee
        free(one);
        free(two);


        return 0;

}

命令行输出:

$ ./dynamCat
one: tee
two: hee
strLen: 7
one: teehee
two: hee

这就是坏东西的来源。

在命令行上使用 valgrind 输出:

==28804== Memcheck, a memory error detector
==28804== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==28804== Using Valgrind-3.16.1 and LibVEX; rerun with -h for copyright info
==28804== Command: ./dynamCat
==28804==
==28804== Invalid read of size 1
==28804==    at 0x4841C72: strlen (vg_replace_strmem.c:459)
==28804==    by 0x48D9407: __vfprintf_internal (in /usr/lib/libc-2.33.so)
==28804==    by 0x48C463E: printf (in /usr/lib/libc-2.33.so)
==28804==    by 0x1092EE: main (dynamCat.c:37)
==28804==  Address 0x4a3c040 is 0 bytes inside a block of size 4 free'd
==28804==    at 0x4840D7B: realloc (vg_replace_malloc.c:834)
==28804==    by 0x1091FA: dynamCat (dynamCat.c:11)
==28804==    by 0x1092D6: main (dynamCat.c:35)
==28804==  Block was alloc'd at
==28804==    at 0x483E77F: malloc (vg_replace_malloc.c:307)
==28804==    by 0x10926D: main (dynamCat.c:26)
==28804==
==28804== Invalid read of size 1
==28804==    at 0x4841C84: strlen (vg_replace_strmem.c:459)
==28804==    by 0x48D9407: __vfprintf_internal (in /usr/lib/libc-2.33.so)
==28804==    by 0x48C463E: printf (in /usr/lib/libc-2.33.so)
==28804==    by 0x1092EE: main (dynamCat.c:37)
==28804==  Address 0x4a3c041 is 1 bytes inside a block of size 4 free'd
==28804==    at 0x4840D7B: realloc (vg_replace_malloc.c:834)
==28804==    by 0x1091FA: dynamCat (dynamCat.c:11)
==28804==    by 0x1092D6: main (dynamCat.c:35)
==28804==  Block was alloc'd at
==28804==    at 0x483E77F: malloc (vg_replace_malloc.c:307)
==28804==    by 0x10926D: main (dynamCat.c:26)
==28804==
==28804== Invalid read of size 1
==28804==    at 0x48460D0: mempcpy (vg_replace_strmem.c:1536)
==28804==    by 0x48ED211: _IO_file_xsputn@@GLIBC_2.2.5 (in /usr/lib/libc-2.33.so)
==28804==    by 0x48D915A: __vfprintf_internal (in /usr/lib/libc-2.33.so)
==28804==    by 0x48C463E: printf (in /usr/lib/libc-2.33.so)
==28804==    by 0x1092EE: main (dynamCat.c:37)
==28804==  Address 0x4a3c042 is 2 bytes inside a block of size 4 free'd
==28804==    at 0x4840D7B: realloc (vg_replace_malloc.c:834)
==28804==    by 0x1091FA: dynamCat (dynamCat.c:11)
==28804==    by 0x1092D6: main (dynamCat.c:35)
==28804==  Block was alloc'd at
==28804==    at 0x483E77F: malloc (vg_replace_malloc.c:307)
==28804==    by 0x10926D: main (dynamCat.c:26)
==28804==
==28804== Invalid read of size 1
==28804==    at 0x48460DE: mempcpy (vg_replace_strmem.c:1536)
==28804==    by 0x48ED211: _IO_file_xsputn@@GLIBC_2.2.5 (in /usr/lib/libc-2.33.so)
==28804==    by 0x48D915A: __vfprintf_internal (in /usr/lib/libc-2.33.so)
==28804==    by 0x48C463E: printf (in /usr/lib/libc-2.33.so)
==28804==    by 0x1092EE: main (dynamCat.c:37)
==28804==  Address 0x4a3c040 is 0 bytes inside a block of size 4 free'd
==28804==    at 0x4840D7B: realloc (vg_replace_malloc.c:834)
==28804==    by 0x1091FA: dynamCat (dynamCat.c:11)
==28804==    by 0x1092D6: main (dynamCat.c:35)
==28804==  Block was alloc'd at
==28804==    at 0x483E77F: malloc (vg_replace_malloc.c:307)
==28804==    by 0x10926D: main (dynamCat.c:26)
==28804==
==28804== Invalid free() / delete / delete[] / realloc()
==28804==    at 0x483F9AB: free (vg_replace_malloc.c:538)
==28804==    by 0x109312: main (dynamCat.c:41)
==28804==  Address 0x4a3c040 is 0 bytes inside a block of size 4 free'd
==28804==    at 0x4840D7B: realloc (vg_replace_malloc.c:834)
==28804==    by 0x1091FA: dynamCat (dynamCat.c:11)
==28804==    by 0x1092D6: main (dynamCat.c:35)
==28804==  Block was alloc'd at
==28804==    at 0x483E77F: malloc (vg_replace_malloc.c:307)
==28804==    by 0x10926D: main (dynamCat.c:26)
==28804==
==28804==
==28804== HEAP SUMMARY:
==28804==     in use at exit: 7 bytes in 1 blocks
==28804==   total heap usage: 4 allocs, 4 frees, 4,111 bytes allocated
==28804==
==28804== 7 bytes in 1 blocks are definitely lost in loss record 1 of 1
==28804==    at 0x4840D7B: realloc (vg_replace_malloc.c:834)
==28804==    by 0x1091FA: dynamCat (dynamCat.c:11)
==28804==    by 0x1092D6: main (dynamCat.c:35)
==28804==
==28804== LEAK SUMMARY:
==28804==    definitely lost: 7 bytes in 1 blocks
==28804==    indirectly lost: 0 bytes in 0 blocks
==28804==      possibly lost: 0 bytes in 0 blocks
==28804==    still reachable: 0 bytes in 0 blocks
==28804==         suppressed: 0 bytes in 0 blocks
==28804==
==28804== For lists of detected and suppressed errors, rerun with: -s
==28804== ERROR SUMMARY: 9 errors from 6 contexts (suppressed: 0 from 0)

非常感谢您的帮助。我对 C 还是很陌生,非常感谢您的帮助。

【问题讨论】:

    标签: c memory-leaks


    【解决方案1】:

    如果realloc返回一个空指针,不要释放它的返回值;将空指针传递给free 是没有意义的:

        char *tmp = realloc(dest, len);
    
        if(tmp == NULL){
            fprintf(stderr, "strAppend: realloc messed up\n");
            free(tmp); // This does nothing.
    

    dest 是一个参数,因此分配给它只会更改参数。它不会改变原来的论点:

           dest = tmp; // This changes only the dest inside dynamCat.
    

    要给调用者一个新地址,你必须要么把它作为一个指针返回:

    char *dynamCat(char *dest, const char *src)
    {
        …
        dest = something;
        …
        return dest;
    }
    

    或者你必须把它放入调用者传递的指针中:

    void dynamCat(char **dest, const char *src)
    {
        …
        char *tmp = realloc(*dest, len);
        …
            *dest = tmp;
        }
    
        strcat(*dest, src);
    }
    

    在后一种情况下,当调用dynamCat时,你必须传递一个指针的地址:

            dynamCat(&one, two);
    

    前一种情况,你必须从dynamCat的返回值中取出新指针:

        one = dynamCat(one, two);
    

    【讨论】:

      【解决方案2】:

      realloc 函数可以改变对象的地址。当物体变大时,这样做的必要性是显而易见的:原来的位置可能没有空间。缩小对象时也可能是这样。

      抽象地说,当我们调用realloc(x, newsize) 时,指针x 变得不确定。我们必须捕获返回的指针y = realloc(x, newsize),然后在之前引用x 的所有地方使用它。

      在您的程序中,连接函数返回void,而main 继续引用旧字符串。

      你的dynamCat应该是这样的:

      /* dest is destroyed: use the return value
       * in place of dest!
       */
      char *dynamCat(char *dest, const char *src) {
          size_t len = strlen(dest)  + strlen(src) + 1;
      
          printf("strLen: %ld\n", len);
      
          char *tmp = realloc(dest, len);
      
          if(tmp == NULL){
              fprintf(stderr, "strAppend: realloc messed up\n");
              /* better handling needed here, too */
          }
      
          strcat(tmp, src);
          return tmp;
      }
      

      【讨论】:

      • 非常感谢!您的解释非常有帮助,并且创造了奇迹!
      • 谢谢。请注意,您最好编写不破坏其输入对象的函数。也就是说,dynamCat 可以只保留两个输入字符串,并返回一个新分配的串联字符串。您可能会造成内存泄漏,但内存泄漏不会破坏您的程序,这与“释放后使用”错误不同。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-10-09
      • 1970-01-01
      • 1970-01-01
      • 2011-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多