2017-05-04 192 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。您需要分配它指向的指针数组,然后您需要分配各个数组。