我正在尝试创建一个记录,其中我可以跟踪学生的名字及其分数。运行后,我输入一个学生记录,然后输入两个记录后,我会遇到一个分段故障错误。
我不明白是什么导致了这个错误,因为我是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;
}
当您对自己的位置有解释,如果您要学习C,请不要尽早学习不良习惯。在考虑您的代码可靠之前,您应该解决许多问题,还有许多其他问题可以解决您的代码工作,就像您预期的那样工作。
首先, validate asl 用户输入!。如果您未能验证所有用户输入,则不知道您的代码是从您使用的第一个输入中处理垃圾还是偏离了不确定的行为。用户可以输入任何东西,或者猫可以在键盘上行走,等等...您有责任验证您有期望的输入。
例如,从您的第一个输入开始,您应该在最小上检查 scanf
的返回以确保您的成功转换的数量 。这很简单,例如,
if (scanf ("%d", &n) != 1) { /* validate number */
fprintf (stderr, "error: invalid input (number).n");
return 1;
}
服用字符串输入时,您需要将接受的字符数限制为可用存储的大小。您可以使用 width 修饰符使用scanf
完成此操作。由于您在name
中具有可用的 100 字符,因此可以存储 99个字符加上 null-Null-enull-termination byte 。此外,由于名称可以包含空格,因此您可以使用a 字符类读取所有字符,直到'n'
字符。(在这里,最好使用面向线路的输入功能(例如fgets
)为您提供服务。例如,
if (scanf (" %99[^n]%*c", st[i].name) != 1) {
fprintf (stderr, "error: invalid input (name).n");
return 1;
}
您还需要了解您要在输入缓冲区(stdin
)中离开'n'
,如果您的下一个输入是scanf
的字符输入,则必须考虑到这一点。所有面向行的输入功能(fgets
,getline
)读取并包含'n'
,scanf
没有。但是,您可以使用 sissment抑制运算符 '*'
to read-> read-discard 指定的输入( %*c
( CC_15)读取/dost下一个字符( 'n'
))。
在您写动态分配内存的任何代码中,关于分配的任何内存块,您都有两个责任:(1)始终保留指向起始地址的指针 for记忆的块,(2)当不再需要时,它可以被释放。例如,
free (st); /* free allocated memory */
必须使用内存错误检查程序来确保您没有编写/之外的内存块,试图读取或基于非初始化的值读取或以跳高为基础,最后确认您已释放了所有您分配的内存。对于Linux,Valgrind是正常的选择,但是每个操作系统都有类似的程序。
最后,虽然不是错误,但C的标准编码样式避免了caMelCase
变量,而有利于所有下case 。参见例如 NASA- C样式指南,1994
将所有这些放在一起,并将输出和格式调整为您的预期(我可能完全错),您可以重写您的编码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct students {
char name[100];
int roll;
float mark;
} student;
int main ()
{
int n = 0, i = 0, maxc = 0; /* initialize variables */
student *st = NULL;
printf ("How many students do you want to enter: ");
if (scanf ("%d", &n) != 1) { /* validate number */
fprintf (stderr, "error: invalid input (number).n");
return 1;
}
/* allocate & validate */
if ((st = malloc (n * sizeof (student))) == NULL) {
fprintf (stderr, "error: virtual memory exhausted.n");
return 1;
}
for (i = 0; i < n; i++) { /* take input & validate */
printf ("enter name: "); /* limit & accept full name */
if (scanf (" %99[^n]%*c", st[i].name) != 1) {
fprintf (stderr, "error: invalid input (name).n");
return 1;
}
st[i].roll = i;
printf ("enter score for %s: ", st[i].name);
if (scanf ("%f", &st[i].mark) != 1) {
fprintf (stderr, "error: invalid input (mark).n");
return 1;
}
}
for (i = 0; i < n; i++) { /* compute max length for name */
int len = (int)strlen (st[i].name);
if (len > maxc)
maxc = len;
}
printf ("nroll %-*s marknn", maxc, "name");
for (i = 0; i < n; i++)
printf (" %3d %-*s %.2fn",
st[i].roll, maxc, st[i].name, st[i].mark);
free (st); /* free allocated memory */
return 0;
}
示例使用/输出
$ ./bin/structloop
How many students do you want to enter: 4
enter name: John J. Franklin
enter score for John J. Franklin: 83.1
enter name: Betty C. Smith
enter score for Betty C. Smith: 91.2
enter name: Jennifer L. Burgen-Kwiatkowski
enter score for Jennifer L. Burgen-Kwiatkowski: 88.7
enter name: Alfred R. Murrow
enter score for Alfred R. Murrow: 73.5
roll name mark
0 John J. Franklin 83.10
1 Betty C. Smith 91.20
2 Jennifer L. Burgen-Kwiatkowski 88.70
3 Alfred R. Murrow 73.50
使用调试器并在核心转储处进行回溯,您会在这里崩溃;
printf("%s: %f ",i,&st[i].mark);
该线可能应该看起来像这样;
printf("%d: %f ",i,st[i].mark);