cscanfstdinrewind

How does scanf know if it should scan a new value?


I'm studying about how scanf works.

After scanned other type variable, char variable stores a white-space('\n') by getchar() or scanf("%c"). To prevent this, they should clear buffer. And I did it with rewind(stdin)

though stdin is rewinded previous input value is keeping in buffer. and I can do something with the previous value normally.(nothing runtime errors) but if I try scanf again, scanf will scan a new value even there is a normal value in buffer. how does scanf determine if it should scan a new value?

I found this mechanism with below code.

#include <stdio.h>
#define p stdin

int main() {
    int x;
    char ch;

    void* A, * B, * C, * D, * E;

    A = p->_Placeholder;
    printf("A : %p\n", A);//first time, it shows 0000
    scanf_s("%d", &x);

    B = p->_Placeholder;
    printf("B : %p\n", B);//after scanned something, I think it's begin point of buffer which is assigned for this process
    rewind(stdin);//rewind _Placeholder 

    C = p->_Placeholder;
    printf("C : %p\n", C);//it outputs the same value as B - length of x

    D = p->_Placeholder;
    printf("D : %c\n", ((char*)D)[0]);//the previous input value is printed successfully without runtime error. it means buffer is not be cleared by scanf
    scanf_s("%c", &ch, 1);//BUT scanf knows the _Placeholder is not pointing new input value, so it will scan a new value from console. How??

    E = p->_Placeholder;
    printf("E : %p\n", E);
    printf("ch : %c\n", ch);
}

Solution

  • There are some problems with you approach:

    scanf() is quite tricky to use: even experienced C programmers get bitten by its many quirks and pitfalls. In your code, you test %d and %c, which behave very differently:

    Processing %c after %d is tricky if the input stream is bound to a terminal as the user will enter a newline after the number expected for %d and this newline will be read immediately for the %c. The program can ignore white space before the byte expected for %c by inserting a space before %c in the format string: res = scanf(" %c", &ch);

    To better understand the behavior of scanf(), you should output the return value of each call and the stream current position, obtained via ftell(). It is also more reliable to first set the stream to binary mode for the return value of ftell() to be exactly the number of bytes from the beginning of the file.

    Here is a modified version:

    #include <stdio.h>
    
    #ifdef _MSC_VER
    #include <fcntl.h>
    #include <io.h>
    #endif
    
    int main() {
        int x, res;
        char ch;
        long A, B, C, D;
    
    #ifdef _MSC_VER
        _setmode(_fileno(stdin), _O_BINARY);
    #endif
    
        A = ftell(stdin);
        printf("A : %ld\n", A);
    
        x = 0;
        res = scanf_s("%d", &x);
    
        B = ftell(stdin);
        printf("B : %ld, res=%d, x=%d\n", B, res, x);
    
        rewind(stdin);
        C = ftell(stdin);
        printf("C : %ld\n", C);
    
        ch = 0;
        res = scanf_s("%c", &ch, 1);
        D = ftell(stdin);
        printf("D : %ld, res=%d, ch=%d (%c)\n", D, res, ch, ch);
    
        return 0;
    }