2017-12-21 9 views
7

유효하지 않은 메모리 누수가 발생합니다.Valgrind가 유효하지 않아 메모리 누수가 발생했습니다.

/*============================================================================= 
    | 
    | Assignment: Test #2 

    |  Class: Programming Basics 
    |   Date: December 20th, 2017 
    | 
    |  Language: GNU C (using gcc), OS: Arch Linux x86_64) 
    |  Version: 0.0 
    | To Compile: gcc -Wall -xc -g -std=c99 kontrolinis2.c -o kontrolinis_2 
    | 
    +----------------------------------------------------------------------------- 
    | 
    | Description: The program which gets the input number, which indicates how 
    |    many words there will be, then prompts the user to enter 
    |    those words, and then displays a histogram in descending 
    |    order by times the word is repeated. The words with the 
    |    same duplicate count are sorted in lexicographical order 
    | 
    +===========================================================================*/ 

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

#include "dbg.h" 
#include "lib_riddle.h" 

#define MAX_STRING 50 

// Frequency structure. Contains the word and the times 
// it is repeated 
typedef struct Freq { 
    char* word; 
    int times; 
} Freq; 

// Histogram structure. Contains the list of frequencies (struct) 
// and the size of the list. 
typedef struct Histogram { 
    Freq** freqs; 
    int size; 
} Histogram; 

// sort the portion of the given array of frequency structs 
// in lexicographically reverse order (from z to a) by Freq->word attribute. 
// 
// ::params: target - array continaing frequency structs 
// ::params: first - first index of the portion of the array 
// ::params: last - last index of the portion of the array 
// ::return: Array of frequency structs (portion of which is 
// sorted in lexicographically reverse order) 
Freq** sort_rlexicographical(Freq** target, int first, int last); 

// sort the frequency structs array by their Freq->times 
// attribute, using quicksort 
// 
// ::params: target - the frequency array 
// ::params: first - first index of the array 
// ::params: first - last index of the array 
// ::return: Sorted array of frequency structs 
Freq** quicksort_freqs(Freq** target, int first, int last); 

