as told by @chux , scanf
leaves '\n' in the stdin
( memory buffer ) , and fgets()
takes value until there is a '\n' in the buffer , in order to clear the buffer the statement fflush(stdin);
is used before the fgets()
statement
unable to read a string inside a loop structure using fgets() function
Pregunta
I used fgets()
and gets()
also for getting a string as input inside a loop. In the first execution, it worked properly but in the second time, it skips the inputting step and straight away goes to the next line.
#include<stdio.h>
#include<conio.h>
struct student
{
int roll,m[3];
float avg;
char name[30];
}s[5];
void main()
{
int i;
clrscr();
printf("Enter thr student details:");
for(i=0;i<5;i++)
{
printf("\nstudent[%d] name:",i+1);
fgets(s[i].name,30,stdin);
printf("student[%d] register number: ",i+1);
scanf("%d",&s[i].roll);
printf("student[%d] marks:\n",i+1);
scanf("%d%d%d",&s[i].m[0],&s[i].m[1],&s[i].m[2]);
s[i].avg=(s[i].m[0]+s[i].m[1]+s[i].m[2])/3;
}
printf("-----------------------------------------------------------");
printf("\n NAME REG.NO AVERAGE");
printf("\n-----------------------------------------------------------");
printf("\n DISTINCTION");
for(i=0;i<5;i++)
if(s[i].avg>74)
printf("\n%-20s%-10d%.2f",s[i].name,s[i].roll,s[i].avg);
printf("\n FIRST CLASS");
for(i=0;i<5;i++)
if((s[i].avg<74)&&s[i].avg>50)
printf("\n%-20s%-10d%.2f",s[i].name,s[i].roll,s[i].avg);
printf("\n FAIL");
for(i=0;i<5;i++)
if(s[i].avg<50)
printf("\n%-20s%-10d%.2f",s[i].name,s[i].roll,s[i].avg);
getch();
}
Solución 3
Otros consejos
Enter thr student details:
student[1] name:abcd <Enter>
fgets
reads until the size limit is reached or EOF
is returned or a new line (\n
) character is encountered. In the above scenario, it reads abcd
and also reads \n
,and returns.
student[1] register number: 12<Enter>
student[1] marks:
12 13 14<Enter>
Now, you are using scanf
to read the numbers. scanf
with %d
returns until a number is encountered or EOF
is seen. It ignores all the new line characters.
After the above two steps you are left with an extra \n
in the input stream.(since scanf
doesn't actually read it).
Now when you have a next call for fgets
, there is already a \n
first. It returns there, without actually prompting for the next name.
Solution:
Put a getch()
, after reading the marks. This removes the leading \n
from the stream.
Or, read the name using scanf
itself.
scanf("%s", s[i].name);
scanf("%d%d%d")
leaves the Enter or '\n'
in stdin
. The following fgets()
then reads only "\n"
.
The best solution is to use the fgets()/sscanf()
combination. Robust code checks the return results.
{
char buf[100];
printf("\nstudent[%d] name:",i+1);
if (fgets(s[i].name, sizeof s[i].name, stdin) == NULL)
Handle_EOF();
printf("student[%d] register number: ", i+1);
if (fgets(buf, sizeof buf, stdin) == NULL)
Handle_EOF();
if (sscanf(buf, "%d", &s[i].roll) != 1)
Handle_InputError();
printf("student[%d] marks:\n",i+1);
if (fgets(buf, sizeof buf, stdin) == NULL)
Handle_EOF();
if (sscanf(buf, "%d%d%d", &s[i].m[0], &s[i].m[1], &s[i].m[2]) != 3)
Handle_InputError();
s[i].avg = (s[i].m[0] + s[i].m[1] + s[i].m[2])/3;
}