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

时间:2017-05-04 07:51:58

标签: c pointers struct dynamic-memory-allocation realloc

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

我尝试使用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 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分:1)

你有

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

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

在进入pros->reason索引之前,您需要将pros->reason指向有效的内存位置。

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

除了这个问题之外,还有另一个问题使得这段代码无意义,即在循环的每次迭代中调用malloc()。你只需要调用realloc()一次,得到一个由内存分配器函数分配的指针(到内存),然后在循环中使用function validateform() { var email1 = document.getElementById('Email').value; var email = trim(email1); //email check condition email should be in like this if (!(email.endsWith("@hai.com") || email.endsWith("@hello.com"))) { alert("Email Should be in @hi.com or @hello.com"); $("#Email").val(''); document.getElementById("Email").focus(); return false; } } function trim(email2) { return email2.replace(/^\s+|\s+$/g, ""); }调整到需要的存储器中。

答案 2 :(得分:0)

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

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

  • 列表结构现在是自包含的,无需跟踪单独变量中的字符串数量
  • 添加了自包含AddString功能
  • 不再需要malloc s
  • 正确释放所有已分配的内存
  • 删除了一些逻辑错误(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");
}