// print Frequency array in reverse order, which displays 
// the data as in historgram (from bigger to smaller) 
// 
// ::params: target - the frequency array 
// ::params: size - size of the array 
void print_reverse(Freq** target, int size); 



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

    // get number from the user 
    int size = get_pos_num("Please enter a number of words > ", 0); 

    Histogram* histogram = malloc(sizeof(Histogram)); 
    histogram->freqs = malloc(size * sizeof(Freq*)); 
    histogram->size = 0; 

    char** words = (char**)malloc(size * sizeof(char*)); 
    for (int i = 0; i < size; i++) { 
     words[i] = (char*)malloc(MAX_STRING * sizeof(char)); 
    } 

    // get words from the user 
    for (int i = 0; i < size; i++) { 
     words[i] = get_word("Enter word > ", words[i]); 
    } 

    int duplicates; 
    int is_duplicate; 
    int hist_size = 0; 

    // initialize the array of duplicates 
    char** duplicated = (char**)malloc(size * sizeof(char*)); 
    for (int i = 0; i < size; i++) { 
     duplicated[i] = (char*)calloc(MAX_STRING+1, sizeof(char)); 
     /*duplicated[i] = (char*)malloc(MAX_STRING);*/ 
     /*duplicated[i] = (char*)calloc(MAX_STRING + 1, sizeof(char));*/ 
    } 

    // count the duplicates of each word and add the word with its duplicate count 
    // to the frequency array, and then - to the histogram struct. Each word is 
    // writtern once, without duplication. 
    for (int i = 0; i < size; i++) { 
     is_duplicate = 0; 

     // if the word is already added to the duplicate list, 
     // it means that its duplicates are already counted, 
     // so the loop iteration is skipped 
     for (int k = 0; k < size; k++) { 
      if (strcmp(duplicated[k], words[i]) == 0) { 
       is_duplicate = 1; 
      } 
     } 

     // skipping the loop iteration 
     if (is_duplicate) { 
      continue; 
     } 

     // found the word about which we are not yet sure 
     // whether it has any duplicates. 
     duplicates = 1; 
     Freq* freq = malloc(sizeof(Freq)); 
     freq->word = (char*)malloc(sizeof(MAX_STRING * sizeof(char))); 
     freq->word = words[i]; 
     // searching for the duplicates 
     for (int j = i + 1; j < size; j++) { 
      if (strcmp(words[i], words[j]) == 0) { 
       // in case of a duplicate 
       // put word in duplicates array 
       // and increase its duplicates count 
       duplicated[i] = words[i]; 
       duplicates++; 
      } 
     } 
     freq->times = duplicates; 
     histogram->freqs[histogram->size++] = freq; 
     hist_size++; 
    } 

    debug("Frequency table:"); 
    for (int i = 0; i < hist_size; i++) { 
     debug("%s %d", histogram->freqs[i]->word, histogram->freqs[i]->times); 
    } 
    debug("-----------------------"); 

    histogram->freqs = quicksort_freqs(histogram->freqs, 0, hist_size - 1); 

    debug("Sorted frequency table:"); 
    for (int i = hist_size - 1; i >= 0; i--) { 
     debug("%s %d", histogram->freqs[i]->word, histogram->freqs[i]->times); 
    } 
    debug("-----------------------"); 

    int max_count = histogram->freqs[hist_size - 1]->times; 
    int index = hist_size - 1; 
    int index_max; 

    // partition the frequency array by the same duplicate times, and 
    // pass the partitioned array to reverse lexicographical sort 
    // on the go. 
    for (int i = max_count; i > 0 && index >= 0; i--) { 
     index_max = index; 
     if (histogram->freqs[index]->times == i) { 
      while (index - 1 >= 0 && histogram->freqs[index - 1]->times == i) { 
       index--; 
      } 
      if (index != index_max) { 
       histogram->freqs = sort_rlexicographical(
        histogram->freqs, index, index_max); 
      } 
      index--; 
     } 
    } 

    printf("\nLexicographically sorted frequency table:\n"); 
    print_reverse(histogram->freqs, hist_size); 




    for (int i = 0; i < size; i++) { 
     free(duplicated[i]); 
    } 
    free(duplicated); 

    for (int i = 0; i < size; i++) { 
     free(words[i]); 
    } 
    free(words); 

    for (int i = 0; i < hist_size; i++) { 
     free(histogram->freqs[i]->word); 
    } 

    for (int i = 0; i < hist_size; i++) { 
     free(histogram->freqs[i]); 
    } 
    free(histogram->freqs); 
    free(histogram); 


    return 0; 
} 

Freq** quicksort_freqs(Freq** target, int first, int last) 
{ 
    Freq* temp; 
    int pivot, j, i; 

    if (first < last) { 
     pivot = first; 
     i = first; 
     j = last; 

     while (i < j) { 
      while (target[i]->times <= target[pivot]->times && i < last) { 
       i++; 
      } 
      while (target[j]->times > target[pivot]->times) { 
       j--; 
      } 
      if (i < j) { 
       temp = target[i]; 
       target[i] = target[j]; 
       target[j] = temp; 
      } 
     } 
     temp = target[pivot]; 
     target[pivot] = target[j]; 
     target[j] = temp; 

     quicksort_freqs(target, first, j - 1); 
     quicksort_freqs(target, j + 1, last); 
    } 
    return target; 
} 

Freq** sort_rlexicographical(Freq** target, int first, int last) 
{ 
    int i, j; 
    Freq* temp; 

    for (i = first; i < last; ++i) 

     for (j = i + 1; j < last + 1; ++j) { 

      if (strcmp(target[i]->word, target[j]->word) < 0) { 
       temp = target[i]; 
       target[i] = target[j]; 
       target[j] = temp; 
      } 
     } 

    debug("In lexicographical reverse order:"); 
    for (i = 0; i < last + 1; ++i) { 
     debug("%s", target[i]->word); 
    } 
    debug("-----------------------"); 

    return target; 
} 

