2010-12-05 40 views
0

我在GWW(用户)的帮助下提出了这段代码,现在我不能释放char **。realloc释放2d数组的问题

这里是我的代码(它只是读取输入文件和打印的名字在它的屏幕上):

编辑:

/* deallocate2D 
corresponding function to dynamically deallocate 2-dimensional array using 
* malloc. 
* accepts a char** as the "array" to be allocated, and the number of rows. 
* as with all dynamic memory allocation, failure to free malloc'ed memory 
* will result in memory leaks 
*/ 
void deallocate2D(char** array, int nrows) { 

    /* deallocate each row */ 
    int i; 
    for (i = 0; i < nrows; i++) { 
     free(array[i]); 
    } 

    /* deallocate array of pointers */ 
    free(array); 
} 

int readInputFile(FILE *fp, char **file_images) { 
    num_lines = 0; 
    int s = 10; 
    char line[MAX_LENGTH]; 
    char **final_filenames; 

    while (fgets(line, sizeof line, fp) != NULL) /* read a line */ { 
     if (line[0] != '\n') { 
      if (num_lines >= s) { 
       s += 100; 
       if ((file_images = (char**) realloc(file_images, s * sizeof (char*))) == NULL) { 
        printf("Error reallocating space for 2d array: %s\n", strerror(errno)); 
        return -1; 
       } 
      } 
      if ((file_images[num_lines] = malloc(MAX_LENGTH * sizeof (char))) == NULL) { 
       printf("Error allocating space for 2d array: %s\n", strerror(errno)); 
       return -1; 
      } 

      strncpy(file_images[num_lines], line, MAX_LENGTH); 
      if (file_images[num_lines] == NULL) { 
       printf("Strncpy failed: %s\n", strerror(errno)); 
       return -1; 
      } 
      printf("name of file %d is: %s \n", num_lines, file_images[num_lines]); 
      num_lines++; 
     } 
    } 
    printf("Num_lines: %d\n",num_lines); 
    //realloc to number of lines in the file, to avoid wasting memory 
    if ((final_filenames = realloc(file_images, num_lines * sizeof (char*))) == NULL) { 
     printf("Error reallocating space for 2d array: %s\n", strerror(errno)); 
     return -1; 
    } else { 
     file_images = final_filenames; 
     deallocate2D(final_filenames, num_lines); 
    } 
    return 0; 
    //don't forget to free lines 2d array! (here or at the end of the code) 
} 

int main(int argc, char *argv[]) { 
    //pixel* image; 
    char **images_filenames; 

    //check parameters 
    if (argc < 4) { 
     printf("Incorrect usage.\nPlease use \"./invert input_filename.ppm charWidth charHeight \"\n"); 
     return -1; 
    } 

    printf("Opening input file [%s]\n", argv[1]); 
    FILE *fpin = fopen(argv[1], "r"); 
    if (fpin == NULL) { 
     printf("Could not open input file\n"); 
     return -1; 
    } 
    if ((images_filenames = ((char**) malloc(10 * sizeof (char*)))) == NULL) { 
     printf("Error allocating initial space for 2d array: %s\n", strerror(errno)); 
     return -1; 
    } 

    if (readInputFile(fpin, images_filenames) == -1) { 
     printf("Error reading image filenames from input\n"); 
     return -1; 
    } 

    fclose(fpin); 
    printf("###########\n"); 

    deallocate2D(images_filenames, num_lines); 

    printf("Done!\n"); 
    return 0; 
} 

所以,我不明白为什么我不能释放final_filenames数组,然后是images_filenames,因为它给了我* glibc检测到 ./main:double free或corruption(!prev):0x0986d228 * *。

无论如何,如果您在此代码中看到不正确的东西,虽然它可行,但请随时指出。

回答

3

问题是您正在释放一个可能已被释放的指针,并且您不知道使用了多少空间没有指向最近分配的空间的指针(通常情况下)所以你不能准确地释放内存。在main(),您有:

char **images_filenames;      

[...]         

