【问题标题】:Database of student info using array of structures (C language)使用结构数组的学生信息数据库(C 语言)
【发布时间】:2014-03-20 10:09:13
【问题描述】:

函数 computeScore() 用于使用结构数组创建一个最多包含 50 名学生的数据库。该函数接收学生、姓名、考试成绩和考试成绩,计算总分,然后打印出来。当学生姓名为“END”时,输入将结束。之后,程序将计算总平均分或所有学生并打印出来。

当我输入第一个学生的信息时效果很好,但是当程序第二次进入 while 循环时我遇到了麻烦(当我想输入第二个学生的信息时)。

这是我到目前为止所做的:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h> 
#include <string.h> 
#include <math.h>

struct student{
    char name[20];     /* student name */
    double testScore;  /* test score */
    double examScore;  /* exam score */
    double total;      /* total score = test+exam scores */
};

void computeScore();

int main()
{
computeScore();
return 0;
}

void computeScore()
{
    struct student info[50];
    int count = 1;
    double allStudent = 0, allStudentAvg;

    while (info[count].name != 'END')
    {
        printf("\nEnter student name: ");
        gets(info[count].name);
        printf("Enter test score: ");
        scanf("%lf", &info[count].testScore);
        printf("Enter exam score: ");
        scanf("%lf", &info[count].examScore);

        info[count].total = (info[count].testScore + info[count].examScore) / 2;
        printf("Student %s's total= %f\n", info[count].name, info[count].total);

        allStudent += info[count].total;
        count++;
    }
    allStudentAvg = allStudent / count;
    printf("Overall average = %f", allStudentAvg);
}

预期输出:

Enter student name: John Doe
Enter test score: 34
Enter exam score: 46
Student John Doe's total = 40.000000

Enter student name: Jane Doe
Enter test score: 60
Enter exam score: 80
Student John Doe's total = 70.000000

Enter student name: END
Overall average: 55.000000

我得到的输出是:

Enter student name: John Doe
Enter test score: 34
Enter exam score: 46
Student John Doe's total = 40.000000

Enter student name: Enter test score: 

\\Program skipped the input of 2nd student name

【问题讨论】:

    标签: c arrays structure


    【解决方案1】:

    这是因为最后一次调用scanf,它使换行符仍在缓冲区中,所以下一个gets 读取该换行符。

    您可以使用虚拟的gets 调用显式获取该换行符,但通过在格式后添加一个空格来告诉scanf 简单地读取(并丢弃)尾随空格会更容易:

    scanf("%lf ", &info[count].examScore);
    /*        ^        */
    /*        |        */
    /* Note space here */
    

    不必担心前导空格(如上次scanf 调用中缓冲区中留下的换行符),因为数字格式(和其他一些格式)会自动跳过前导空格。您可能想阅读this reference

    【讨论】:

    • 我添加了空格,它不起作用,它现在没有读入我的考试成绩):
    【解决方案2】:

    不要使用gets 读取字符串。它是一种痛苦!最好使用fgets

    fgets(info[count].name, 20, stdin);
    

    scanf 一起使用时要小心。在这种情况下,这些函数会读取上一个 scanf 调用留下的 \n 字符。
    您可以通过在最后一个scanf 之后放置一个getchar 来使用这个\n

    scanf("%lf", &info[count].examScore);
    getchar();  
    

    甚至更好

    scanf("%lf", &info[count].examScore);
    while(getchar() != '\n'); 
    

    【讨论】:

      【解决方案3】:

      预计您的下一个问题:

      替换

      info[count].name != 'END'
      

      通过

      strcmp(info[count].name, "END") != 0
      

      您不能使用!= 运算符比较字符串,您可以使用strcmp 函数。

      此外:

      你声明了int count = 1;,但这意味着info数组的第一个元素不会被使用,你应该有int count = 0;

      在while 条件info[count].name != 'END' 中,info[count].name 未初始化,因此即使您按照之前的建议使用strcmp 更正条件,您的比较也可能总是错误的。换句话说:您比较用户之前是否输入过“END”,甚至输入过“END”。

      【讨论】:

      • 如何初始化 info[count].name?
      • 其实不是初始化与否,而是你应该改变你的程序的逻辑。在gets(info[count].name); 之后进行测试,如果为真,则退出循环。
      【解决方案4】:

      Scanf 给你造成了这个问题..

      在 scanf 之前使用__fpurge(stdin) 来解决您的问题。

      使用fgets 而不是scanf

      【讨论】:

      • 请注意,这是一个非标准函数。
      【解决方案5】:

      对不起,我还不能发表评论。除了黑客的回答,我想建议你在 scanf 之前使用 fflush(stdin) 或 fluahall() 并且你应该使用 strcmp 代替 info[count].name != '结束'。

      【讨论】:

        【解决方案6】:

        不要使用gets 读取字符串。这是不安全的,因为如果输入字符串过大调用未定义的行为并且很可能由于段错误而导致程序崩溃,它会溢出它写入的缓冲区。问题是while 循环中的最后一个scanf 调用将尾随换行符留在stdin 缓冲区中 -

        scanf("%lf", &info[count].examScore);
        

        然后gets 在循环的下一次迭代中读取此换行符,导致gets 返回。阅读此 C-FAQ Why gets call is skipped? 您应该使用 scanf 而不是 gets

        替换下面的语句

        gets(info[count].name);
        

        scanf(" %19s", info[count].name);  // -1 for the terminating null byte
        

        注意格式字符串" %19s" 中的前导空格。这导致scanf 读取并丢弃位于stdin 缓冲区中的任意数量的无关(包括零)空白字符。 19 表示scanf 最多将 19 个字符写入缓冲区,然后在末尾附加空字节。这称为最大字段宽度,可确保在输入字符串过长的情况下,scanf 不会超出缓冲区,从而引发未定义的行为。

        【讨论】:

          【解决方案7】:

          你不能使用逻辑运算符比较字符串第一个错误,第二个''可以只包含字符表示任何单个字符,它可能是数字、符号等。这是两个问题,有些 get 和 puts 甚至 scanf 都会跳过单词所以您有时必须使用两个输入预定义函数,因为它们中的任何一个都会读取。

          scanf(some input);
          gets(some input);
          

          其中任何一个都可以工作我个人使用它。

          【讨论】:

            猜你喜欢
            • 2015-06-07
            • 1970-01-01
            • 2012-08-30
            • 2021-01-27
            • 1970-01-01
            • 1970-01-01
            • 2012-06-08
            • 2011-03-19
            • 2023-03-07
            相关资源
            最近更新 更多