首页 文章

在c中结构中动态分配内存

提问于
浏览
0

我正在尝试创建两个列表,优点和缺点,然后打印它们 . 但我无法弄清楚我做错了什么 .

我尝试使用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");
}

3 回答

  • 1

    有很多问题 . 以前的评论和答案仍然适用 .

    这是一个干净的解决方案 .

    • 列表结构现在是自包含的,无需跟踪单独变量中的字符串数

    • 添加了自包含 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");
    }
    
  • 2

    无需动态分配这些: list * pros; list * cons; . 像 pros = (list*)realloc(pros, i*sizeof(list)); 这样的代码没有任何意义 .

    相反,将它们声明为纯变量 . list pros .

    您需要动态分配的是成员 pros.reason . 您需要分配它指向的指针数组,然后您需要分配各个数组 .

  • 0

    你有问题

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

    因为您要使用的内存无效 . pros->reason 未指向有效内存,因此您无法取消引用它,这会导致undefined behavior .

    在索引到 pros->reason 之前,需要使 pros->reason 指向有效的内存位置 .

    之后,如果希望将 pros->reason[i] 用作 fgets() 的目标,则还需要使 pros->reason[i] 指向有效内存 .


    除了这个问题之外,还有另一个问题使得这段代码无意义,即在循环的每次迭代中调用 malloc() . 您只需要调用 malloc() 一次,以获取由内存分配器函数分配的指针(到内存),然后在循环内使用 realloc() 将其调整到所需的内存 .

相关问题