Here is my code for a simple programme in C for storing details of students in a struct. The problem that I am having is that the fgets statement for taking in the name string doesn't get executed and directly prints my next printf statement The error line is marked. Also, the rest of the code works perfectly. Now I have tried the same code with changing 'fgets' to 'gets' and 'scanf'/'scanf_s' too, but I am having the same result.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct Students
{
char name[30];
int age;
int roll_number;
char address[30];
}std[3];
void names(struct Students std[], int n)
{
int i = 0;
printf("Here are the names of students whose age is 14");
while (i < n)
{
if (std[i].age == 14)
{
printf("%s", std[i].name);
}
i++;
}
}
void everoll(struct Students std[], int n)
{
int i = 0;
printf("Here are the names of students whose age is 14");
while (i < n)
{
if (std[i].roll_number % 2 == 0)
{
printf("%s", std[i].name);
}
i++;
}
}
void details(struct Students std[], int n, int a)
{
int i = 0;
while (i < n)
{
if (std[i].roll_number == a)
{
printf("Here are the details\n");
printf("The name is : %s\nThe address is : %s\nThe age is : %d", std[i].name, std[i].address, std[i].age);
}
i++;
}
}
int main()
{
printf("Enter the details of the students:\n\n");
for (int i = 0; i < 3; i++)
{
printf("Enter the roll number of the student:\n");
scanf_s("%d", &std[i].roll_number);
printf("Enter the age of the student:\n");
scanf_s("%d", &std[i].age);
printf("Enter the name of the student:\n");
fgets(std[i].name, 30, stdin); //error line
printf("Enter the address of the student:\n"); //This line gets executed dirctly
fgets(std[i].address, 30, stdin); //This fgets works fine
}
eve:
printf("Which operation do you want to perform \n1) finding students with age 14\n2) Printing names of students with even roll number\n3) Finding details by enetering the roll number\n");
int d;
scanf_s("%d", &d);
int b;
switch (d)
{
case 1:
names(std, 3);
break;
case 2:
everoll(std, 3);
break;
case 3:
printf("Enter the roll number:\n");
scanf_s("%d", &b);
details(std, 3, b);
break;
default:
printf("Wrong number entered");
goto eve;
}
return 0;
}
The function
scanforscanf_sdoes not generally consume a whole line of input, unless you explicitly instruct it to.For example, if the user enters the input
where
\nis the newline character that is generated when the user presses the ENTER key, then the function callwill match and consume only the character
5, but leave the newline character on the input stream.The function call
will then consume all leading whitespace characters, so it will consume the newline character on the first line, and then match and consume the
20from the second line. It will not consume the newline character on the second line.The function call
will now read everything on the input stream up to and including the next newline character. Since the next character is the newline character from the second line (which was left there by
scanf_s), that is all that this function call will read from the input stream, and it will write that character intostd[i].name. Therefore, this function call will not read anything from the third line.The function call
will now again read everything on the input stream up to and including the next newline character. Therefore, it will read the entire contents of line 3 of the input (which is
John Doe) intostd[i].address, including the newline character.So, to summarize, your program has the following issue:
The second call to
scanf_swill not consume the newline character, so that the first call tofgetswill only read the newline character from line 2, although you want it to read the entire line 3 instead. As a consequence, line 3 is read by the secondfgetsfunction call, although you intend it to be read by the firstfgetscall instead.Therefore, the simplest fix to your problem would be to consume the remainder of the line (including the newline character) after the second
scanf_sstatement, before the firstfgetsstatement.One way to accomplish this is to use the following loop:
A more compact way of writing this is:
You can also use
scanffor this purpose:However, instead of using
scanforscanf_sto read partial lines, it would be more intuitive and less error-prone to always read exactly one whole line of input. Therefore, I would recommend usingfgetsfor reading all 4 lines if input. You can then use the functionstrtolto convert a string into an integer: