Search code examples
cfor-loopstructfgetsgets

C Programming data input error


I'm writing this to get student information (full name, id and gpa for the last 3 trimester, so I used structures and a for loop to plug in the information however, after 1st excution of the for loop (which means at student 2) my 1st and 2nd input are shown on screen together. How could I prevent this from happening in a simple and easy way to understand? ( P.S: I already tried to put getchar(); at the end of the for loop and it worked, however; I'm not supposed to use it 'cause we haven't learnt in class)

The part of the c program where my error happens:

 #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;
}

Computer output:

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

Solution

  • Use scanf in following way to read the student name:

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

    The first space in the format specifier is important. It negates the newline from previous input. The format, by the way, instructs to read until a newline (\n) is encountered.

    [Edit: Adding explanation on request]

    The format specifier for accepting a string is %s. But it allows you to enter non-whitespace characters only. The alternative way is to specify the characters that are acceptable (or not acceptable, based on the scenario) within square brackets.

    Within square brackets, you can specify individual characters, or ranges, or combination of these. To specify characters to be excluded, precede with a caret (^) symbol.

    So, %[a-z] would mean any character between a and z (both included) will be accepted

    In your case, we need every character other than the newline to be accepted. So we come up with the specifier %[^\n]

    You will get more info on these specifiers from the web. Here's one link for convenience: http://beej.us/guide/bgc/output/html/multipage/scanf.html

    The space in the beginning actually 'consumes' any preceding white space left over from previous input. You can refer the answer here for a detailed explanation: scanf: "%[^\n]" skips the 2nd input but " %[^\n]" does not. why?