Reputation: 1
This is my code. I didnt want to use scanf()
to read the name and I tried using fgets()
but after I put the first name and age, the second and third time my program runs the for loop it doesnt take age .
#include <stdio.h>
#include <string.h>
struct student
{
char name[15];
int age;
};
int main()
{
int i;
struct student s[A];
for (i = 0 ; i < A ; i++)
{
printf("enter the names and age\n");
fgets(s[i].name, 10, stdin);
scanf("%d", &s[i].age);
}
printf("\n\n");
for (i = 0 ; i < A ; i++)
{
printf("%s\t%d\n", s[i].name, s[i].age);
}
return 0;
}
It doesnt work, why?
But when I replace fgets with
scanf("%s%d",s[i].name,&s[i].age);
It works fine
Upvotes: 0
Views: 1389
Reputation: 154228
The difference between fgets() and scanf()
fgets(...)
typically reads until receiving a '\n'
scanf("%d", ...)
typically:
1. Reads and discards leading white-space.
2. Reads numeric input (sign,digits) until scanning a non-digit.
3. Non-digit is put back into stdin
for the next input function.
Example:
JohnEnter
"John\n"
is read by fgets()
into s[0].name
.
21Enter
21
is read by scanf("%d",...)
into s[0].age
. '\n'
put back into stdin
"\n"
is read by fgets()
into s[1].name
.
M
"M"
is read by scanf("%d",...)
, nothing is put in s[1].age
. 'M'
put back into stdin
.
aryEnter
"Mary\n"
is read by fgets()
into s[2].name
.
19Enter
19
is read by scanf("%d",...)
into s[2].age
. '\n'
put back into stdin
"\n"
is read by fgets()
into s[3].name
.
Alternative: To read 2 lines, call fgets()
twice, then parse:
int Scan_student(struct student *dest) {
char buffer[2][80];
dest->name[0] = '\0';
dest->age[0] = -1;
printf("enter the names and age\n");
for (int i=0; i<2; i++) {
if (fgets(buffer[i], sizeof buffer[i], stdin) == NULL) {
return EOF; // stdin was closed, no more input (or input error)
}
buffer[i][strcspn(buffer[i], "\r\n")] = '\0'; // lop off potential trailing \n
}
// parse the 2 buffers: MANY options here - something simple for now.
if (sscanf(buffer[0], " %14[-'A-Za-z ]", dest->name) != 1) {
return 0;
}
if (sscanf(buffer[1], "%d", &dest->age) != 1) {
return 0;
}
return 1;
}
int i;
struct student st[3];
for (i = 0 ; i < sizeof(st) / sizeof(st[0]) ; i++) {
if (Scan_student(&st[i]) != 1) break;
}
Upvotes: 2
Reputation: 53026
If you input both the name and the age in a single line, then that's the normal behavior because fgets()
will read the whole line until 9
bytes (in your case) are read or a '\n'
is found.
You need one of the two, for instance you could only use fgets()
like this
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct student
{
char name[100];
int age;
};
int main()
{
int i;
struct student s[1];
for (i = 0 ; i < sizeof(s) / sizeof(*s) ; i++)
{
char number[100];
char *unconverted;
printf("Name > ");
fgets(s[i].name, sizeof(s[i].name), stdin);
if ((unconverted = strchr(s[i].name, '\n')) != NULL)
*unconverted = '\0'; // Remove the trailing '\n'
printf("Age > ");
fgets(number, sizeof(number), stdin);
s[i].age = strtol(number, &unconverted, 10);
if ((*unconverted != '\0') && (*unconverted != '\n'))
s[i].age = -1; // Invalid value indicating input error
}
for (i = 0 ; i < sizeof(s) / sizeof(*s) ; i++)
printf("Name: %s\nAge : %d\n", s[i].name, s[i].age);
return 0;
}
Or scanf()
only
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct student
{
char name[100];
int age;
};
int main()
{
int i;
struct student s[1];
for (i = 0 ; i < sizeof(s) / sizeof(*s) ; i++)
{
printf("Name Age > ");
if (scanf("%99s%d", s[i].name, &s[i].age) != 2)
{
fprintf(stderr, "input error\n");
s[i].name[0] = '\0';
s[i].age = -1;
}
}
for (i = 0 ; i < sizeof(s) / sizeof(*s) ; i++)
printf("Name: %s\nAge : %d\n", s[i].name, s[i].age);
return 0;
}
and you can then input both name and age in a single line.
The fgets()
method is better because you don't need to deal with the '\n'
that scanf()
doesn't pick up from stdin
. A combination would work if you are careful to force the user to input the values in separate lines.
Upvotes: 1
Reputation: 19
To be honest fgets() isn't required here as you've specified to read from stdin you should simply use gets() this reads from stdin by default. If your moving between a scanf() statement and a gets() statement you should use fflush(stdin) to clear out the input stream, example below:
scanf("%99s", s[i].name);
fflush(stdin);
gets(s[i].age);
In general your better sticking with either scanf() or gets() and not combining them.
Upvotes: -1