2016-09-25 6 views
2

다음 함수에서 연결된 목록의 머리글 구조에 대한 포인터를 반환하고 싶습니다. fread가 struct의 문자열을 읽을 수 없기 때문에 malloc을 사용해야합니다. 몇몇 변수와 newheader-> name 문자열을 가리킨다. 다음 함수에서 임시 변수를 해제하면 반환 된 새 헤더는 null 값만 출력하고, 그렇지 않으면 메모리 누수가 발생하지만 함수는 정상적으로 작동합니다. NULL 값이 아닌 완전한 링크 된 목록의 머리를 반환 할 수 있기를 원합니다.fread는 C의 이진 파일에서 struct의 문자열 값을 읽을 수 없습니다

struct head *read_strings(char *file) { 
    FILE *my_file; 
    struct head * newheader = NULL; 
    char *str = NULL; 
    newheader = buildhead(); 

    int len, lenStr, lenTotal = 0; 
    printf("\n\n"); 
    my_file = fopen(filename, "rb"); 
    if (my_file == NULL) { 
     printf("error\n"); 
    } 
    fread(&len,sizeof(int),1, my_file); 
    newheader->name = malloc(len); 
    fread(newheader->name,sizeof(char),len, my_file); 
    fread(&newheader->length,sizeof(int),1, my_file); 

    if (newheader->length != 0) { 
     if (newheader->length == lenTotal) { 
      fread(&lenStr,sizeof(int),1, my_file); 
      str = malloc(lenStr); //char *str = malloc(lenStr); 
      fread(str,sizeof(char),lenStr, my_file); 
      create_string(newheader, str); 
      lenTotal += lenStr; 
      str = NULL; //free(str); 
     } 
     else { 
      while (newheader->length != lenTotal) { 
       fread(&lenStr,sizeof(int),1, my_file); 
       str = malloc(lenStr); //char *str = malloc(lenStr); 
       fread(str,sizeof(char),lenStr, my_file); 
       create_string(newheader, str); 
       lenTotal += lenStr; 
       str = NULL; //free(str); 
      } 
     } 
    } 

    printString(newheader); 
    fclose(my_file); 
    free(str); 
    //if i free newheader->name here then I get no memory leaks 
    //free(newheader->name); 
    freeStructure(newheader); 
    return newheader; 
} 

이진 파일에서 문자열을 읽고 struct에 저장해야합니다. 하지만 구조체의 문자열 변수에 값을 직접 저장할 수 없다. 새로운 문자열을 malloc하고 가리 키지 않는 한. 위 코드에서 newheader-> length를 fread로 읽을 수 있지만 newheader-> name은 읽을 수 없다는 것을 알 수 있습니다. 문자열 배열에 fread 결과를 넣으려고했으나 분할 오류가 발생했습니다.

내 바이너리 파일의 모습입니다. 그것은 모든 문자열과 int 다음에 널 종결자가 있습니다. 그때 나는 오류

*** Error in `./test': munmap_chunk(): invalid pointer: 
0x000000000040133e *** Aborted. 

다음 얻을 내 freestruct() 함수에서 newheader-> 이름을 확보하는 경우를 해제하지 않는 경우

0000000 021 \0 \0 \0 i t  i s  a  g o o d 
0000020  d a y \0 R \0 \0 \0 # \0 \0 \0 I t  
0000040 w a s  t h e  b e s t  o f  
0000060 o y e  h o y e  t i m e s . \0 
0000100 034 \0 \0 \0 I t  w a s  t h e  b 
0000120 l u r s t  o f  t i m e s . \0 
0000140 \a \0 \0 \0 m o n k e y \0 006 \0 \0 \0 p 
0000160 a n d a \0 006 \0 \0 \0 s h i f u \0 
0000177 

는 내가 1 개 블록에 17 바이트를 잃게됩니다.

==24169== HEAP SUMMARY: 
==24169==  in use at exit: 0 bytes in 0 blocks 
==24169== total heap usage: 5 allocs, 6 frees, 1,201 bytes allocated 
==24169== 
==24169== All heap blocks were freed -- no leaks are possible 
==24169== 
==24169== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from0) 
==24169== 
==24169== 1 errors in context 1 of 1: 
==24169== Invalid free()/delete/delete[]/realloc() 
==24169== at 0x4C29E90: free (in 
/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==24169== by 0x401298: freestruct (A1.c:267) 
==24169== by 0x400F8A: write_strings (A1.c:189) 
==24169== by 0x400840: main (test.c:25) 
==24169== Address 0x40133e is not stack'd, malloc'd or (recently) 
free'd 
==24169== 
==24169== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from0) 

이 내 freestruct에서 코드의 작은 조각이 이진 파일에 캐릭터 라인을 기입 한 후() 함수

if (header->next == NULL) { 
    header->length = 0; 
    free(header->name); 
    free(header); 
} 

, 나는 전체 구조를 해제하고 read_strings 기능을 다시 만들어

편집 : readString 함수 내에서 newheader-> name을 해제하면 메모리 누수가 발생하지 않지만 newheader를 main으로 반환하고 printString 및 freestruct를 호출하고 싶습니다.

나쁜 문법에 사과드립니다. 내가 제대로 setNamegetName 기능을 이해한다면

+0

변수 및 값을 모니터링하면서 디버거를 사용하여 코드를 한 줄씩 단계별로 실행하십시오. 또한'setName'이라는 함수를 사용합니다. 어떻게합니까? 그리고'getName'은 무엇을합니까? 구조'name' member *를 두 번 설정해야합니까? –

+0

그리고 관련없는 쿼리는 파일에서 문자열 (및 길이)에 문자열 종결자를 포함합니까? –

+0

@JoachimPileborg setname은 header-> name에 보내진 문자열을 할당하고 getname은 그 값을 반환합니다. –

답변

0

는 다음 세 가지 라인은 문제가있다 : 모든이 첫번째 선이 같은 일을

... 
setName(newheader, name); 
newheader->name = getName(newheader); 
... 
free(name); 

첫째로, 그러나 그것은 단지 중복 문제가 아니다. 문제를 일으키는 마지막 줄입니다.

name이 가리키는 메모리를 가리 킵니다. 할당 후에 두 포인터가 동일한 메모리를 가리키고 있습니다. 그런 다음 그 기억을 해방하십시오. 그것은 두 포인터를 모두 무효로 만듭니다.

복제본 (예 : 비표준이지만 공통 인 strdup 기능) 중 하나가 필요합니다. 또는 메모리를 해제하지 마십시오.


내가 그것을 명확하게 할 수있는 경우

당신은 당신이 메모리를 할당하는 변수 name이 ... 볼 수 있습니다.그것은 다음과 같이 보일 것입니다 :

newheader->name = name; 

실제로 수행하는 과제는 단지 무엇

 
+------+  +---------------------+ 
| name | --> | memory for the name | 
+------+  +---------------------+ 

포인터 복사가 아닌 메모리가 가리키는. 할당 후 할당 된 값은 다음과 같습니다.

 
+------+ 
| name | ------------\ 
+------+    \ +---------------------+ 
         >-> | memory for the name | 
+-----------------+ / +---------------------+ 
| newheader->name | -/ 
+-----------------+ 

이제 두 개의 변수가 동일한 메모리를 가리키고 있습니다.

그럼 당신은 메모리를

free(name); 

이 무료 있어요,하지만 우리는 같은 메모리에 변수를 가리키는이 있음을 기억하십시오. 지금은 당신이 지금 free되기를 메모리에 액세스하려고합니다 newheader->name에 액세스하려고하고, 때마다 그래서 당신은 정의되지 않은 동작이있을 것이다

 
+------+ 
| name | -------------> ? 
+------+   

+-----------------+ 
| newheader->name | --> ? 
+-----------------+ 

것 같습니다.

+0

setName과 getName은 연결된 목록의 도움말 기능입니다. 나는 그들을 newheader-> name = name으로 대체 할 수있다; strcpy (newheader-> name, name);을 사용하여 시도했습니다. 하지만 그 또한 나에게 준 오류를 준 –

+0

@ samadbond 내 대답을 업데이 트되었습니다. 그것이 더 명확하게되기를 바랍니다. 자세한 설명은 –

+0

에게 감사드립니다. 무슨 일이 일어 났는지 이해하지만 fread를 사용하여 이진 파일에서 문자열을 읽는 다른 방법을 생각해 낼 수는 없습니다. 함수의 끝에서 연결된 목록에 헤더를 반환해야합니다. newheader-> name에 문자열을 추가하는 다른 해결책은 무엇입니까 –

관련 문제