0

我写这篇文章是为了获取学生信息(最后 3 个学期的全名、id 和 gpa,所以我使用结构和 for 循环来插入信息,但是,在第一次执行 for 循环之后(这意味着学生 2 )我的第一个和第二个输入一起显示在屏幕上。我怎样才能以一种简单易懂的方式防止这种情况发生?( PS:我已经尝试将 getchar(); 放在 for 循环的末尾并且它起作用了,但是;我不应该使用它,因为我们还没有在课堂上学习过)

我的错误发生的c程序部分:

 #include <stdio.h>

struct Student {
  char name[30];
  int id;
  float gpa[3];
};

float averageGPA ( struct Student [] );

int main()
{
  int i;
  float average;
  struct Student studentlist[10];
  i=0;

  for (i; i<10; i++)
  {
     printf("\nEnter the Student %d full name: ", i+1);
     fgets(studentlist[i].name, 30, stdin);
     printf("Enter the Student %d ID: ", i+1);
     scanf("\n %d", &studentlist[i].id);
     printf("Enter the Student %d GPA for the 1st trimester: ", i+1);
     scanf("%f", &studentlist[i].gpa[0]);
     printf("Enter the Student %d GPA for the 2nd trimester: ", i+1);
     scanf("%f", &studentlist[i].gpa[1]);
     printf("Enter the Student %d GPA for the 3rd trimester: ", i+1);
     scanf("%f", &studentlist[i].gpa[2]);
  }

  average = averageGPA(studentlist);

  printf("\n\nThe average GPA is %.2f", average); 

  return 0;
}

float averageGPA (struct Student studentlist[])
{
  int i;
  float total = 0.0, average = 0.0;
  for (i=0; i<10; i++)
  {
    total =  studentlist[i].gpa[0] + studentlist[i].gpa[1] + studentlist[i].gpa[2]; 
  }

  average = total / 30 ;
  return average;
}

电脑输出:

Enter the Student 1 full name: mm

Enter the Student 1 ID: 12

Enter the Student 1 GPA for the 1st trimester: 3

Enter the Student 1 GPA for the 2nd trimester: 4

Enter the Student 1 GPA for the 3rd trimester: 3

Enter the Student 2 full name: Enter the Student 2 ID: <<<<< Here is the problem!!
4

4 回答 4

2

尝试在最后一个之后吃换行符scanf

scanf("%f ", &studentlist[i].gpa[2]);
         ^

这非常像您的getchar解决方案。它实际上优于getchar,因为它只丢弃空格。

于 2012-09-07T11:08:24.873 回答
2

但是你必须使用getchar()丢弃在你的 last 之后仍然在输入缓冲区中的换行符scanf("%f"),它根据给定的格式转换一个浮点数并将所有其他字符留在缓冲区中。

如果您不能使用,请在循环结束时getchar()使用另一个.. 但当然会更好fgets()getchar()

编辑解释:每当您在键盘上键入字符时,都会进入一个输入缓冲区,等待您的应用程序处理。getchar() 只是从这个缓冲区“消耗”一个字符(返回它),如果缓冲区为空,则等待一个有效的字符。scanf("%f") 仅“消耗”字符,导致浮点数。因此,当您键入“5.12<enter>”时,scanf 会从缓冲区“5.12”中读取并删除,留下“<enter>”。所以下一个 fgets() 已经在缓冲区中找到了换行符并立即返回;这就是为什么你应该使用 getchar(): 忽略它的返回值,你成功地从缓冲区中丢弃“<enter>”。最后请注意,如果缓冲区中只有"<enter>",scanf("%f"

最后一点:输入流由您的操作系统默认策略缓冲,因为在您键入“<enter>”之前应用程序不会接收任何字符。

于 2012-09-07T11:10:22.330 回答
1

通过以下方式使用 scanf 读取学生姓名:

scanf(" %[^\n]",studentlist[i].name);

格式说明符中的第一个空格很重要。它否定先前输入的换行符。顺便说一句,格式指示读取直到遇到换行符 (\n)。

[编辑:应要求添加解释]

接受字符串的格式说明符是%s. 但它只允许您输入非空白字符。另一种方法是在方括号内指定可接受的(或不可接受的,基于场景)的字符。

在方括号内,您可以指定单个字符、范围或这些字符的组合。要指定要排除的字符,请以插入符号 (^) 开头。

因此,%[a-z]这意味着 a 和 z 之间的任何字符(都包括在内)将被接受

在您的情况下,我们需要接受除换行符以外的每个字符。所以我们想出了说明符%[^\n]

您将从网上获得有关这些说明符的更多信息。为方便起见,这里有一个链接:http: //beej.us/guide/bgc/output/html/multipage/scanf.html

开头的空间实际上“消耗”了之前输入留下的任何前面的空白。您可以在此处参考答案以获取详细说明:scanf: "%[^\n]" 跳过第二个输入,但 " %[^\n]" 不跳过。为什么?

于 2012-09-07T11:09:25.840 回答
0

我只想对 scanf() 说不。对所有输入字段使用 fgets() 并使用 atoi() 和 atof() 转换为数字。

于 2012-09-07T11:24:18.420 回答