Hi all!

I was experimenting a little with scanf. I am posting the code and the outputs I am having prolems understanding:

#include <stdio.h>

int main()
{
   char a,b,c;
   int d,e;

   scanf("%c%c",&a,&b);//-------------------(1)
   printf("%c     %c\n\n",a,b);

   scanf("%d%d",&d,&e);//-------------------(2)
   printf("%d     %d\n\n",d,e);

   scanf("%c abc",&a);//--------------------(3)
   printf("%c\n\n",a);

   scanf("%c abcdefgh",&a);//---------------(4)
   printf("%c\n\n",a);

   getch();    

return 0;    
}

In (1):
Doesnt work. Scanf only takes one input. For (2), the same thing works. Why is it that it works for integers but not characters?

In (3):
Lets say I input 'm'. The subsequent printf prints nothing. After that, for scanf in (4) if I input 'k', then the subsequent printf prints 'm'. Why is that?

Thanks !

Recommended Answers

All 9 Replies

The C function scanf() is notoriously unsafe and you have discovered this.

In line(1) you are supposed to enter 2 characters.
If you enter accidentally 3 characters, the input will flow into the next scanf().
To avoid that flush the input stream.

In line(2) you should enter 2 integers separated by whitespace.

The lines(3) and line(4) make no sense to me.

for scanning the characters, you better use "space" between the %c's in (1).
as this:

scanf("%c %c",&a,&b);

for line (2), (3), (4)... i agree with lardmeister..

In C, you must know what you are doing. You have already decleared variable a, b and c as a single char and you wonder why, your printf only print a single character from the keyboard using scanf()?.
If you want more than a single character then you can do:

char a[20],b[20];

later you can do:

scanf("%s %s",a,b);  // get input
fflush(stdin) // OR fpurge(stdin) on unix-like OS

For (3) and (4):
You will need to understand that scanf() is used to get input from stdin. It's first parameter is what you can call a template to format the input. While the second the what you are really getting from stdin.
Check this page: http://www.cplusplus.com/reference/clibrary/cstdio/scanf/

In C, you must know what you are doing.

Yes indeed.

fflush(stdin) // OR fpurge(stdin) on unix-like OS

Oh, the irony. fflush() is specifically designed for output streams, and if you know what you're doing then you've probably heard that the C standard says calling fflush() on an input stream invokes undefined behavior. If you know what you're doing, you avoid undefined behavior like you avoid that guy walking down the street yelling to himself.

Thanks guys! This answers some of my questions. ((1) and (2)).
But I must tell you these are somewhat silly experiments and have no "sense" to them. Mainly to prepare me for C/C++ quizzes which give you a program and you have to tell what the output (if any) will be or if an error is present.

If format strings are not supposed to be like "%c abc", then why doesnt scanf terminate and return 0 when it encounters this type of format string? If it is not exiting in error, it means that its supposed to do something, right?
I came to know that when you do something like scanf("abc%c",&a), "abc%c" is a valid and meaningful format string string. Here, scanf matches first 3 characters (a,b,c) and if all of them match it takes the 4th characters and puts it in variable a (otherwise terminates with return 0). I simply wanted to know what happens when you put the abc after %c.

If format strings are not supposed to be like "%c abc", then why doesnt scanf terminate and return 0 when it encounters this type of format string?

You can have format strings like that, and they're occasionally useful. But it's important to understand the purpose of a literal match and how scanf() will behave.

I simply wanted to know what happens when you put the abc after %c.

%c is a placeholder for any character and it will be stored in the corresponding variable. "abc" will be matched literally and if it's not matched then scanf() will stop reading at that point. You'll only notice the effect if trying to extract more placeholders or by looking at the contents of the stream after scanf() returns. For example:

#include <stdio.h>

int main(void)
{
    char ch;
    int rc;

    rc = scanf("%cabc", &ch);
    printf("scanf() returned %d\n", rc);
    printf("scanf() extracted '%c'\n", ch);
    printf("Next character: '%c'\n", getchar());

    return 0;
}

If you type "gabcxyz" the output will be:

scanf() returned 1
scanf() extracted 'g'
Next character: 'x'

If you type "gxyz" the output will be:

scanf() returned 1
scanf() extracted 'g'
Next character: 'x'

These two tests show that the "abc" part was matched and tossed away, and also that if the literal match fails, nothing is extracted. Now you can test another placeholder:

#include <stdio.h>

int main(void)
{
    char ch;
    int x, rc;

    rc = scanf("%cabc%d", &ch, &x);
    printf("scanf() returned %d\n", rc);

    if (rc > 0)
    {
        printf("scanf() extracted '%c'\n", ch);
    }

    if (rc > 1)
    {
        printf("scanf() extracted '%d'\n", x);
    }

    printf("Next character: '%c'\n", getchar());

    return 0;
}

If you type "gabc123z" the output will be:

scanf() returned 2
scanf() extracted 'g'
scanf() extracted '123'
Next character: 'z'

If you type "g123z" the output will be:

scanf() returned 1
scanf() extracted 'g'
Next character: '1'

Notice how scanf() stopped when the literal match failed. Other inputs to try would be "gab123z" and "ga123z" to see that scanf() will stop reading at the first failed character.

Thank you very much deceptikon !!
That was a very detailed and thorough explanation. Got all the answers I wanted, and more!

Also, if fflush(stdin) is not the best way to flush input stream, what is?

if fflush(stdin) is not the best way to flush input stream, what is?

The best way to flush the stream is to not need to flush it in the first place. ;) Most of the time you'll get recommendations to read a line in full using fgets() or some variation, then parse that line in memory using sscanf(). This is the single best way to keep the stream clear.

However, it would be foolish to suggest that you'll never need to clear the stream, in which case a decent facsimile of fflush(stdin) that's conformant to the C standard is as follows:

void clear_line(FILE* in)
{
    int ch;

    clearerr(in); /* Required as of C99 */

    do
    {
        ch = getc(in);
    }
    while (ch != '\n' && ch != EOF);

    if (!feof(in))
    {
        /* Only clear non-EOF errors for the caller */
        clearerr(in);
    }
}

The only problem with this is that it doesn't account for an empty stream. If you call clear_line(stdin) and the stream is empty, it will block for input and then ignore the input, so it's not exactly like fflush(stdin). Unfortunately, there's no standard way to simulate fflush(stdin) completely.

Finally, the problems with fflush(stdin) are very real, but if you're using a compiler that supports it and if you don't plan on moving to a compiler that doesn't, any complaints about it are strictly on principle. The only reason I mentioned it as a problem at all is the majority of people who advocate the use of fflush(stdin) don't realize that it's technically undefined by the C standard.

Thank you very much !! :D
It's always exciting to know something you know most people don't know. :P :D

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.