【问题标题】:Using fscanf to input data into a dynamic struct pointer array?使用 fscanf 将数据输入到动态结构指针数组中?
【发布时间】:2013-02-08 13:31:10
【问题描述】:

我有一个任务并且遇到了一些障碍。以下代码应该从文件中获取输入,将其读入我定义的结构中,并且对输入行数没有任何限制。但是,它在 24 行出现了段错误:

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 typedef struct __student {
6         int ID;
7         char fname[33];
8         char lname[33];
9         float grade;
10 } student;
11
12 void partA(FILE *fp) {
13
14         int i, r;
15         i = r = 0;
16         int N = 1000;
17         student **S;
18
19         S = (student **)malloc(sizeof(student *) * N);
20
21
22         while(!feof(fp)){
23                 fscanf(fp, "%d %[^,], %s %f", &S[i]->ID, S[i]->lname, S[i]->fname, &S[i]->grade ); // segfault occurs on this line
24                 printf("%d %s %s %f\n", S[i]->ID, S[i]->fname, S[i]->lname, S[i]->grade);
25                 i++;
26                 printf("Something's happening, at least");
27                 if(i == N){
28                         N *= 2;
29                         S = (student **)realloc(S, sizeof(student) * N);
30                         if(S == NULL) {
31                                 printf("Memory reallocation failed; Fatal error.");
32                                 break;
33                         }
34                 }
35         }
36 }

我之前测试过代码,虽然当时我使用的是静态数组并想更改为动态大小。然而,即使 gdb with 除了行号之外提供的帮助也很少。我需要单独 malloc 每个 student 结构,还是我在这里遗漏了一些完全不同的东西?

编辑:当我在while循环中为每个学生分配内存时,代码似乎有效:

S[i] = (student *)malloc(sizeof(student));

所以这似乎已经解决了这个问题。我会进行一些测试以确保。

【问题讨论】:

  • 这看起来像一个奇怪的链接列表\二维数组。你要哪个?
  • 您能解释一下输入行的格式吗? "%d %[^,], %s %f" 你为什么要用',' 这样做?
  • 安德烈,这是一个疏忽,我很抱歉。我之前尝试过 LL 方法,但发现它不是我需要的。 @AdriánLópez 输入数据的格式为 , 。我只是使用扫描集来摆脱逗号。我很抱歉没有提到这一点!
  • 是的,您必须为每个学生分配内存,或者您可以分配一个 students 数组作为开头,而不是一个指向学生的指针数组。 IE。将S = (student**)malloc(sizeof(student*)*N) 替换为S = (student*)malloc(sizeof(student)*N)
  • 确实问题出在您的内存分配上。您需要N * the size of the structure 的内存,而不是N * the size of a pointer to your structure

标签: c segmentation-fault dynamic-arrays scanf


【解决方案1】:

在第 19 行,您为 N 个学生指针分配了足够的空间,但没有为学生自己的结构分配空间。您需要执行以下操作:

for( int i = 0; i < N; i++) {
     S[i] = malloc(sizeof(struct __student));
}

【讨论】:

  • 哦,哎呀,看起来您通过编辑回答了自己的问题。
  • 我做到了,但无论哪种方式我都会接受答案,因为它是正确的。谢谢。
【解决方案2】:

除了你的 malloc 问题之外,这两行还有很大的问题

while(!feof(fp)){
    fscanf(fp, "%d %[^,], %s %f", &S[i]->ID, S[i]->lname, S[i]->fname, &S[i]->grade ); // segfault occurs on this line

一个问题是您的 lnamefname 字段是固定大小的 33 字符数组,这意味着如果您的输入此时有超过 32 个字符,您将跑出数组的末尾并损坏事物。另一个问题是您没有检查fscanf 的返回值以查看是否有问题(例如EOF),导致您在到达文件末尾时尝试打印垃圾记录。你想要的是这样的:

while (fscanf(fp, "%d %32[^,],%32s%f", &S[i]->ID, S[i]->lname, S[i]->fname, &S[i]->grade) == 4) {

用于您的循环控制。

编辑

while(!feof(fp)) 的问题(以及为什么它几乎总是一个错误)是feof(fp) 仅在您尝试读取文件末尾之后才返回 true。在你读完最后一行之后,feof(fp) 仍然返回 false,所以你再次进入循环并尝试读另一行。该读取失败,但由于您没有检查 fscanf 的返回值,因此您没有意识到这一点,而是在您的数组中获得了一个垃圾额外值。

【讨论】:

  • 感谢您的回答。我不检查输入大小的原因是,正如我所说,这是一个分配,输入大小保证是一致的。当然,否则我会检查一下。谢谢你提到返回值,我确实应该养成一个习惯,尽可能地使用它来进行错误检测。一件事:while(!feof(fp)) 和 while(fscanf(...) == 4) 之间有什么区别?由于我正在从一致的输入中读取,因此无法匹配这些项目基本上等同于它是 EOF,不是吗?谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-17
  • 1970-01-01
  • 2021-08-19
  • 2011-01-02
  • 2016-01-22
  • 1970-01-01
相关资源
最近更新 更多