C语言 我得到了一个分段错误,而不是打印结构值

7fhtutme  于 2023-05-22  发布在  其他
关注(0)|答案(2)|浏览(98)

我正试图创建一个记录,在其中我可以跟踪学生的名字和他们的分数。运行后,我输入一个学生记录,输入两个记录后,我得到一个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;
}
abithluo

abithluo1#

虽然你有一个解释,你 segfault 起源,如果你要学习C,不要过早学习坏习惯。在考虑代码是否可靠之前,您应该解决许多问题,并且可以解决许多其他问题,以使代码像预期的那样工作。
首先,* 验证**所有用户输入!.如果你无法验证所有的用户输入,你就不知道你的代码是在处理垃圾,还是从你接受的第一个输入开始就偏离到了“未定义的行为”。用户可以输入任何东西,或者猫可以在键盘上行走,等等。您有责任验证您的输入是否符合预期。
例如,从第一次输入开始,您应该 * 至少 * 检查scanf的返回,以确保您获得了预期的 * 成功转换 * 的数量。这很容易做到,例如,

if (scanf ("%d", &n) != 1) {    /* validate number */
    fprintf (stderr, "error: invalid input (number).\n");
    return 1;
}

当接受字符串输入时,您需要将接受的字符数限制为可用存储空间的大小。您可以使用scanf使用 width 修饰符来完成此操作。由于name中有 100 个可用字符,因此可以存储 *99个字符 * 加上 * 空终止字节 *。此外,由于名称可以包含空格,因此可以使用 character class 来读取'\n'字符之前的所有字符。(这里你可以使用 * 行导向 * 输入函数,比如fgets)。例如,

if (scanf (" %99[^\n]%*c", st[i].name) != 1) {
        fprintf (stderr, "error: invalid input (name).\n");
        return 1;
    }

您还需要了解您将'\n'留在 input bufferstdin)中,并且您必须考虑到,如果您的下一个输入是scanf的字符输入,则'\n'将很乐意接受'\n'作为您的输入。所有面向行的输入函数(fgetsgetline)读取并包含'\n'scanf不读取并包含'\n'。但是,您可以使用 * 赋值抑制 * 操作符'*'来 * 读取并丢弃 * 指定的输入(%*c读取/丢弃下一个字符('\n'))。
在你写的任何动态分配内存的代码中,你有两个关于任何分配的内存块的责任:(1)* 始终为内存块保留一个指向起始地址 * 的指针,因此,(2)当不再需要它时,它可以被释放。例如,

free (st);  /* free allocated memory */

你必须使用一个内存错误检查程序来确保你没有写超出/超出你分配的内存块,试图读取或基于一个未初始化的值进行跳转,最后确认你已经释放了所有你分配的内存。对于Linux,Valgrind是正常的选择,但每个操作系统都有类似的程序。
最后,虽然不是一个错误,但C的标准编码风格避免了caMelCase变量,而支持所有 * 小写 *。参见NASA - C Style Guide, 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  mark\n\n", maxc, "name");
    for (i = 0; i < n; i++)
        printf (" %3d  %-*s  %.2f\n",
                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
5m1hhzi4

5m1hhzi42#

使用调试器并在核心转储中进行回溯,您会发现它在此处崩溃;

printf("%s: %f ",i,&st[i].mark);

这一行可能看起来像这样;

printf("%d: %f ",i,st[i].mark);

相关问题