-1

When I take user’s name as input and use that information to do another task, the output does not contains first character of the first student name.

int main() {
    // Task1 - Enter student number
    int i, number;
    printf("Enter the number of students: ");
    scanf("%d", &number);
    getchar();
    while (number > 1000) {
        printf("Your number is too high. Maximum number of student is 1000. Please enter again: ");
        scanf("%d", &number);
    }
    //Task2 - get student info
    struct studentInfo students[number];
   
    for (i = 0; i < number; i++) {
        printf("\nEnter data for student %d:\n", i + 1);
        printf("Enter student %d name: ", i + 1);
        getchar(); // consume the newline character left in the input stream
        fgets(students[i].fullName, sizeof(students[i].fullName), stdin); //use fgets instead of scanf
        students[i].fullName[strcspn(students[i].fullName, "\n")] = 0; // Remove trailing newline
 
        printf("Enter student %d ID: ", i + 1);
        scanf("%s", students[i].ID);
       
        printf("Enter student %d birthdate: ", i + 1);
        scanf("%s", students[i].birthDate);
    }
}

I have changed fgets to gets and add getchar but it’s still not working

4
  • Questions seeking debugging help should generally provide a minimal reproducible example of the problem, which includes all #include directives the exact input required to reproduce the problem, and, in this case, also includes the definition of struct studentInfo. This allows other people to easily test your program, by simply using copy&paste. Commented Apr 30, 2023 at 16:13
  • In your question, you wrote: "the output does not contains first character of the first student name" -- What output? Your posted code does not contain any attempt of printing the first student's name. Please provide a minimal reproducible example of the problem and specify exactly the input, desired output and actual output. Commented Apr 30, 2023 at 16:30
  • @AndreasWenzel: I found enough information was present to answer. So I answered as I may, in a form that even a novice programmer can apply; though the instructor may ask about sscanf(). Commented Apr 30, 2023 at 19:05
  • @Joshua: Yes, I agree that the question is already answerable (I actually answered it myself, too) if you fill all the gaps with speculation. For example, in order to answer, it is necessary to speculate that students[i].fullName is an array and not a pointer and that is has a sufficient size to accomodate the input. It is also necessary to speculate that all necessary #include directives are being used, so that the compiler is not using any implicit declarations (which may cause the compiler to make false assumptions on the parameter types or the return values). Commented Apr 30, 2023 at 21:11

2 Answers 2

2

The problem is after scanf("%d", ...), a newline is left in the input stream. Use of scanf() for keyboard input is a bad idea. Consider using fgets() and sscanf() instead.

Example:

    printf("Enter the number of students: ");
    scanf("%d", &number);

would become:

    printf("Enter the number of students: ");
    fgets(keyboard_line, 80, stdin);
    sscanf(keyboard_line, "%d", &number);

Where you declare keyboard_line as char keyboard_line[80]; at the top of main();

Sign up to request clarification or add additional context in comments.

7 Comments

Do i have to delete the line getchar after that part and edit while (number > 1000)?
@DatTran: Yes. The best way is clearly to read all keyboard input line at a time with fgets().
Is there any error in my task 2? Please let me know, thank you.
In your answer, you wrote: "The problem is after scanf("%d", ...), a newline is left in the input stream." -- This statement is incorrect, because OP is successfully discarding that newline character by using getchar();. Therefore, that is not "the problem". The problem is rather that OP's code is calling getchar(); one time too many before fgets in the first iteration of the loop. See my answer for further information. However, your provided solution will still solve the problem.
@Joshua, Minor: Better as char keyboard_line[80]; ... fgets(keyboard_line, sizeof keyboard_line, stdin);
|
2

The problem is that the statement

scanf("%d", &number);

will leave the newline character on the input stream, whereas the statement

fgets(students[i].fullName, sizeof(students[i].fullName), stdin);

will read an entire line of input including the newline character (assuming that the supplied memory buffer is large enough to store the entire line).

You appear to be attempting to compensate for the fact that scanf leaves the newline character on the input stream by using the statement

getchar();

in several places in your code to read and discard the newline character. However, you are not doing this correctly.

If the user enters a number below 1000 for the statement

scanf("%d", &number);

then you will execute the statement

getchar();

twice afterwards, because that statement is in two places in your posted code. This means that it will probably read the newline character as well as the first character of the next line of input of the user.

This explains why in the first loop iteration, students[i].fullName is missing the first character.

In order to fix this, I suggest that you always have the statement

getchar();

either

  1. immediately after every scanf function call, or
  2. immediately before every fgets function call.

The problem in your posted code is that you are doing a mixture of both.

Note that solution #2 will only work if the first statement in the program is a scanf statement, because if the first statement is a fgets statement, then there will be no newline character to remove. For this reason, it would probably be better to use solution #1.

Also, using the statement

getchar();

will only work if scanf left over only a newline character. However, if the user for example enters

6abc

then the %d format specifier of scanf will only match 6, but will leave abc\n on the input stream. In that case, it would be necessary to call getchar() four times instead of only once.

For this reason, it is generally better to use the following loop instead:

int c;

do
{
    c = getchar();

} while ( c != EOF && c != '\n' );

This loop can be shortened to the following two lines:

for ( int c; ( c = getchar() ) != EOF && c != '\n' )
    ;

If you use this several times in your program, it may be easier to simply write your own function:

void discard_remainder_of_line()
{
    int c;

    do
    {
        c = getchar();

    } while ( c != EOF && c != '\n' );
}

That way, you only have to write

discard_remainder_of_line();

after every scanf statement.

It would also be safer to always check the return value of scanf before using the result of scanf.

1 Comment

Of course while ( c != EOF && c != '\n' ); and while ( c != '\n' && c != EOF); both function alike, yet since '\n' is more likely, testing that first is a tad quicker.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.