简体   繁体   English

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

[英]Dynamically allocated memory in structure in c

I'm trying to create two lists, pros and cons and then print them. 我正在尝试创建两个列表,利弊,然后打印它们。 But I can't figure out what am I doing wrong. 但是我不知道我在做什么错。

I tried to debug the program with gdb online and I found out that the error is in function fgets(). 我尝试使用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");
}

There is no need to allocate these dynamically: list * pros; list * cons; 无需动态分配这些资源: list * pros; list * cons; list * pros; list * cons; . Code like pros = (list*)realloc(pros, i*sizeof(list)); pros = (list*)realloc(pros, i*sizeof(list)); doesn't make any sense. 没有任何意义。

Instead, declare them as plain variables. 而是将它们声明为普通变量。 list pros . list pros

What you instead need to allocate dynamically is the member pros.reason . 相反,您需要动态分配的成员是pros.reason You need to allocate an array of pointers that it points to, and then you need to allocate the individual arrays. 您需要分配一个指向它的指针数组,然后需要分配各个数组。

You have a problem in 你有一个问题

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

as the memory you want to use is not valid . 因为您要使用的内存无效 pros->reason does not point to a valid memory, so you cannot dereference it, this causes undefined behavior . pros->reason不会指向有效的内存,因此您无法取消引用它,这会导致未定义的行为

Before you can index-into pros->reason , you need to make pros->reason point to a valid memory location. 在索引pros->reason ,您需要使pros->reason指向有效的内存位置。

After that, you need to make pros->reason[i] s also to point to valid memory if you want them to be used as the destination of fgets() . 之后,如果希望将它们用作fgets()目的地 ,则还需要使pros->reason[i]指向有效内存。


Apart from this issue, you have another issue which makes this code nonsense, that is calling malloc() on every iteration of the loop. 除了这个问题之外,还有另一个使代码变得毫无意义的问题,那就是在循环的每次迭代中都调用malloc() You need to call malloc() only once, to get a pointer (to memory) allocated by memory allocator function and then, use realloc() inside the loop to adjust that to the required memory. 您只需调用一次malloc() ,即可获得由内存分配器函数分配的(指向内存的)指针,然后在循环内使用realloc()将其调整为所需的内存。

There are many issues. 有很多问题。 Previous comments and answers do still apply. 以前的评论和答案仍然适用。

Here is a clean solution. 这是一个干净的解决方案。

  • The list structure is now self contained, no need to track the number of strings in separate variables 列表结构现在是自包含的,无需跟踪单独变量中的字符串数
  • added selfcontained AddString function 添加了AddString函数
  • no more unnecessary malloc s 不再需要不必要的malloc
  • all allocated memory is freed correctly 正确释放了所有分配的内存
  • some logic errors removed (inverted logic of keepGoing ) 删除了一些逻辑错误( keepGoing反向逻辑)

There is still room for improvement. 仍有改进的空间。 Especially there is no error checking for the memory allocation functions. 特别是对于内存分配功能没有错误检查。


#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");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM