【问题标题】:I cannot read string after reallocrealloc 后我无法读取字符串
【发布时间】:2018-01-09 08:21:08
【问题描述】:

我有这个功能,我重新分配内存,但是当我想读取字符串时它不起作用=>错误 Student 是一个结构体

void insertStudent(Student **myStudents, int *size)
{
    int newSize = *size + 1;
    *myStudents = (Student*)realloc(myStudents, newSize*sizeof(Student));
    printf("Enter your grade: ");
    scanf("%f", &(*myStudents)[*size - 1].nota);

    printf("Enter your first name: ");
    scanf("%s", &(*myStudents)[newSize-1].firstName);


    printf("Enter your second name: ");
    scanf("%s", &(*myStudents)[*size - 1].lastName);
    //Generate a new code
    /*int code = rand() % 1+1000;
    int ok = 0;
    while (ok == 0)
    {
        ok = 1;
        for (int i = 0; i < *size; i++)
            if ((*myStudents)[i].cod == code)
            {
                code = rand() % 1 + 1000;
                ok = 0;
            }
    }*/
    (*myStudents)[*size-1].cod = 7;
    printf("Your code is: %d. Do not forget it! ", 7);
}

【问题讨论】:

  • 能否在问题中添加编译器错误?
  • 您需要确定*size - 1newSize - 1 中的哪一个是正确的,并始终如一地使用它。我认为是第二个,但仔细看。
  • 旁注:realloc() 可能会失败。在这种情况下,它会返回 NULL并且旧指针仍然有效。由于您需要free() old 指针,因此基本上是内存泄漏等待发生将realloc() 的返回值分配给您作为参数传递的同一指针。
  • 正如其他人将(或已经)指出的那样:在编写普通的旧 C 时,请不要转换 maillocrealloccalloc 的返回值。在 C++ 中需要转换,但在 C 中被认为是不好的做法,因为它可以隐藏错误(尤其是 C11 之前)
  • @EliasVanOotegem nitpick:隐式函数声明在 C99 中已经错误(需要诊断),使得“规范”参数有点弱。尽管如此,我仍然认为casting to/from void * is bad practice

标签: c string struct realloc


【解决方案1】:
void insertStudent(Student **myStudents, int *size)
{
    *myStudents = (Student*)realloc(myStudents, newSize*sizeof(Student));
                               //   ^ <- look here

这是一个指向你学生的指针的指针。 realloc() 期望指向最初分配的数据的指针,所以你肯定必须在这里传递 *myStudents

还要更改代码以使用临时变量。 realloc() 可能会在错误时返回 NULL,在这种情况下,原始内存仍然被分配,你必须 free() 它。

为了计算大小,最好使用sizeof (newSize * sizeof **myStudents) 的表达式语法,因为这样可以防止以后更改类型时出错。

对于大小,您应该始终使用size_t,因为这可以保证容纳任何可能的对象大小(int 不是...)

进一步说明:在 C 中与 void * 之间的转换是 隐式 的,arguably better style 不明确编写此转换。

总而言之,代码应该是这样写的

void insertStudent(Student **myStudents, size_t *size)
{
    size_t newSize = *size + 1;
    Student *newStudents = realloc(*myStudents, newSize * sizeof *newStudents);
    if (!newStudents)
    {
        free(*myStudents);
        *myStudents = 0;
        return; // check for this error in calling code
    }
    *myStudents = newStudents;
    *size = newSize;
    // [...]
}

【讨论】:

    【解决方案2】:

    realloc() 需要指向要重新分配的内存的指针,即*myStudents 而不是myStudents

    改变

     *myStudents = (Student*)realloc(myStudents, newSize*sizeof(Student));
    

     *myStudents = (Student*)realloc(*myStudents, newSize*sizeof(Student));
    

    【讨论】:

      【解决方案3】:

      您正在重新分配给myStudents。这不是你的意图,也是不可能的。

      来自standard 7.22.3.5

      void *realloc(void *ptr, size_t size);

      否则,如果 ptr 不匹配之前由 内存管理函数,或者如果空间已被 调用 free 或 realloc 函数,行为未定义。如果 新对象的内存无法分配,旧对象没有 解除分配,其值不变。

      之前你有未定义的行为,你没有传递最初分配的内存地址。相反,您传递了一个局部变量。你有未定义的行为

      Student* t = realloc(*myStudents, newSize*sizeof(Student))
      if(t){
        *myStudents = t;
        (*size)++;
      }
      else {
         perror("realloc failed");
         free(*myStudents);
         exit(EXIT_FAILURE);
      }
      

      此外,当您增加内存时,如果调用成功,您应该增加它。然后在整个代码中持续访问*size-1,更容易处理和通过。

      如上所示的正确方法。如果realloc 返回NULL,您将不会丢失对已分配内存的引用。随之而来的还有检查realloc 的返回值的建议。在这种情况下,强制转换是多余的 - 不要这样做。

      scanf你可以简单地写

      scanf("%s",(*myStudents)[newSize-1].firstName);
      

      否则,您将通过 char (*)[] 它需要 char*

      【讨论】:

      • @MareşȘtefan.: 希望分配了一些内存,而不仅仅是指针。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多