void print_reverse(Freq** target, int size) { 
    for (int i = size - 1; i >= 0; i--) { 
     printf("%s ", target[i]->word); 
     printf("%d \n", target[i]->times); 
    } 
} 

잘못된없는 점 :

196 for (int i = 0; i < size; i++) { 
197  free(words[i]); 
198 } 

과 : 행동

201 for (int i = 0; i < hist_size; i++) { 
202  free(histogram->freqs[i]->word); 
203 } 

내 프로그램 : 여기 내 코드입니다

➜ tmp1 ./kontrolinis2 
Please enter a number of words > 4 
Enter word > test1 
Enter word > test1 
Enter word > test2 
Enter word > test2 
DEBUG kontrolinis2.c:150: Frequency table: 
DEBUG kontrolinis2.c:152: test1 2 
DEBUG kontrolinis2.c:152: test2 2 
DEBUG kontrolinis2.c:154: ----------------------- 
DEBUG kontrolinis2.c:158: Sorted frequency table: 
DEBUG kontrolinis2.c:160: test1 2 
DEBUG kontrolinis2.c:160: test2 2 
DEBUG kontrolinis2.c:162: ----------------------- 
DEBUG kontrolinis2.c:264: In lexicographical reverse order: 
DEBUG kontrolinis2.c:266: test2 
DEBUG kontrolinis2.c:266: test1 
DEBUG kontrolinis2.c:268: ----------------------- 

Lexicographically sorted frequency table: 
test1 2 
test2 2 

Valgrind의 출력합니다 (로 동일한 "사용자"입력) :

Lexicographically sorted frequency table: 
test1 2 
test2 2 
==9430== Invalid free()/delete/delete[]/realloc() 
==9430== at 0x4C2E14B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==9430== by 0x1091D4: main (kontrolinis2.c:197) 
==9430== Address 0x51f19d0 is 0 bytes inside a block of size 50 free'd 
==9430== at 0x4C2E14B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==9430== by 0x109194: main (kontrolinis2.c:192) 
==9430== Block was alloc'd at 
==9430== at 0x4C2CE5F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==9430== by 0x108C77: main (kontrolinis2.c:89) 
==9430== 
==9430== Invalid free()/delete/delete[]/realloc() 
==9430== at 0x4C2E14B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==9430== by 0x109217: main (kontrolinis2.c:202) 
==9430== Address 0x51f1ad0 is 0 bytes inside a block of size 50 free'd 
==9430== at 0x4C2E14B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==9430== by 0x109194: main (kontrolinis2.c:192) 
==9430== Block was alloc'd at 
==9430== at 0x4C2CE5F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==9430== by 0x108C77: main (kontrolinis2.c:89) 
==9430== 
==9430== 
==9430== HEAP SUMMARY: 
==9430==  in use at exit: 118 bytes in 4 blocks 
==9430== total heap usage: 18 allocs, 18 frees, 2,612 bytes allocated 
==9430== 
==9430== 16 bytes in 2 blocks are definitely lost in loss record 1 of 2 
==9430== at 0x4C2CE5F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==9430== by 0x108DC7: main (kontrolinis2.c:133) 
==9430== 
==9430== 102 bytes in 2 blocks are definitely lost in loss record 2 of 2 
==9430== at 0x4C2EF35: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==9430== by 0x108D23: main (kontrolinis2.c:104) 
==9430== 
==9430== LEAK SUMMARY: 
==9430== definitely lost: 118 bytes in 4 blocks 
==9430== indirectly lost: 0 bytes in 0 blocks 
==9430==  possibly lost: 0 bytes in 0 blocks 
==9430== still reachable: 0 bytes in 0 blocks 
==9430==   suppressed: 0 bytes in 0 blocks 
==9430== 
==9430== For counts of detected and suppressed errors, rerun with: -v 
==9430== ERROR SUMMARY: 6 errors from 4 contexts (suppressed: 0 from 0) 

