【问题标题】:Copy the file content to a struct将文件内容复制到结构
【发布时间】:2020-10-22 07:20:27
【问题描述】:

我尝试从文件中获取学生的姓名和代码并将其保存到结构中。文件是这样的

6, student1
2, student2
9, student3

这是我的尝试。你能告诉我这段代码有什么问题吗?

#include <stdio.h>
#include <stdlib.h>
#define N 20

struct Students {
    char studentName[N];
    int code;
};

void student() {
    FILE *f = fopen("file.txt", "r");
    struct Students *ptr;
    int i;
    ptr = malloc(sizeof(struct Students));
    if (ptr == NULL){
        printf("memory cannot be allocated");
        exit(1);
    }
    if (f == NULL) {
        printf("can't open the file");
        exit(1);
    }
    i=0;
    while (feof(f)) {
        fscanf(f, "%d, %s\n", &(ptr+i)->code, &(ptr+i)->studentName);    
        ptr = realloc(ptr, sizeof(struct Students) * i);
        i++;
    }
}

int main() {
    student();
    return 0;
}

【问题讨论】:

  • while(feof(f)) 肯定是不对的。您的意思可能是while(!feof(f)),但这也是错误的,请参阅stackoverflow.com/questions/5431941/…
  • 另外,你的realloc 逻辑是错误的。仔细想一想:每一步,ptr 可以容纳多少个结构,最后一个的索引是什么,你要写什么索引?
  • 另外fscanf(f, "%d, %s\n", &amp;(ptr+i)-&gt;code, (ptr+i)-&gt;studentName);, &amp;(ptr+i)-&gt;studentName 应该是(ptr+i)-&gt;studentName 或者更好ptr[i].studentName
  • 在你的第一个 realloc 中,你乘以 i = 0。这肯定不是你想要的

标签: c file struct


【解决方案1】:

我调试了你的代码,我们会看到一些问题:

#include <stdio.h>
#include <stdlib.h>
#define N 20

struct Student { // 1- changed name from Students to Student
    char name[N];
    int code;
};

struct Student* student() {
    FILE *f = fopen("file.txt", "r");
    if (f == NULL) {
        printf("can't open the file");
        exit(1);
    }


    struct Student *ptr = NULL; // 2- initialize pointer with null

    int i;
    for(i=0; !feof(f); i++) { // 3- replace while with for and changed condition to !foef(f)
        ptr = realloc(ptr, sizeof(struct Student) * (i+1)); // 4- allocate with size (i+1) because i is always size-1 and less than we need.
        fscanf(f, "%d, %s\n", &ptr[i].code, ptr[i].name); // 5- changed syntax of accessing fields of structs
    }
    return ptr; // 6- return pointer to free it later and prevent memory leak
}

int main() {
    struct Student* ptr = student();
    // use it and free it
    return 0;
}

解释:

  1. 您的结构 Student 包含只有一个学生的信息,而不是很多学生s,因此最好将其命名为 Student。 我还把studentCode重命名为code,因为很明显这段代码是属于Student的。
  2. 我们总是希望我们的数组与其元素一样大小,当它为空时它可以指向 NULL,当我们想要添加值时,我们扩展它。
  3. 当我们有计数器和增量时,最好使用for 以获得更好的代码可读性,更重要的是,我们的条件应该是!feof(f),因为我们要读取直到文件结束。
  4. 可能最重要的问题是:你分配的内存比我们需要的少,i 变量总是包含最后一个大小,如果我们要扩展数组,我们应该分配大小为i+1 的内存。李>
  5. 如您所见,使用. 运算符而不是获取地址并使用-&gt; 要简单得多。
  6. 我们分配了内存,但从未使用它并释放它,我假设我们想在函数结束后使用它并释放它,所以我返回了指针,否则,我们有内存泄漏。

最后一点:为 char 字符串分配 20 个字节并不总是安全的,使用 sscanf 获取输入可能会导致内存问题,您应该考虑使用 fgetsgetline,因为它们是安全的。

祝你好运。

【讨论】:

  • "%s" in fscanf 不是安全说明符,容易出现缓冲区溢出,请使用"%19s"
  • 你说得对,我提到它不安全,谢谢完成。
  • 你做到了,我错过了,但正如我所提到的,使用 %19s 而不是 %s 可以解决问题。
【解决方案2】:

在第一次重新分配中,分配的大小是通过乘以 i = 0 来计算的,因此分配的大小为 0。另外,studenName 已经是一个地址,因为它是一个数组,所以之前的 '&'不需要这个变量。

它可以写得更好,但坚持原来的代码更好的版本是:

i = 0;
while (!feof(f)) {
    fscanf(f, "%d, %s\n", &(ptr+i)->code, (ptr+i)->studentName);
    ++i;   
    ptr = realloc(ptr, sizeof(struct Students) * (i+1));
}

最后一点值得注意:在性能方面,realloc 是一项代价高昂的操作。考虑在每个循环周期分配超过 1 个分配单元。这里的内存几乎没有那么贵

【讨论】:

  • 在另一个答案中查看我的评论。
猜你喜欢
  • 1970-01-01
  • 2016-05-21
  • 2016-08-20
  • 1970-01-01
  • 1970-01-01
  • 2015-02-28
  • 1970-01-01
  • 1970-01-01
  • 2022-01-07
相关资源
最近更新 更多