2017-05-04 191 views
0

我試圖創建兩個列表,優點和缺點,然後打印出來。 但我無法弄清楚我做錯了什麼。動態分配內存結構c

我試圖用gdb在線調試程序,我發現錯誤在函數fgets()中。

#include <stdio.h> 
#include <string.h> 
typedef struct list{ 
    char ** reason; 

} list; 
void printMenu(); 
void printList(list * myList, int len1); 


int main(void) 
{ 
    int keepGoing = 0; 
    int choice = 0; 
    int i = 0; 
    int j = 0; 
    list * pros; 
    list * cons; 

    while (!keepGoing){ 

     printMenu(); 
     scanf("%d", &choice); 

     pros = (list*)malloc(sizeof(list)); 
     cons = (list*)malloc(sizeof(list)); 
     switch (choice){ 
     case 1: 
      i++; 
      printf("Enter a reason to add to list PRO: "); 
      pros = (list*)realloc(pros, i*sizeof(list)); 
      fgets(pros->reason[i], 50, stdin); 
      pros->reason[strcspn(pros->reason[i], "\n")] = 0; 
      break; 
     case 2: 
      j++; 
      cons = (list*)realloc(cons->reason, j*sizeof(list)); 
      printf("Enter a reason to add to list CON: "); 
      fgets(cons->reason[j], 50, stdin); 
      cons->reason[strcspn(cons->reason[j], "\n")] = 0; 
      break; 
     case 3: 
      printf("PROS:\n"); 
      printList(pros, i); 
      printf("CONS:\n"); 
      printList(cons, j); 

      break; 
     case 4: 
      keepGoing = 1; 
      break; 
     default: 
      printf("Invalid value."); 
      keepGoing = 1; 
     } 
    } 

    free(pros); 
    free(cons); 

    getchar(); 
    return 0; 
} 

void printList(list * reasons, int len1){ 
    int i = 0; 
    for (i = 0; i < len1; i++){ 
     printf("%s\n", reasons->reason[i]); 
    } 
} 
void printMenu(){ 
    printf("Choose option:\n"); 
    printf("1 - Add PRO reason\n"); 
    printf("2 - Add CON reason\n"); 
    printf("3 - Print reasons\n"); 
    printf("4 - Exit\n"); 
} 
+0

是什麼'count'? –

+0

[請參閱此討論,爲什麼不在'C'中投射'malloc()'和家族的返回值。](http://stackoverflow.com/q/605845/2173917)。 –

+0

那麼你'malloc'每個循環的結構...因此每個循環擦除數據。你還可以在以前從未分配過的東西上使用'realloc' [即使'realloc會分配大小,你應該使用'malloc']。阿洛斯'keepGoing'總是等於1;你有一個無限循環;然後你永遠不會釋放它[你忘了釋放列表] – kaldoran

回答

0

有很多問題。以前的評論和答案仍然適用。

這是一個乾淨的解決方案。

  • 列表結構現在獨立的,沒有必要跟蹤獨立變量的字符串數
  • 增加自持AddString功能
  • 沒有更多的不必要的malloc小號
  • 所有分配的內存被正確釋放
  • 刪除了一些邏輯錯誤(反轉邏輯keepGoing

還有改進的餘地。尤其是沒有檢查內存分配函數的錯誤。


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

typedef struct list { 
    int size;  // number of strings 
    int chunksize; // current of chunk 
    char ** reason; 
} list; 

void printMenu(); 
void printList(list * reasons); 
void freeList(list * l); 
void AddString(list *l, const char *string); 

int main(void) 
{ 
    int keepGoing = 1; 
    int choice = 0; 

    list pros = { 0 }; // = {0} initializes all fields to 0 
    list cons = { 0 }; 

    while (keepGoing) { 

    printMenu(); 
    scanf("%d", &choice); 

    char input[50]; 
    fgets(input, sizeof(input), stdin); // absorb \n from scanf 

    switch (choice) { 
    case 1: 
     printf("Enter a reason to add to list PRO: "); 
     fgets(input, sizeof(input), stdin); 
     AddString(&pros, input); // Add string to pros 
     break; 
    case 2: 
     printf("Enter a reason to add to list CONS: "); 
     fgets(input, sizeof(input), stdin); 
     AddString(&cons, input); // Add string to cons 
     break; 
    case 3: 
     printf("PROS:\n"); 
     printList(&pros); 
     printf("CONS:\n"); 
     printList(&cons); 
     break; 
    case 4: 
     keepGoing = 0; 
     break; 
    default: 
     printf("Invalid value."); 
     keepGoing = 1; 
    } 
    } 

    freeList(&pros); 
    freeList(&cons); 

    getchar(); 
    return 0; 
} 


#define CHUNKSIZE 10 

void AddString(list *l, const char *string) 
{ 
    if (l->size == l->chunksize) 
    { 
    // resize the reason pointer every CHUNKSIZE entries 
    l->chunksize = (l->chunksize + CHUNKSIZE); 

    // Initially l->reason is NULL and it's OK to realloc a NULL pointer 
    l->reason = realloc(l->reason, sizeof(char**) * l->chunksize); 
    } 

    // allocate memory for string (+1 for NUL terminator) 
    l->reason[l->size] = malloc(strlen(string) + 1); 

    // copy the string to newly allocated memory 
    strcpy(l->reason[l->size], string); 

    // increase number of strings 
    l->size++; 
} 

void freeList(list * l) { 
    for (int i = 0; i < l->size; i++) { 
    // free string 
    free(l->reason[i]); 
    } 

    // free the list of pointers 
    free(l->reason); 
} 

void printList(list * l) { 
    for (int i = 0; i < l->size; i++) { 
    printf("%s\n", l->reason[i]); 
    } 
} 

void printMenu() { 
    printf("Choose option:\n"); 
    printf("1 - Add PRO reason\n"); 
    printf("2 - Add CON reason\n"); 
    printf("3 - Print reasons\n"); 
    printf("4 - Exit\n"); 
} 
1

你有

fgets(pros->reason[i], 50, stdin); 

只要你想使用內存的一個問題是不是有效pros->reason沒有指向有效的內存,所以你不能解除引用它,這會導致undefined behavior

在您可以索引到pros->reason之前,您需要將pros->reason指向有效的內存位置。

之後,你需要做pros->reason[i] S還,如果你希望它們被用作目的地fgets()指向有效的內存。


除了這個問題,你有另外一個問題,這使得該代碼廢話,就是在循環的每次迭代打電話malloc()。你只需要調用malloc()一次,得到一個由內存分配器函數分配的指針(對內存),然後在內部使用realloc()調整即可得到所需內存。

+0

還有更多的問題:x(每個循環的alloc列表,重新分配應該先分配的內容(即使realloc會創建內存)) – kaldoran

+0

你的意思是這樣的嗎? pros-> reason =(char **)malloc(sizeof(char *)* SIZE); – Saga

+0

@Saga沿着那條線,是的。 –

2

有沒有必要動態分配這些:list * pros; list * cons;。像pros = (list*)realloc(pros, i*sizeof(list));這樣的代碼沒有任何意義。

相反,將它們聲明爲普通變量。 list pros

您需要動態分配的是會員pros.reason。您需要分配它指向的指針數組,然後您需要分配各個數組。