0

私は学生の情報を取得するためにこれを書いています (最後の 3 学期の氏名、ID、および GPA です。そのため、構造体と for ループを使用して情報をプラグインしましたが、for ループの最初の実行後 (つまり、学生 2 で) ) 私の 1 番目と 2 番目の入力が一緒に画面に表示されます. どうすればこれが起こらないようにシンプルでわかりやすい方法で防ぐことができますか? ( PS: for ループの最後に getchar(); を入れようとしましたが、うまくいきましたただし、授業で習っていないので使うべきではありません)

私のエラーが発生する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

ただしgetchar()、最後の の後にまだ入力バッファーにある改行文字を破棄するために使用する必要がありますscanf("%f")。これは、指定された形式に従ってフロートを変換し、他のすべての文字をバッファーに残します。

を使用できない場合は、ループの最後でgetchar()別のものを使用fgets()してください..もちろん、getchar()より良いでしょう

説明のために編集: キーボードで文字を入力するたびに、アプリケーションによって処理されるのを待っている入力バッファーに入ります。getchar() は、このバッファーから 1 文字を「消費」し (それを返します)、バッファーが空の場合は有効な char を待ちます。scanf("%f") は文字のみを「消費」し、浮動小数点になります。したがって、「5.12<enter>」と入力すると、scanf はバッファ「5.12」を読み取って削除し、「<enter>」を残します。したがって、次の fgets() は既にバッファ内で改行を見つけており、すぐに戻ります。そのため、getchar() を使用する必要があります。その戻り値を無視して、バッファから "<enter>" を正常に破棄します。最後に、バッファに "<enter>" しかない場合は、scanf("%f"

最後に 1 つ: 入力ストリームは OS のデフォルト ポリシーによってバッファリングされます。これは、「<enter>」と入力するまでアプリケーションが文字を受信しないという意味です。

于 2012-09-07T11:10:22.330 に答える
2

最後の の後に改行を食べてみてくださいscanf:

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

これはあなたのソリューションに非常に似ていますgetchargetchar空白のみを破棄するため、実際にはより優れています。

于 2012-09-07T11:08:24.873 に答える
1

次の方法で scanf を使用して、学生の名前を読み取ります。

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

フォーマット指定子の最初のスペースは重要です。前の入力からの改行を否定します。ちなみに、フォーマットは、改行 (\n) に遭遇するまで読み取るように指示します。

[編集: リクエストに応じて説明を追加]

文字列を受け入れるための書式指定子は%s. ただし、空白以外の文字のみを入力できます。もう 1 つの方法は、許容される (またはシナリオに基づいて許容されない) 文字を角括弧内に指定することです。

角かっこ内では、個々の文字、範囲、またはこれらの組み合わせを指定できます。除外する文字を指定するには、先頭にキャレット (^) 記号を付けます。

したがって、%[a-z]a と z の間の任意の文字 (両方を含む) が受け入れられることを意味します。

あなたの場合、改行以外のすべての文字を受け入れる必要があります。したがって、指定子を考え出します%[^\n]

これらの指定子の詳細については、Web から入手できます。便宜上、1 つのリンクを次に示します: http://beej.us/guide/bgc/output/html/multipage/scanf.html

先頭のスペースは、前の入力から残った前の空白を実際に「消費」します。詳細な説明については、こちらの回答を参照してください: scanf: "%[^\n]" は 2 番目の入力をスキップしますが、" %[^\n]" はスキップしません。なぜ?

于 2012-09-07T11:09:25.840 に答える
0

scanf() にはノーと言います。すべての入力フィールドに fgets() を使用し、atoi() および atof() で数値に変換します。

于 2012-09-07T11:24:18.420 に答える