0

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!!
Jainendra
  • 24,713
  • 30
  • 122
  • 169
MohdAziz
  • 3
  • 2

4 Answers4

2

Try eating the newline after the last scanf:

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

This is very much like your getchar solution. It's actually superior to getchar, since it only discards whitespace.

cnicutar
  • 178,505
  • 25
  • 365
  • 392
  • I tried this, but It hasn't worked. After I plug in the last gpa and click enter it keeps giving me spaces down ( like when you press enter in msword). – MohdAziz Sep 07 '12 at 12:32
2

But you have to use getchar() to discard the newline character that is still in the input buffer after your last scanf("%f"), which according to given format converts a float and leave in the buffer all other chars.

If you can't use getchar(), use another fgets() at the end of the loop.. but of course getchar() would be better

Edit for explanation: whenever you type on your keyboard characters go in a input buffer waiting to be processed by your application. getchar() just "consumes" one character from this buffer (returning it), waiting for a valid char if the buffer is empty. scanf("%f") only "consumes" characters resulting in a float. So, when you type "5.12<enter>", scanf reads and removes from buffer "5.12" leaving "<enter>". So the next fgets() already finds a newline in the buffer and returns immediately; that's why you should use getchar(): ignoring its returning value you successfully discard "<enter>" from the buffer. Finally, please note that if in the buffer there is only "<enter>", scanf("%f") discards it (since it cannot be converted in a float) and waits for another input blocking application.

One last note: input stream is buffered by your OS default policy, in the sense that application does not receive any character until you type "<enter>".

Jack
  • 1,488
  • 11
  • 21
  • A scanf() with a space in the format string (see the other answers) would be even better yet, since it only discards white space characters, and at the same time any number of white space characters (for example CR+LF) and not just a single one. – Lundin Sep 07 '12 at 11:19
  • The thing I don't know exactly what does getchar() do, but after surfing the internet I have seen so many using it, so I tried it and it worked. Could you provide me with an informative explanation about the getchar() function and thanks a lot for your help. take care – MohdAziz Sep 07 '12 at 12:38
1

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?

Community
  • 1
  • 1
vaisakh
  • 1,041
  • 9
  • 19
  • I tried this and it has worked perfectly, but I don't know how you managed to come to this format specifier, a little bit of explanation would be great. Thanks a lot for your help – MohdAziz Sep 07 '12 at 12:26
  • Any time..:) I see still no answers being chosen. It would help everyone if one of the answers is selected as the correct one. if your question has been answered, that is.. – vaisakh Sep 08 '12 at 17:20
  • Is there a way to select a specific answer, or just by voting up? – MohdAziz Sep 12 '12 at 03:23
  • There should be a tick mark next to each..click on the one next to the answer you need to accept. You can see the faq for more info..Oh..and by the way, Welcome to Stackoverflow :) – vaisakh Sep 13 '12 at 06:50
0

I would just say no to scanf(). Use fgets() for all input fields and convert to numeric with atoi() and atof().

Scooter
  • 6,802
  • 8
  • 41
  • 64