The below code runs perfectly with scanf()
, but i want to input characters along with white space. I have tried gets()
and fgets()
(commented below), but its not working (its skipping to next iteration in the loop & displaying blank(NULL) during output for Name input used by fgets()
). Any idea how to do it?
PS: I've tried fputs()
with sample programs, its working fine. But i am little confused while using structure pointer.
#include <stdio.h>
#include <stdlib.h>
struct details {
uint Id;
char Name[20];
};
int main() {
int tot, i;
struct details *info;
printf("Enter no. of details to be stored = ");
scanf("%d", &tot);
info = (struct details *)malloc(tot*sizeof(struct details));
for(i=0; i<tot; i++) {
printf("%d)Id = ", i+1);
scanf("%d", &info->Id);
printf("%d)Name = ", i+1);
fgets(info->Name, 20, stdin); //How to make fgets() work??
//scanf("%s", &info->Name); //works fine with scanf()
info++;
}
for(i=0; i<tot; i++) {
--info;
}
printf("\nDisplaying details:\n");
for(i=0; i<tot; i++) {
printf("%d)Id = %d\n%d)Name = %s\n", i+1, info->Id, i+1, info->Name);
info++;
}
return 0;
}
output:
[xyz@xyz:Temp] $ ./fgets_Struct
Enter no. of details to be stored = 2
1)Id = 111
1)Name = 2)Id = 222
2)Name =
Displaying details:
1)Id = 111
1)Name =
2)Id = 222
2)Name =
[xyz@xyz:Temp] $
The problem comes from the "%d" scanf. It does not consume the line terminator, so the next read will interpret it as an empty line.
Your info
allocation is wrong too. What you should use to allocate the size is not the size of info
, but the size of an element pointed to by info
.
printf("Enter no. of details to be stored = ");
scanf("%d\n", &tot); // <-- must consume end of line here
info = (struct details *)malloc(tot*
sizeof(*info)); // <-- use size of the pointed object, not the pointer
Also, tinkering with your info
pointer is unnecessary and dangerous.
Something like that would be simpler and safer
for(i=0; i<tot; i++) {
printf("%d)Id = ", i+1);
scanf("%d\n", &info[i].Id)); // <-- store input in current info record
// and eat up the line terminator
printf("%d)Name = ", i+1);
fgets(info[i].Name, // <-- idem
sizeof(info[i].Name), // fgets will guarantee no buffer overflow
stdin);
}
printf("\nDisplaying details:\n");
for(i=0; i<tot; i++) {
printf("%d)Id = %d\n%d)Name = %s\n", i+1, info[i].Id, i+1, info[i].Name);
As for scanf / fgets, in your case (with "%s" format given to scanf), they should both read the input until a new line is entered, spaces included.
EDIT: I said something wrong here, sorry and thanks to chux for correcting me.
scanf ("%s")
will indeed stop at the first white space. If you want the whole line, the easiest way is to use fgets. If you really want to use scanf, you'll need a syntax like "%[^\n]%*c"
.
To make sure your buffer does not overflow if the user types more than 20 characters, you can either
- use
"%19[^\n]%*c"
as scanf
format (20th character is needed for the '\0' terminator), or
- use
fgets
with 20 passed as buffer size (fgets
takes care of the terminator, it will read at most 19 characters to be able to add the '\0' without overflowing).
Of course you should use sizeof
to compute max buffer size, like for instance:
fgets(info[i].Name, sizeof(info[i].Name), stdin);
Thus you won't have to modify the value if you decide, for instance, to have your buffer size changed to 50 characters.
First, you have a serious bug in your code.
info = (struct details *)malloc(tot*sizeof(info));
sizeof(info)
returns either 4 or 8 (depending on the platform, 32 or 64 bit), but has nothing to do with your struct size. So you are allocating memory for pointers, but are using that space for your struct. Writing your data into this will overwrite other data in memory (although probably not in that simple example), because you allocate way too few bytes. What you want to use is sizeof(struct details)
which would return 24.
Now to your input problem. Basically, scanf and gets should not be used together like that. The problem is that scanf reads what you type until you press return, which is not included. When you call gets after that, it sees this return and returns immediately with an empty string. If you change all your input calls to gets, it works perfectly. Example:
char test[256];
printf("Enter no. of details to be stored = ");
gets(test);
tot = atoi(test);
between the line scanf()
for ID and fgets()
put the line getchar()
like this
scanf("%d",&(info->Id));
getchar();
I had the same problem! Actually, I came to this page to get the solution and then I remembered the buffer!! So this is the way I solved it:
[...]
cout << "\nType the name: " ;
fflush(stdin); (you always have to clean the buffer before saving chars to a variable)
gets(pers.nom);
[...]
Cheers!!
P.S. cin and cout are from C++ but work like scanf and printf