So I'm stuck on this one. When I put an fgets after scanf, the fgets couldn't store space inputs. A quick googling taught me that This happens because every scanf() leaves a newline character in a buffer that is read by the next scanf.
and putting a space or newline at the end of the control string fixes it... Yep it did but the problem I am facing is that if there's a printf between scanf and fgets, the fgets work before the printf.
So, I need an explanation for this behavior any solutions/workarounds if any.
Compiler/Platform used: gcc 11/Linux
Here is the code (LOOK AT LINE 24-27 for example)
/*Write a program to create a structure of employees containing the following data members: Employee ID, Name, Age, Address, Department and Salary.
Input data for 10 employees and display the details of the employee from the employee ID given by the user.*/
#include <stdio.h>
#include <string.h>
int main()
{
int i=0;
typedef struct employee
{
long int id;
char name[30];
int age;
char address[100];
char dept[30];
long int salary;
}emp;
emp list[5];
for (i = 0; i<10;i )
{
printf("Enter id of employee %d : ", i 1);
scanf("%ld ", &(list[i].id));
printf("Enter name of employee %d : ", i 1);
fgets(list[i].name, 30, stdin);
printf("Enter age of employee %d : ", i 1);
scanf("%d ", &(list[i].age));
printf("Enter address of employee %d : ", i 1);
fgets(list[i].address, 100, stdin);
printf("Enter dept of employee %d : ", i 1);
fgets(list[i].dept, 30, stdin);
printf("Enter salary of employee %d : ", i 1);
scanf("%ld ", &list[i].salary);
}
long int emp_id;
int flag=0;
printf("Enter employee id to be searched: ");
scanf("%ld", &emp_id);
// Linear search
for (i=0; i<10; i )
{
if (list[i].id==emp_id)
{
printf("Employee found!!");
flag=1;
printf("Id : %ld \n", list[i].id);
printf("Name : %s \n", list[i].name);
printf("Age : %d\n", list[i].age);
printf("Address : %s \n", list[i].address);
printf("Dept : %s \n", list[i].dept);
printf("Salary : %ld \n", list[i].salary);
}
}
if (flag==0)
{
printf("Employee not found!!");
}
}
Output
CodePudding user response:
Yep it did but the problem I am facing is that if there's a printf between scanf and fgets, the fgets work before the printf.
That description is not accurate.
The problem is the following line:
scanf("%ld ", &(list[i].id));
This line will first read a number and then continue reading and discarding whitespace characters until a non-whitespace character is encountered. Since you are probably using a terminal that is line-based, this means that it will have to enter at least a whole line of extra input, before the function scanf
returns.
Therefore, I recommend that you remove the space character from the format string, and that you use a different method of discarding the leftovers of the line after the scanf
function call. You could simply call getchar
to consume the newline character, and then discard it. However, this will only work if the next character actually is the newline character. A more robust method of discarding the leftovers of a scanf
function call would be the following loop:
int c;
do
{
c = getchar();
} while ( c != EOF && c != '\n' );
This loop will continue discarding characters until it encounters the newline character, or if end-of-file or an error occurs.
After fixing your program, it should look like this:
#include <stdio.h>
#include <string.h>
void discard_remainder_of_line( void )
{
int c;
do
{
c = getchar();
} while ( c != EOF && c != '\n' );
}
int main()
{
int i=0;
typedef struct employee
{
long int id;
char name[30];
int age;
char address[100];
char dept[30];
long int salary;
}emp;
emp list[5];
for (i = 0; i<10;i )
{
printf("Enter id of employee %d : ", i 1);
scanf("%ld", &(list[i].id));
discard_remainder_of_line();
printf("Enter name of employee %d : ", i 1);
fgets(list[i].name, 30, stdin);
printf("Enter age of employee %d : ", i 1);
scanf("%d", &(list[i].age));
discard_remainder_of_line();
printf("Enter address of employee %d : ", i 1);
fgets(list[i].address, 100, stdin);
printf("Enter dept of employee %d : ", i 1);
fgets(list[i].dept, 30, stdin);
printf("Enter salary of employee %d : ", i 1);
scanf("%ld", &list[i].salary);
discard_remainder_of_line();
}
long int emp_id;
int flag=0;
printf("Enter employee id to be searched: ");
scanf("%ld", &emp_id);
discard_remainder_of_line();
// Linear search
for (i=0; i<10; i )
{
if (list[i].id==emp_id)
{
printf("Employee found!!");
flag=1;
printf("Id : %ld \n", list[i].id);
printf("Name : %s \n", list[i].name);
printf("Age : %d\n", list[i].age);
printf("Address : %s \n", list[i].address);
printf("Dept : %s \n", list[i].dept);
printf("Salary : %ld \n", list[i].salary);
}
}
if (flag==0)
{
printf("Employee not found!!");
}
}
As you can see, at least the first part of your program appears to work now:
Enter id of employee 1 : 264
Enter name of employee 1 : John Doe
Enter age of employee 1 : 22
Enter address of employee 1 : 43 Third Street
Enter dept of employee 1 : Computer Science
Enter salary of employee 1 : 5000
Enter id of employee 2 : Jane Doe
Enter name of employee 2 : 21
Enter age of employee 2 :
CodePudding user response:
Your problem is that the convention you use with the space at the end of the scanf
format string does not really consume the \n
. As a result fgets
consumes it and skips the string input. It really has nothing to do with the printf
.
The way to solve this is to explicitly consume the newline like so: scanf("%ld%*c", &i)
. The *
is a suppressing character which tells scanf
to consume the input but not try to assign it to a variable and the c
conversion specifier asks to read any character. So we ask scanf
to read one char
after the long int
but not assign it to a variable. If this char
happens to be a newline everything will be OK (But if not - trouble again). Please read the documentation at scanf, fscanf, sscanf, scanf_s, fscanf_s, sscanf_s.
I would also recommend you add a call to fflush(stdout);
after every printf
because your are not using a newline to terminate your prints.
As a final note. It is probably best that you read all your input using fgets
which will properly handle any input terminated by a newline (also on systems where the newline is not just one character). Once you read the input as a string you can use sscanf or other functions to correctly parse it.