전체 프로그램이 아닌 전체 프로그램의 기본 부분 또는 작동하는 프로토 타입을 붙여야하는지 여부를 수정하십시오. 그러나 여기에서 주요 세부 사항은 이며 "malloc"및 "free"키워드가 포함 된 줄입니다. "get_pos_num"와 "GET_WORD":

UPDATE : 여기에 사용되는 라이브러리에서 두 가지 기능을 덧붙이

char* get_word(char* message, char* output) 
{ 

    while (1) { 
     printf("%s", message); 
     if (scanf("%s", output) == 1 && getchar() == '\n') { 
      break; 
     } else { 
      while (getchar() != '\n') 
       ; 
      printf("Error: not a string, or too many arguments\n"); 
     } 
    } 

    return output; 
} 

int get_pos_num(char* message, int zero_allowed) 
{ 
    int num; 
    int margin; 

    if (zero_allowed) { 
     margin = 0; 
    } else { 
     margin = 1; 
    } 

    while (1) { 
     printf("%s", message); 
     if (scanf("%d", &num) == 1 && getchar() == '\n') { 
      if (num >= margin) { 
       break; 
      } else { 
       printf("Error: number is not positive"); 
       if (zero_allowed) { 
        printf(" or zero"); 
       } 
       printf("\n"); 
      } 
     } else { 
      while (getchar() != '\n') 
       ; 
      printf("Error: not a number\n"); 
     } 
    } 

    return num; 
} 
+0

'get_pos_num'과 get_word는 무엇입니까? 그것들은'lib_riddle.h'에 정의되어 있습니까? 우리에게는 그런 것이 없습니다. 'Debug'는'printf'와 다소 차이가 있다고 가정합니다. –

+0

예, 디버그는 printf입니다. get_pos_num 및 get_word는 라이브러리의 함수입니다. 내 질문을 즉시 수정하여 포함시킵니다. – Riddle00

+0

Upvoted, 다음에 약간 더 * 좀 더 적은 예제를 만들려고해도 : D –

답변

9

음 명백한 문제는 여기에 있습니다 :

freq->word = (char*)malloc(sizeof(MAX_STRING * sizeof(char))); 
freq->word = words[i]; 

당신이 할당 freq->word에 대한 메모리 및 words[i]으로 덮어 쓰기.

나중에 words을 무료로 가져온 다음 구조에 할당 한 많은 freq을 무료로 만듭니다. 당신이 words[i]을 복사하려면

당신은 사용해야 하나

freq->word = strdup(words[i]); 

또는

freq->word = malloc(strlen(words[i])+1); 
strcpy(freq->word,words[i]); 

또한 모두가 당신의 원인이됩니다 당신이 너무 여기

duplicated[i] = words[i]; 

을 같은 일을 눈치 할당 된 메모리를 추적하는 동안 메모리가 누출됩니다.

는 그리고 또 다른 한가지는 (내가 콜롬보 오늘 것 같다)는 malloc에서

sizeof(MAX_STRING * sizeof(char))이있는 이상 단지 MAX_STRING * sizeof(char)해야해야한다는 것입니다. 당신이 얻게 될 결과가 전적으로 확실하지는 않지만 4 바이트 또는 8 바이트가 될 것입니다.

+0

다른 한편으로는 : 수정 프로그램이 여전히 여기에서 충돌하기 때문에 더 많은 오류가 있어야합니다. –

+0

감사합니다!그게 정확히 문제 였고, 지금 나는 그것을 얻는 것처럼 보입니다. 또한 "duplicated [i] = words [i]"와 동일한 상황이 있었는데 "strcpy (duplicated [i], words [i])"로 변경해야했습니다. " – Riddle00

+0

실수로 MAX_STRING * sizeof (char)를 수정 해 주셔서 감사합니다. – Riddle00

관련 문제