if ((images_filenames = ((char**) malloc(10 * sizeof (char*)))) == NULL) { 

[...] 

if (readInputFile(fpin, images_filenames) == -1) { 

[...] 

deallocate2D(images_filenames, num_lines); 

您拨出10个字符指针,然后传递数组到readInputFile()功能。在那个函数里面,有代码来重新分配数组,但是你还没有提供让主程序知道这个新地址是什么的方法。你这样做的方式是通过传递一个指针给你想要修改的指针,或者你有这个函数返回修改过的值(或者你使用肮脏的做法,比如使用全局变量而不是参数 - 但是你不应该那样做)。

所以,你需要:

if (readInputFile(fpin, &images_filenames) == -1) { 

而在readInputFile()功能,你需要一大堆的变化 - 大一个对付三指针参数,再各种编码问题:

int readInputFile(FILE *fp, char ***ppp_files) 
{ 
    num_lines = 0; 
    int s = 10; 
    char line[MAX_LENGTH]; 
    char **file_images = *ppp_files; 
    char **final_filenames; 

更新:我没有注意到,这是简单的初始化NUM_LINES,不宣布它。因此,num_lines必须是某种全局变量......下面的一些评论需要进行调整以适应此情况。


到目前为止,变化是(几乎)微不足道的;我们得到一个'char **'指针,因此是三指针参数。为简化以下代码,请在旧名称(file_images)下创建参数的本地副本,并使用参数指向的值对其进行初始化。以下代码可以继续使用file_images;只需确保参数在返回之前已更新。

除...

您认为“S = 10”,但实际上,你应具备的主要功能,告诉你有多少行可用。它确实分配了10行,但如果没有仔细审查,情况就不清楚。你应该有main()程序说明预分配了多少行 - 这是该函数的一个额外参数。您还要面对的问题是,main()程序无法告知deallocate2D()函数数组中有多少行,因为它不知道。目前还不清楚你的代码是如何编译的;你在这里有一个局部变量num_lines,但是在main()中有一个变量num_lines,对此没有声明。本地变量掩盖任何全局变量。

while (fgets(line, sizeof line, fp) != NULL) { 
     if (line[0] != '\n') { 
      if (num_lines >= s) { 
       s += 100; 

添加大量行是个好主意;它会“分摊”重新分配的成本。

   if ((file_images = (char**) realloc(file_images, s * sizeof (char*))) == NULL) 

虽然您已经使用过该技术,但存在一些具体问题。 纯代码风格:当行包含一个嵌入式的分配和if它变得太长时间,分割转让出来的条件之前:

   file_images = (char**) realloc(file_images, s * sizeof (char*)); 
       if (file_images == NULL) 

现在有只是一个细微的错误离开。如果realloc()失败,会发生什么情况...

是的,您泄漏了内存,因为file_images中的值为空,因此无法释放指向它的内容。 不要写

x = realloc(x, size); 

它泄漏失败的记忆!因此,您需要:

   char **new_space = realloc(file_images, s * sizeof (char*)); 
       if (new_space == NULL) 
       { 
        printf("Error reallocating space for 2d array: %s\n", 
          strerror(errno)); 
        *ppp_files = file_images; 
        return -1; 
       } 
      } 

作为一般规则,错误消息应打印在stderr;我没有解决这个问题。

请注意,我仔细地将file_images的最后一个(非空)值复制到主程序中的变量中。对大小做同样的操作(另一个接口更改)或使用一个结构来封装数组大小和指向其基的指针也许是适当的。

 if ((file_images[num_lines] = malloc(MAX_LENGTH * sizeof (char))) == NULL) 
     { 
      printf("Error allocating space for 2d array: %s\n", strerror(errno)); 
      return -1;    
     } 

该错误返回需要设置*ppp_files = file_images;

  strncpy(file_images[num_lines], line, MAX_LENGTH); 


      if (file_images[num_lines] == NULL) {    
       printf("Strncpy failed: %s\n", strerror(errno)); 
       return -1; 
      }                 

这个测试很奇怪;您知道file_images[num_lines]不为空,并且strncpy()不会更改。您不需要测试和错误处理。

  printf("name of file %d is: %s \n", num_lines, file_images[num_lines]); 
      num_lines++; 
     }                
    } 
    printf("Num_lines: %d\n",num_lines); 

OK ......

//realloc to number of lines in the file, to avoid wasting memory 

良好的感觉。这是不值得的;即使在64位机器上,您最多也只会浪费不到1 KiB。但是,整洁没有害处 - 很好。

if ((final_filenames = realloc(file_images, num_lines * sizeof (char*))) == NULL) { 
     printf("Error reallocating space for 2d array: %s\n", strerror(errno)); 
     return -1; 

同样,您需要在返回之前设置*ppp_files = file_images;

} else { 
     file_images = final_filenames; 

这不会影响main()程序中的值。它将需要再次*ppp_files = file_images;

 deallocate2D(final_filenames, num_lines); 

等一下 - 你取消分配所有你仔细分配的空间吗?所以你不打算使用它?上面的任务只是复制了一个指针值;它没有复制内存......

} 
    return 0; 
    //don't forget to free lines 2d array! (here or at the end of the code) 
} 

这个评论是错误的 - 在成功返回时,内存已被释放。


还是让我猜 - 你不使用“VIM”或编辑其他“VI”衍生物。那些在第一列有大写功能的人,因为那样你可以使用']]'或'[['通过文件向前或向后跳转到下一个或前一个函数的开头。在那些不起作用的代码中,它很令人厌烦。


那么,这是一个开始诊断...这里的工作代码使用结构来中继文件名周围的数组。我已经使用从结构中复制出来的局部变量离开了readInputFile()函数的主体,并确保结构始终正确更新。

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

enum { MAX_LENGTH = 512 }; 

typedef struct FileNameArray 
{ 
    size_t nfiles; /* Number of file names allocated and in use */ 
    size_t maxfiles; /* Number of entries allocated in array */ 
    char **files;  /* Array of file names */ 
} FileNameArray; 

static void deallocate2D(FileNameArray *names) 
{ 
    for (size_t i = 0; i < names->nfiles; i++) 
     free(names->files[i]); 
    free(names->files); 
    names->nfiles = 0; 
    names->files = 0; 
    names->maxfiles = 0; 
} 

static int readInputFile(FILE *fp, FileNameArray *names) 
{ 
    int num_lines = names->nfiles; 
    int max_lines = names->maxfiles; 
    char **file_names = names->files; 
    char line[MAX_LENGTH]; 
    char **final_filenames; 

    while (fgets(line, sizeof line, fp) != NULL) 
    { 
     if (line[0] != '\n') 
     { 
      /* Remove newline from end of file name */ 
      char *nl = strchr(line, '\n'); 
      if (nl != 0) 
       *nl = '\0'; 
      if (num_lines >= max_lines) 
      { 
       max_lines += 100; 
       char **space = realloc(file_names, max_lines * sizeof (char*)); 
       if (space == NULL) 
       { 
        fprintf(stderr, "Error reallocating space for 2d array: %s\n", 
          strerror(errno)); 
        return -1; 
       } 
       names->maxfiles = max_lines; 
       names->files = space; 
       file_names = space; 
      } 
      if ((file_names[num_lines] = malloc(strlen(line) + 1)) == NULL) 
      { 
       fprintf(stderr, "Error allocating space for 2d array: %s\n", 
         strerror(errno)); 
       return -1; 
      } 
      names->nfiles++; 
      strcpy(file_names[num_lines], line); 
      printf("name of file %d is: %s \n", num_lines, file_names[num_lines]); 
      num_lines++; 
     } 
    } 

    printf("Num_lines: %d\n", num_lines); 
    //realloc to number of lines in the file, to avoid wasting memory 
    if ((final_filenames = realloc(file_names, num_lines * sizeof (char*))) == NULL) 
    { 
     fprintf(stderr, "Error reallocating space for 2d array: %s\n", 
       strerror(errno)); 
     return -1; 
    } 
    names->maxfiles = num_lines; 
    names->files = final_filenames; 
    return 0; 
} 

int main(int argc, char *argv[]) 
{ 
    FileNameArray names = { 0, 0, 0 }; 

    //check parameters 
    if (argc < 4) 
    { 
     fprintf(stderr, "Usage: %s input_filename.ppm charWidth charHeight\n", 
       argv[0]); 
     return -1; 
    } 

    printf("Opening input file [%s]\n", argv[1]); 
    FILE *fpin = fopen(argv[1], "r"); 
    if (fpin == NULL) { 
     fprintf(stderr, "Could not open input file %s (%s)\n", 
       argv[1], strerror(errno)); 
     return -1; 
    } 

    if ((names.files = malloc(10 * sizeof (char*))) == NULL) 
    { 
     fprintf(stderr, "Error allocating initial space for 2d array: %s\n", 
       strerror(errno)); 
     return -1; 
    } 
    names.maxfiles = 10; 

    if (readInputFile(fpin, &names) == -1) 
    { 
     fprintf(stderr, "Error reading image filenames from input\n"); 
     return -1; 
    } 

    fclose(fpin); 
    printf("###########\n"); 

    deallocate2D(&names); 

    printf("Done!\n"); 
    return 0; 
} 
+0

哇,现在这是一个分析!我感谢您的努力,我会尽快理解和应用您的建议,只要我把我的手放在C编译器上。是的,我不使用vim或vi,我使用Netbeans或Geany等IDE。我会保持发布:) – neverMind 2010-12-05 23:47:03