Reputation: 159
When the for loop is run for the first time the program waits for the users input. But after the first time the two scanf lines seems to be skipped.
I've commented out the misc code:
#include <stdio.h>
int n = 0;
struct student {
int age;
char name[20];
};
void enterStudents() {
printf("How many students do you want to enter? \n");
scanf("%d", &n);
struct student list[n];
for(int i=0; i<n; i++){
printf("Enter student number %d's age: ", i+1);
scanf("%d", &list[i].age);
printf("Enter student number %d's name: ", i+1);
scanf(" %c", list[i].name);
}
listSort(list);
}
/**int listSort(struct student list[n]) {
char tempName[20];
int tempAge;
for(int i=0; i<n-1; i++){
if(list[n].age < list[n+1].age) {
tempAge = list[n].age;
strcpy(tempName, list[n].name);
list[n].age = list[n+1].age;
strcpy(list[n].name, list[n+1].name);
list[n+1].age = tempAge;
strcpy(list[n+1].name, tempName);
}
}
}**/
int main() {
enterStudents();
}
Upvotes: 1
Views: 727
Reputation: 11
Whenever you take input from user where input has sequence as first is any other data type and then character or character array as in your case sequence is integer and then character. First you enter the age of student like 21 now when u press 'enter key' this 'enter' is taken as the input for next character input. Then your input will look like this:
age=21
name='enter' (enter key that you pressed)
Now we can use a function that is fflush(stdin), this will flush out that enter key and allow you to enter name. this code will work:
void enterStudents()
{
printf("How many students do you want to enter? \n");
scanf("%d", &n);
struct student list[n];
for(int i=0; i<n; i++){
printf("Enter student number %d's age: ", i+1);
scanf("%d", &list[i].age);
//enter this line after your first input
fflush(stdin);
printf("Enter student number %d's name: ", i+1);
scanf(" %s", list[i].name);
}
listSort(list);
}
Upvotes: 0
Reputation: 13590
One problem that beginners often overlook with scanf
is that if the conversion
fails or the the conversion converts less characters than the user entered (for
example using %c
instead of %s
), then scanf
leaves the not-converted
characters in the input buffer. A subsequent call of scanf
will first try to
convert those characters that are in the input buffer, before it reads again
from the user.
In your case you used %c
but the user enters something that is longer than a
single character. Only 1 character was used in the conversion the rest was left
in the input buffer. In the next for
iteration scanf("%d")
tries to convert
the characters that were left in the input buffer and because the user enter non-digits for the name, scanf
fails and the next scanf
reads only the first characters and
left the rest behind, etc. That's why it appears that scanf
skips the calls.
You should check the return value of scanf
, it returns the number of
successful conversion it made. This is great information, if you get less
conversions than expected, then you know the scanf
call failed and you can
react to that. Also you may also clean the buffer if you are reading strings,
newlines and word after an empty space are left in the buffer and that can cause
some trouble with subsequent calls of scanf
. You can use a function like this:
void clean_stdin(void)
{
int c;
while((c = getchar()) != '\n' && c != EOF);
}
So your function should look like this:
int enterStudents() {
printf("How many students do you want to enter? \n");
if(scanf("%d", &n) != 1)
{
fprintf(stderr, "Could not read from the user\n");
return -1; // failure
}
if(n <= 0)
{
fprintf(stderr, "invalid number of students\n");
return -1;
}
struct student list[n];
for(int i=0; i<n; i++){
printf("Enter student number %d's age: ", i+1);
if(scanf("%d", &list[i].age) != 1)
{
fprintf(stderr, "could not read age from the user\n");
return -1;
}
printf("Enter student number %d's name: ", i+1);
if(scanf("%19s", list[i].name) != 1)
{
fprintf(stderr, "could not read name from the user\n");
return -1;
}
// cleaning stdin
clean_stdin();
}
...
return n; // sucess
}
Note that I've changed the function so that it returns -1 on failure and the number of students read on success, so the caller can know that something went wrong and get the number of students at the same time. In general, in order to make your code more robust, you should never trust the user and you should double check user input. You have to check that the user didn't enter a negative number for the student count. The "correct" mind set is "the user is trying to break your code by entering incorrect data and I have to deal with that". I know, the code become slightly more larger, but it is more robust and if something fails, you can narrow down more quickly (based on the error messages) where something went wrong. In your code, when something fails, you have really no idea where it could have happened.
Also note that in the name scan I used scanf("%19s", ..)
instead of %s
. The
reason is that using %s
you might overflow the buffer if the name is longer
than the buffer can hold. If the name is longer than 19 characters, it will
overflow the buffer. With "%19s"
you are limiting how many characters should
be read, in this case scanf
will convert at most 19 characters and ignore the
rest. Why 19 and not 20? You have to use 19, because strings in C are
'\0'
-terminated, so the last space in the array should be used for the
'\0'
-terminating bytes, hence 19.
Upvotes: 1