如何正确地 malloc C 中的结构

How to correctly malloc a struct in C

这是我的完整代码,它看起来可以工作,但效果不是很好。 我会接受任何像这样工作的代码。

首先,代码可以运行,但是当我想将第三个名称添加到结构时,它崩溃了。

还有其他方法吗?

我需要结构体,因为以后我想添加一些其他的参数,比如年龄,平均水平,性别等等

请帮帮我。

//The student table
typedef struct students {
    char name[50];
} students;

//Global params
int scount = 0;
students *s;

//Basic functions
void addNewStudent();

int main()
{
    int loop = 1;
    char in;
    int ch;
    printf("Willkommen.\n Wahlen Sie bitte von die folgenden Optionen:\n");
    while (loop)
    {
        printf("\t[1] Neue Student eingeben\n");
        printf("\t[9] Programm beenden\n");

        scanf(" %c", &in);
        while ((ch = getchar()) != '\n');
        switch (in)
        {
        case '1':
            addNewStudent();
            break;
        case '9':
            loop = 0;
            break;
        default: printf("------\nOption nicht gefunden.\n------\n");
            break;
        }
    }
    free(s);
    return 0;
}

void addNewStudent()
{
    int index = 0;
    if (scount == 0)
    {
        s = (students*)malloc(sizeof(students));
    }
    else
    {
        realloc(s, sizeof(students) * scount);
    }

    printf("Geben Sie Bitte die Name:\n");
    fgets(s[scount].name, sizeof(s[scount].name), stdin);

    while (s[scount].name[index] != '\n')
    {
        index++;
    }
    s[scount].name[index] = '[=10=]';
    scount++;
}

我正在使用 Visual Studio。

感谢帮助!

students *mynew= realloc(s, sizeof(students)* (scount+1));
if( mynew != NULL )
    s=mynew;

否则你有内存泄漏。您没有使用 realloc 的 return 值。

不要转换 malloc 的 return 类型。

按照标准 §7.22.2.35

void *realloc(void *ptr, size_t size)

The realloc function deallocates the old object pointed to by ptr and returns a pointer to a new object that has the size specified by size.

最好不要在调用 malloc 时使用同一个指针变量,因为万一它失败了,你也会失去对旧指针变量的引用(除非它是通过其他方式存储的)。

你也没有检查 malloc 的 return 值。

s = malloc(sizeof(students));
if( s == NULL ){
   frpntf(stderr,"%s","Memory allocation failed");
   exit(1);
}

您还应该检查 fgets() 的 return 值。

if( fgets(s[scount].name, sizeof(s[scount].name), stdin) == NULL){
     fprintf(stderr,"%s","Error in input");
     exit(1);
}

还试图编译你的代码,它显示了这个

warning: ignoring return value of ‘realloc’, declared with attribute warn_unused_result [-Wunused-result]
         realloc(s, sizeof(students) * scount);
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

编译时尽量不要忽略任何警告信息。它显示了你遇到的问题。

要点:(为什么 scount+1realloc 中?)

重新分配时,总体思路是增加学生人数。为此,您需要为学生分配额外的内存。这就是代码中 scount+1 的原因。(realloc).


其他几点:

while (s[scount].name[index] != '\n')
{
    index++;
}
s[scount].name[index] = '[=15=]';

你也可以这样做

size_t len = strlen(s[scount].name);
if(len){ 
   s[scount].name[len-1]='[=16=]'; 
}

从标准 §7.21.7.2

中理解原因
char *fgets(char * restrict s, int n,FILE * restrict stream)

The fgets function reads at most one less than the number of characters specified by n from the stream pointed to by stream into the array pointed to by s. No additional characters are read after a new-line character (which is retained) or after end-of-file. A null character is written immediately after the last character read into the array.

[=36=]字符已经存在于输入的string中。你可以得到它的长度但是你知道 [=36=] 之前的那个是 \n 字符 1 那您通过按 Enter 键输入的。我们正在用 [=36=].

覆盖它

1.这是常见的情况,但不是唯一的。在两种情况下,这可能不是正确的看待事物的方式。

  • 输入行在 '\n' 之前有 n-1 个或更多字符。 [=36=] 之前的那个不会是 \n 而是用户输入的一些字符。

  • 最后一行是可能没有 '\n' 的流。 (标准输入关闭)。在那种情况下,输入也不包含 \n

所以在这些情况下,删除 \n 的想法会失败。在评论中讨论。 (chux)


比用这种方式覆盖更好更安全的解决方案:

s[scount].name[strcspn(s[scount].name, "\n")] = '[=18=]';

link 的解释是,如果 [=36=] 作为输入,那么我们基本上会写入 s[scount].name[SIZE_MAX],即不需要。


来自标准 §7.24.5.3

size_t strcspn(const char *s1, const char *s2)

The strcspn function computes the length of the maximum initial segment of the string pointed to by s1 which consists entirely of characters not from the string pointed to by s2.

realloc returns 您需要保留的新指针:

  students* snew = realloc(s, sizeof(students) * (scount + 1));
  if (!snew) {
     free(s); // If there is not enough memory, the old memory block is not freed
     // handle out of memory
  } else { 
     s = snew;
  }

你没有分配回去!看看 realloc 是如何工作的。像这样进行重新分配后,您需要将指针重新分配。

if (scount == 0)
{
    s = (students*)malloc(sizeof(students));
}
else
{
    students *temp = realloc(s, sizeof(students) * (scount+1));
    if(temp == NULL){
        free(s);
    }
    else{
        s = temp;
    }
}

根据定义,重新分配 returns 一个空指针,但您没有收集它。

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

realloc returns a NULL 如果 space 不够用。所以可以在确定不是NULL

的时候重新赋值

只要在上面做一点小改动,你的代码就会非常棒!

干杯!

How to correctly malloc a struct in C ?

p = malloc(sizeof *p);
if (p == NULL) Handle_OutOfMemory();

How to correctly re-allocate a struct in C ?

void *t = realloc(p, sizeof *p * number_of_elements);
if (t == NULL && number_of_elements > 0) {
  Handle_OutOfMemory();
} else {
  p = t;
}

p 指向一些 struct。注意上面没有那种类型的编码


OP' 的主要问题是没有使用 realloc() 的 return 值和分配 1-too-small

// realloc(s, sizeof(students) * scount);
s = realloc(s, sizeof *s * (scount+1));  // or use above code with check for out-of-memory.