分段故障核心转储...?

Posted

技术标签:

【中文标题】分段故障核心转储...?【英文标题】:Segmentation fault core dumped...? 【发布时间】:2011-11-06 08:09:32 【问题描述】:

我正在努力做到这一点:

编写一个接受三个用户输入的程序:作业分数、期中分数和期末考试 标记。

这些输入的类型为浮点型,值应介于 0 和 100 之间。

程序 应该将最终成绩计算为百分比和字母成绩。

• 期末成绩计算为:作业 20%,期中 30%,期末考试 50%。字母等级 计算为:A(最终成绩 ≥ 80%),B(80 > 最终成绩 ≥ 70%),C(70 > 最终成绩 ≥ 60%), D(60 > 最终成绩 ≥ 50%)和 F(50 > 最终成绩)。

显示最终成绩和字母成绩。

使用以下代码:

#include <stdio.h>

int checkMark(int);
float getMark();
float computeFinalGrade(float assign, float midterm, float finalExam, float finalGrade);
int computeLetterGrade(float);

int checkMark(int x)

    while(x<0 || x>100) //While x is a negative number:
    
        printf("Invalid entry.Try again:");
        scanf("%d",&x);
    

    if(x>0 && x<=100)//If x is a positive number:
        x=x;

    return x;


float getMark(void)

    float mark=0,assignMark=0,midMark=0,examMark=0,finalMark=0;
    char letterGrade;


    printf("Enter assignment grade:");
    scanf("%d",mark);

    checkMark(mark);
    assignMark=mark;

    printf("\nEnter midterm mark:");
    scanf("%f",&mark);

    checkMark(mark);
    midMark=mark;

    printf("\nEnter exam mark:");
    scanf("%f",&mark);

    checkMark(mark);
    examMark=mark;


    finalMark=computeFinalGrade(assignMark,midMark,examMark,finalMark);
    letterGrade=computeLetterGrade(finalMark);

    printf("The final grade for the course is %.1f, and the letter grade is %c.\n",finalMark,letterGrade);

    return 0;


float computeFinalGrade(float assign, float midterm, float finalExam, float finalGrade)

    assign=(float)0.2*assign;
    midterm=(float)0.3*midterm;
    finalExam=(float)0.4*finalExam;

    finalGrade=(float)assign+midterm+finalExam;
    return finalGrade;


int computeLetterGrade(float finalGrade)

    int grade;

        if(finalGrade>=80)
            grade=65;

        if(finalGrade<80)
            if(finalGrade>=70)
                grade=66;

        if(finalGrade<70)
            if(finalGrade>=60)
                grade=67;

        if(finalGrade<60)
            if(finalGrade>=50)
                grade=68;

        if(finalGrade<50)
            grade=70;

    return grade;


int main()

    getMark();

    return 0;

当我调试上面的程序并输入一个负数时,它给了我这个:

Enter assignment grade:123
Segmentation fault (core dumped)

我到底做错了什么?

【问题讨论】:

学习使用调试器,如gnu.org/s/gdb 它在哪里崩溃?将核心文件加载到 gdb 并进行一些事后分析。然后,当您知道它崩溃的哪一行时,这个主题就容易一些了。 123 不是负数... @NickLH:在这种情况下,我认为它是 错误 中的“负面”。 他说“并输入一个负数”,即数字 【参考方案1】:

这是你的问题:

scanf("%d",mark);

你需要传递变量的地址,说明符应该是%f。试试:

scanf("%f", &mark);

顺便说一句,有一个C FAQ 与此有关。

【讨论】:

如果您使用gcc -Wall -g yourcode.c -o yourprogram 编译,编译器会捕捉到这一点。但你真的应该了解更多! 你应该学习如何使用gdb,你应该学习更多关于如何使用gcc。特别是,您应该始终将 -Wall 传递给 gcc 以获取您的代码。您可能还应该学习如何使用make 并在多个源文件中编写程序。玩得开心。 @BasileStarynkevitch 你是如何推断我不知道如何使用gdb 或者我没有在启用警告的情况下编译的? Basile 可能在谈论 OP,@cnicutar 是的,指的是Iakam99,那个正在做作业的人。【参考方案2】:

