gpt4 book ai didi

c - 由 fscanf 引起的 fscanf 上的探查器错误

转载 作者:行者123 更新时间:2023-12-04 01:06:40 27 4
gpt4 key购买 nike

我正在用 C 编写一个函数,它应该从文件中输入有关学生及其成绩的信息。但是,有时在运行程序时,即使输出符合预期,测试也会在 fscanf 处显示分析器错误。

/*structure for grade*/
struct Grade {
char subject[51];
int grade;
};
/*structure for student*/
struct Student {
char name[21], surname[21];
int no_grades;
struct Grade grades[100];
};
int input_students(struct Student *students, int n) {
int i = 0, no, j, first;
char name[21], surname[21], subject[51];
FILE *database = fopen("input.txt", "r");
if (database == NULL) {
printf("Error while opening input.txt");
return 0;
}
while (/*i < n && */fscanf(database, "%20s %20s %50s %d\n", name, surname, subject,
&no) == 4) {
first = 1;
for (j = 0; j < i; j++) {
if (strcmp(students[j].name, name) == 0 &&
strcmp(students[j].surname, surname) == 0) {
first = 0;
if (students[j].no_grades >= 100) { /*limit for number of grades per student is 100*/
break;
}
strcpy(students[j].grades[students[j].no_grades].subject,
predmet);
students[j].grades[students[j].no_grades].grade = no;
students[j].no_grades++;
break;
}
}
if (first && i < n) {
strcpy(students[i].name, name);
strcpy(students[i].surname, surname);
students[i].no_grades = 0;
strcpy(students[i].grades[students[i].no_grades].subject, subject);
students[i].grades[students[i].no_grades].grade = no;
students[i].no_grades++;
i++;
}
}
/*while (fscanf(database, "%20s %20s %50s %d\n", name, surname, subject,
&no) == 4) {
for (j = 0; j < i; j++) {
if (strcmp(students[j].name, name) == 0 &&
strcmp(students[j].surname, surname) == 0) {
if (students[j].no_grades >= 100) {
break;
}
strcpy(students[j].grades[students[j].no_grades].subject,
subject);
students[j].grades[students[j].no_grades].grade = no;
students[j].no_grades++;
break;
}
}
}*/

fclose(database);
return i;
}
/更新,注释将代码更改为只有一个循环,同样的事情发生/
返回值是从文件中读取信息的学生人数,而 i < n。
探查器消息指示 fscanf 行中的错误。
==3928== Invalid write of size 1
==3928== at 0x37154582C7: _IO_vfscanf (in /lib64/libc-2.12.so)
==3928== by 0x371546465A: __isoc99_fscanf (in /lib64/libc-2.12.so)
==3928== by 0x400AD5: input_students (main.c:22)
==3928== by 0x401394: main (main.c:174)
==3928== Address 0x7feff2e00 expected vs actual:
==3928== Expected: stack array "name" of size 21 in frame 2 back from here
==3928== Actual: stack array "surname" of size 21 in frame 2 back from here
==3928== Actual: is 32 before Expected
我似乎无法找到这是什么原因。我已经仔细检查了每个字符串是否以 '\0' 结尾,我已经通过调试器运行了程序,它在它应该停止的地方停止,我还没有看到它继续运行并使用未初始化的值,并且它所采用的值符合预期.
我已经翻译了函数和变量的名称,因为它最初不是英文的,因此问题不可能出在函数名称与库函数名称重叠上,但我会在这里更改。
测试代码。这是一个自动测试。
int i, j, no_students;
struct Student students[10];
FILE* database = fopen("input.txt", "w");
fputs("Pero Peric Osnove_racunarstva 8", database);
fputc(10, database);
fputs("Suljo Suljic Osnove_racunarstva 9", database);
fputc(10, database);
fputs("Pero Peric Inzenjerska_matematika_1 6", database);
fclose(database);

no_students=input_students(students, 10);
printf("%d\n", no_students);
for (i=0; i<no_students; i++) {
printf("%s %s ", students[i].name, studenti[i].surname);
for (j=0; j<students[i].no_grades; j++)
printf("%s %d ", students[i].grades[j].subject, students[i].grades[j].grade);
printf("\n");
}
此测试的输出。
2
Pero Peric Osnove_racunarstva 8 Inzenjerska_matematika_1 6
Suljo Suljic Osnove_racunarstva 9
当测试代码在 main.c 中运行时,它不会显示任何编译器错误,调试器也不会显示段错误。
input.txt 的示例,由该自动测试创建。
Pero Peric Osnove_racunarstva 8
Suljo Suljic Osnove_racunarstva 9
Pero Peric Inzenjerska_matematika_1 6
这将是关于分析器的信息,请记住我仍然只是一个学生
==17000== exp-sgcheck, a stack and global array overrun detector
==17000== NOTE: This is an Experimental-Class Valgrind Tool
==17000== Copyright (C) 2003-2012, and GNU GPL'd, by OpenWorks Ltd et al.
==17000== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==17000== Command: outputP9YqwH

最佳答案

好的,这是我认为正在发生的事情:

no_students=input_students(students, 10);
所以你期待 10 个学生,但你有 4 个。所以简单的原因我们将文件指针 database pint 指向 0 行(而不是地址 0)。所以你有这个:
row  name   surname subject                  grade_cnt
0 Pero Peric Osnove_racunarstva 8\n
1 Suljo Suljic Osnove_racunarstva 9\n
3 Pero Peric Inzenjerska_matematika_1 6<END OF FILE>
注意:第 3 行的末尾可能是文件结尾。
所以你第一个循环去读取第 0、1 ... 3 行并尝试读取第 4 行。没有第 4 行,所以它失败了。但可能发生的情况是,当第一个循环完成跳过 EOF 并读取文件缓冲区末尾之外时, database 指向第 4 行。
有两种测试方法:
  • 在第 4 行
  • 之后输入空行
  • while() 循环之间关闭并重新打开文件。

  • 您可能跳过文件指针的另一个原因是:
    fscanf(database, "%20s %20s %50s %d\n", name, surname, subject, &no) == 4)
    \n 之后注意 %d 如果 \n 消失了会发生什么? fscanf() 正在寻找“\n”。
    尝试在输入文件的末尾添加空行。
    或者删除'\n'。
    fscanf(database, "%20s %20s %50s %d", name, surname, subject, &no) == 4)
    这背后的另一个原因是数字 %20s :
    fscanf(database, "%s %s %s %d", name, surname, subject, &no) == 4)
    如果我弄错了,请任何人在评论中告诉我。
    由于 fscanfname 读取 20 个字符。
    编辑:现在我确定我是对的:
    阅读 thisscanffscanf 应谨慎使用,最好避免使用。

    关于c - 由 fscanf 引起的 fscanf 上的探查器错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66188754/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com