获取seg错误而不是打印struct值

时间:2016-06-17 00:41:28

标签: c segmentation-fault

我正在尝试创建一个记录,在其中我可以跟踪学生的姓名和分数。运行后,我输入1个学生记录,输入2个记录后,我收到分段错误错误。我不明白是什么导致了这个错误,因为我是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 个答案:

答案 0 :(得分:2)

在核心转储上使用调试器和回溯,你会发现它崩溃了;

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

该行应该看起来像这样;

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

答案 1 :(得分:2)

虽然您对段错误的来源有解释,但如果您要学习C,请不要及早学习坏习惯。在您认为代码可靠之前,您应该解决许多问题,并且您可以解决许多其他问题,以使您的代码看起来像您想要的那样。

首先,验证所有用户输入!。如果您未能验证所有用户输入,则无法确定您的代码是否正在处理垃圾或从您第一次输入的未定义行为中消失。用户可以输入任何内容 - 或者猫可以在键盘上行走等等......您有责任确认您是否有您期望的输入。

例如,从您的第一个输入开始,您应该至少检查scanf的返回,以确保您拥有成功转化的数量您期望。这很简单,例如

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

在进行字符串输入时,您需要将接受的字符数限制为可用存储空间的大小。您可以使用 width 修饰符使用scanf完成此操作。由于100中有name个字符,因此您可以存储99 charsnul-terminating byte。此外,由于名称可以包含空格,因此您可以使用字符类来读取最多'\n'个字符的所有字符。 (这里使用面向行的输入函数,例如fgets)可以更好地服务。 e.g。

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

您还需要了解您将'\n'留在输入缓冲区stdin)中,如果您的下一个输入是{的字符输入,您必须考虑到这一点{1}}很乐意将scanf作为您的输入。所有面向行的输入函数('\n'fgets)都会读取并包含getline'\n'则不会。但是,您可以使用赋值抑制运算符scanf读取并放弃指定的输入('*'来读取/放弃下一个字符( %*c))。

在任何动态分配内存的代码中,对于分配的任何内存块,您都有2个职责:(1)始终保留指向起始地址的指针因此,(2)当不再需要时,它可以释放。 e.g。

'\n'

您必须使用内存错误检查程序,以确保您没有在已分配的内存块之外/之外写入,尝试读取或基于未初始化的值跳转,最后确认您已拥有释放了你分配的所有内存。对于Linux free (st); /* free allocated memory */ 是正常选择,但每个操作系统都有类似的程序。

最后,虽然不是错误,但C的标准编码样式避免使用valgrind变量来支持所有小写。参见例如NASA - C Style Guide, 1994

把所有这些放在一起,并将输出和格式调整到你想要的东西(我可能完全错了),你可以重写代码如下:

caMelCase

示例使用/输出

#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;
}

查看所有答案和评论,如果您有任何问题,请与我们联系。