2010-12-05 5 views
0

GWW (사용자)의 도움으로이 코드를 작성했지만 이제는 char **을 해제 할 수 없습니다. 여기 재 할당 후 2 차원 배열 해제 문제

내 코드입니다 (그냥 입력 파일을 읽고 화면에있는 이름을 출력) :

편집 : 그래서

/* 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 or 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() 기능에 해당 배열을 전달합니다. 이 함수에는 배열을 재 할당하는 코드가 있지만 주 프로그램이 새 주소가 무엇인지 알 수있는 방법을 제공하지 않았습니다. 당신이하는 일은 수정하고자하는 것이 무엇이든간에 포인터를 전달하거나 함수가 수정 된 값을 반환하도록하는 것입니다 (또는 매개 변수 대신 전역 변수를 사용하는 것과 같은 sordid 사례에 의존합니다).하지만 그렇게해서는 안됩니다).

그래서, 당신이 필요합니다

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으로 계속 작동합니다. 리턴하기 전에 인수가 갱신되었는지 확인하십시오.

제외

...

은 당신의 10 = '가정하지만, 정말, 당신은 주요 기능이 많은 행이 얼마나 당신에게 있어야합니다. 그것은 10 개의 행을 할당했지만,주의 깊은 조사 없이는 명확하지 않습니다. main() 프로그램에 사전 할당 된 행 수 (함수에 대한 추가 인수)가 있어야합니다.또한 main() 프로그램이 알 수 없기 때문에 배열에있는 행의 수를 deallocate2D() 함수가 알 수 없다는 문제가 있습니다. 코드가 어떻게 컴파일되는지는 명확하지 않습니다. 로컬 변수는 num_lines입니다. 그러나 선언이없는 변수 num_linesmain()에 있습니다. 지역 변수는 모든 전역 변수를 마스킹합니다.

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의 값이 null이기 때문에 메모리를 유출 했으므로 가리키는 데 사용할 방법이 없습니다. 쓰기 절대로 :

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에 인쇄되어야합니다. 나는 이것을 고치지 않았다.

주 프로그램의 변수에 마지막 (null이 아닌) 값인 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]은 null이 아니며 strncpy()은 변경되지 않습니다. 테스트 및 오류 처리가 필요하지 않습니다. OK

  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 

좋은 터치. 간신히 가치가 있습니다. 64 비트 컴퓨터에서도 최대 1Kb 미만의 전력을 낭비하고 있습니다. 그러나, 깔끔하게되는 것에 해로움 - 좋은.

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); 

신중히 할당 된 공간을 모두 할당 해제 하시겠습니까? 결국 당신은 그것을 사용하지 않을 것입니까? 위의 할당은 포인터 값을 복사 한 것입니다. 그것은 메모리의 복사본을 만들지 않았다 ...

이 코멘트는 잘못되었습니다. 성공적인 반환시 메모리는 이미 할당이 해제되었습니다.


Lemme 추측 - 편집을 위해 'vim'또는 다른 'vi'파생물을 사용하지 마십시오. 열 1에 함수의 여는 중괄호가있는 사용자는 ']]'또는 '[['을 사용하여 파일을 통해 다음 또는 이전 함수의 시작으로 앞뒤로 이동할 수 있기 때문에. 작동하지 않는 곳에서 코드 작업을하는 것은 불쾌한 일입니다.


글쎄, 시작 ​​진단 ... 여기에 파일 이름 배열을 전달하는 구조를 사용하는 작업 코드가 있습니다. 구조 밖으로 복사 된 로컬 변수를 사용하여 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

+0

@neverMind : 작업 코드에서 메모리 할당 코드를 함수 'int addFileName (FileNameArray * names, const char * line);'과 같은 메소드를 호출하고'readInputFile()'내에서 그것을 호출했다. 그러면 입력 코드에 혼란이 줄어들 것입니다. 그리고'main()'에는 사전 할당이 없습니다. 이 함수는 단순히 처음부터 할당을 처리합니다. –