关于您的代码的更多评论:

int checkMark(int x)

    while(x<0 || x>100) //While x is a negative number:
    
        printf("Invalid entry.Try again:");
        scanf("%d",&x);
    

    if(x>0 && x<=100)//If x is a positive number:
        x=x;

    return x;

应该是:

#define MIN_GRADE 0
#define MAX_GRADE 100

int checkMark(int x)

    while(x<MIN_GRADE || x>MAX_GRADE)
    
        printf("Invalid entry.Try again:");
        scanf("%d",&x);
    

    return x;

注意我:

删除了无用的 cmets

移除了幻数(0 和 100)

删除了一个无用的测试(如果退出 while 循环,则 x 在 0, ..., 100

允许x 等于0

删除了幂等赋值(x=x 没有做任何有用的事情...)

然后:

float getMark(void)

    float mark=0,assignMark=0,midMark=0,examMark=0,finalMark=0;
    char letterGrade;

    printf("Enter assignment grade:");
    scanf("%d",mark);

^ 正如其他人所说,你应该在这个scanf中使用%f&amp;mark

    checkMark(mark);

^ 此处,如果您希望更新此代码中的mark 变量,则应为mark = checkMark(mark);。这是因为mark 的值被传递给函数,而不是对变量mark 的引用。另一种解决方案是传递这样的参考,但我认为你还没有准备好:)

    assignMark=mark;

    printf("\nEnter midterm mark:");
    scanf("%f",&mark);

    checkMark(mark);
    midMark=mark;

    printf("\nEnter exam mark:");
    scanf("%f",&mark);

    checkMark(mark);
    examMark=mark;

^ 所有这些行的注释相同

    finalMark=computeFinalGrade(assignMark,midMark,examMark,finalMark);

^ 在这里传递finalMark 作为参数是完全没用的。应该只是finalMark = computeFinalGrade(assignMark, midMark, examMark);,你不觉得吗?

    letterGrade=computeLetterGrade(finalMark);

    printf("The final grade for the course is %.1f, and the letter grade is %c.\n",finalMark,letterGrade);

    return 0;

如前所述,您不需要将一些finalGrade 值传递给computeFinalGrade,您应该可以:

float computeFinalGrade(float assign, float midterm, float finalExam)

    return 0.2*assign + 0.3*midterm + 0.4*finalExam; // this could even be a macro

最后,在computeLetterGrade 中,您正在执行大量冗余测试,并且您的控制流被此变量分配弄乱了,另外您应该使用char 而不是int。试试这个:

char computeLetterGrade(float finalGrade)

    if(finalGrade>=80) return 'A';
    // Since we did not return, necessarily finalGrade < 80
    if(finalGrade>=70) return 'B';
    if(finalGrade>=60) return 'C';
    if(finalGrade>=50) return 'D';
    // All other ifs failed, therefore finalGrade < 50
    return 'E';

您可能需要修复一些我没有提到的问题,但至少您应该通过其中一些更正更接近您的目标。

【讨论】:

【参考方案3】:

如果您使用的是 linux,请查看我的回答 here。这是关于 valgrind,一个帮助调试段错误、内存泄漏等的工具。

【讨论】:

【参考方案4】:

当您的程序尝试访问分配给您的程序的内存区域之外的内存区域时,会发生分段错误。 scanf() 需要变量的地址。在您的代码中,您将变量的值传递给scanf(),而不是 cnicutar 指出的地址。

scanf("%d",mark);

mark 变量没有初始化并且有一些随机数据,被scanf 当作一个内存位置,当它试图写入那个地址时... 出现分段错误,因为你访问了一个受限的内存。另外,mark 是浮点变量,所以你应该使用%f 说明符..

scanf("%f", &mark);

【讨论】:

以上是关于分段故障核心转储...?的主要内容,如果未能解决你的问题,请参考以下文章

在 C 中转储的分段故障核心

分段故障核心转储在 Hermite 中

C - 分段故障(核心转储)

使用嵌套在向量中的向量转储的分段故障核心

python OpenCV分段故障(核心转储)

分析分段错误核心转储 (gdb)