2012-09-07 45 views
0

我正在写这个来获取学生信息(最后3个学期的全名,id和gpa,所以我使用了结构和一个for循环来插入信息,但是在第一次学习之后for循环(这意味着在学生2)我的第一个和第二个输入一起显示在屏幕上。我怎么能以简单易懂的方式来防止这种情况发生?(PS:我已经试图把getchar();放在for循环的结束,它的工作,但是,我不应该使用它,因为我们还没有在课堂上所学到)C编程数据输入错误

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!! 
+1

请修改您的文章适当的缩影。它似乎在复制/粘贴期间消失了。 – Lundin

+0

为什么不像所有其他输入一样,对_name_字段使用'scanf'? – Vishal

回答

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]" skips the 2nd input but " %[^\n]" does not. why?

+0

我试过这个,它的工作很完美,但是我不知道你是如何得到这个格式说明符的,一点解释就会很棒。非常感谢您的帮助 – MohdAziz

+0

我已经添加了解释 – vaisakh

+0

哦,这太棒了,非常感谢您的帮助。 – MohdAziz

2

尝试最后scanf吃完后换行:

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

这是非常非常喜欢你的getchar解决方案。它实际上优于getchar,因为它只丢弃空格。在下面的方法读取学生姓名

+0

我试过这个,但它没有奏效。在插入最后一个GPA并点击输入后,它会一直给我空间(例如,当你按下msword时输入)。 – MohdAziz

2

但你必须使用getchar()你最后scanf("%f")后丢弃换行符仍处于输入缓冲器,它根据给定的格式转换的浮动和离开缓冲所有其他字符。

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

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

最后一个注意事项:输入流被您的操作系统默认策略缓冲,从应用程序直到您输入“<输入>”才会收​​到任何字符。

+0

scanf()在格式字符串中的空格(请参阅其他答案)会更好然而,因为它只丢弃空白字符,并且同时丢弃任何数量的空白字符(例如CR + LF)而不是单个空白字符。 – Lundin

+0

我不确切知道getchar()做了什么,但是在浏览互联网之后,我看到了很多使用它的地方,所以我尝试了它,并且它工作正常。你能否给我提供一个关于getchar()函数的信息性解释,并且非常感谢你的帮助。保重 – MohdAziz

0

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