我正试图创建一个记录,在其中我可以跟踪学生的名字和他们的分数。运行后,我输入一个学生记录,输入两个记录后,我得到一个segmentation fault错误。
我不明白是什么原因导致这个错误,因为我是一个初学者的C语言。
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Students {
char name[100];
int roll;
float mark;
} Student;
int main() {
int N, i;
printf("How many students do you want to enter: ");
scanf("%i", &N);
Student *st = malloc(N*sizeof(Student));
for (i = 0; i < N; i++) {
printf("Enter name: ");
scanf("%s", st[i].name);
st[i].roll = i;
printf("Enter score for %s", st[i].name);
scanf("%f", &st[i].mark);
printf("%i. %s ", i, st[i].name);
printf("%s: %f ", i, &st[i].mark);
printf("\n");
}
return 0;
}
2条答案
按热度按时间abithluo1#
虽然你有一个解释,你 segfault 起源,如果你要学习C,不要过早学习坏习惯。在考虑代码是否可靠之前,您应该解决许多问题,并且可以解决许多其他问题,以使代码像预期的那样工作。
首先,* 验证**所有用户输入!.如果你无法验证所有的用户输入,你就不知道你的代码是在处理垃圾,还是从你接受的第一个输入开始就偏离到了“未定义的行为”。用户可以输入任何东西,或者猫可以在键盘上行走,等等。您有责任验证您的输入是否符合预期。
例如,从第一次输入开始,您应该 * 至少 * 检查
scanf
的返回,以确保您获得了预期的 * 成功转换 * 的数量。这很容易做到,例如,当接受字符串输入时,您需要将接受的字符数限制为可用存储空间的大小。您可以使用
scanf
使用 width 修饰符来完成此操作。由于name
中有 100 个可用字符,因此可以存储 *99个字符 * 加上 * 空终止字节 *。此外,由于名称可以包含空格,因此可以使用 character class 来读取'\n'
字符之前的所有字符。(这里你可以使用 * 行导向 * 输入函数,比如fgets
)。例如,您还需要了解您将
'\n'
留在 input buffer(stdin
)中,并且您必须考虑到,如果您的下一个输入是scanf
的字符输入,则'\n'
将很乐意接受'\n'
作为您的输入。所有面向行的输入函数(fgets
,getline
)读取并包含'\n'
,scanf
不读取并包含'\n'
。但是,您可以使用 * 赋值抑制 * 操作符'*'
来 * 读取并丢弃 * 指定的输入(%*c
读取/丢弃下一个字符('\n'
))。在你写的任何动态分配内存的代码中,你有两个关于任何分配的内存块的责任:(1)* 始终为内存块保留一个指向起始地址 * 的指针,因此,(2)当不再需要它时,它可以被释放。例如,
你必须使用一个内存错误检查程序来确保你没有写超出/超出你分配的内存块,试图读取或基于一个未初始化的值进行跳转,最后确认你已经释放了所有你分配的内存。对于Linux,Valgrind是正常的选择,但每个操作系统都有类似的程序。
最后,虽然不是一个错误,但C的标准编码风格避免了
caMelCase
变量,而支持所有 * 小写 *。参见NASA - C Style Guide, 1994把所有这些放在一起,并调整输出和格式,以达到你想要的效果(我可能完全错了),你可以重写代码如下:
示例使用/输出
5m1hhzi42#
使用调试器并在核心转储中进行回溯,您会发现它在此处崩溃;
这一行可能看起来像这样;