Reading newline from previous input when reading from keyboard with scanf()

16,310

Solution 1

First scanf read the entered string and left behind \n in the input buffer. Next call to scanf read that \n and store it to character.
Try this

scanf (" %c", &characte);   
     // ^A space before %c in scanf can skip any number of white space characters. 

Program will not work for strings more than one character because scanf stops reading once find a white space character. You can use fgets instead

 fgets(string, 200, stdin);

Solution 2

OP's first problem is typically solved by prepending a space to the format. This will consume white-space including the previous line's '\n'.

// scanf("%c", &character);
scanf(" %c", &character);

Moreover, the program does not work for strings with more than one word. How could I overcome these problems?

For the the 2nd issue, let us go for a more precise understanding of "string" and what "%s" does.

A string is a contiguous sequence of characters terminated by and including the first null character. 7.1.1 1

OP is not entering a string even though "I enter a string (e.g.: computer)," is reported. OP is entering a line of text. 8 characters "computer" followed by Enter. There is no "null character" here. Instead 9 char "computer\n".

"%s" in scanf("%s", string); does 3 things:

1) Scan, but not save any leading white-space.

2) Scan and save into string any number of non-white-space.

3) Stop scanning when white-space or EOF reached. That char is but back into stdin. A '\0' is appended to string making that char array a C string.

To read a line including spaces, do not use scanf("%s",.... Consider fgets().

fgets(string, sizeof string, stdin);
// remove potential trailing \r\n as needed
string[strcspn(string, "\n")] = 0;

Mixing scanf() and fgets() is a problem as calls like scanf("%s", string); fgets(...) leave the '\n' in stdin for fgets() to read as a line consisting of only "\n". Recommend instead to read all user input using fgets() (or getline() on *nix system). Then parse the line read.

fgets(string, sizeof string, stdin);
scanf(string, "%c", &character);

If code must user scanf() to read user input including spaces:

scanf("%*[\n]"); // read any number of \n and not save.
// Read up to 199 `char`, none of which are \n
if (scanf("%199[^\n]", string) != 1) Handle_EOF();

Lastly, code should employ error checking and input width limitations. Test the return values of all input functions.

Solution 3

What you're seeing is the correct behavior of the functions you call:

  • scanf will read one word from the input, and leave the input pointer immediately after the word it reads. If you type computer<RETURN>, the next character to be read is the newline.

  • To read a whole line, including the final newline, use fgets. Read the documentation carefully: fgets returns a string that includes the final newline it read. (gets, which shouldn't be used anyway for a number of reasons, reads and discards the final newline.)

I should add that while scanf has its uses, using it interactively leads to very confusing behavior, as I think you discovered. Even in cases where you want to read word by word, use another method if the intended use is interactive.

Solution 4

You can make use of %*c:

#include <string.h>
#include <stdio.h>

int main()
{
    char string[200];
    char character;
    printf ("write something: ");
    scanf ("%s%*c", string);
    printf ("%s", string);
    printf ("\nwrite a character: ");
    scanf ("%c%*c", &character);
    printf ("\nCharacter %c  Correspondent number: %d\n", character, character);

    return 0;
}

%*c will accept and ignore the newline or any white-spaces

Share:
16,310

Related videos on Youtube

El Cid
Author by

El Cid

Updated on September 17, 2022

Comments

  • El Cid
    El Cid over 1 year

    This was supposed to be very simple, but I'm having trouble to read successive inputs from the keyboard.

    Here's the code:

    #include <string.h>
    #include <stdio.h>
    
    int main()
    {
        char string[200];
        char character;
        printf ("write something: ");
        scanf ("%s", string);
        printf ("%s", string);
        printf ("\nwrite a character: ");
        scanf ("%c", &character);
        printf ("\nCharacter %c  Correspondent number: %d\n", character, character);
    
        return 0;
    }
    

    What is happening

    When I enter a string (e.g.: computer), the program reads the newline ('\n') and puts it in character. Here is how the display looks like:

     write something: computer
     computer
     Character:
        Correspondent number: 10
    

    Moreover, the program does not work for strings with more than one word. How could I overcome these problems?

    • John
      John almost 9 years
      scanf is insecure, use fgets instead.
    • ericbn
      ericbn almost 9 years
    • ericbn
      ericbn almost 9 years
    • user3629249
      user3629249 almost 9 years
      regarding this line: 'scanf ("%s", string);' the user could overflow the input buffer, resulting in undefined behaviour and leading to a seg fault event. suggest: 'scanf ("%199s", string);'
  • chux - Reinstate Monica
    chux - Reinstate Monica almost 9 years
    Note: %*c will accept and ignore any following char which is often the newline, but could be any white-space like ' '.
  • Jahid
    Jahid almost 9 years
    @ chux, Yes, that's right. I will add your note to my answer precisely.
  • chux - Reinstate Monica
    chux - Reinstate Monica almost 9 years
    OP's use of printf() is correct. Variadic arguments like char character are promoted using the usual proportion to int (or rarely unsigned) so the cast int is not needed. printf ("%c %d",... takes two int arguments so OP is using the correct specifier. "d,i The int argument is converted ..." "c If no l length modifier is present, the int argument... " C11 §7.21.6.1 8
  • user3629249
    user3629249 almost 9 years
    I agree with using fgets() rather than scanf() to read a line of text. However, the second input is expected to input the 'newline' and 'newline' is white space, so the suggested: scanf (" c", &character); will not work as scanf will skip over the new line. Maybe that is what is wanted, the question was unclear on that detail.
  • haccks
    haccks almost 9 years
    @user3629249; It is always safe to use " %c" in scanf. What if user will press Enter/Return twice?
  • M.M
    M.M about 7 years
    Your code has a buffer overflow, and fflush(stdin) causes undefined behaviour
  • M.M
    M.M about 7 years
    This has a buffer overflow; you need to limit the input
  • ps_
    ps_ about 7 years
    @M.M any evidence to back up the fact that fflush produces undefined behaviour ! And I didn't quite get the buffer overflow part can you please rephrase/explain. Thanks.
  • M.M
    M.M about 7 years
    If they type 200 letters then you overflow string. For fflush see section 7.21.5.2/2 of the current C standard, "If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined". stdin is not an output or update stream.
  • ps_
    ps_ about 7 years
    @M.M As far as buffer overflow goes, that's not the point I was trying to make. Obviously an array would overflow if you try storing data beyond its capacity. I was neither addressing that issue nor trying to accommodate for that in my code.
  • ps_
    ps_ about 7 years
    @M.M And yes the specification says so, but still fflush is behaving entirely as one would predict and as is supposed to even with an input stream hence I think it'd be safe to assume that stdin can be flushed in this manner without any repercussions unless you've a counter example where flushing stdin between successive inputs results in undefined behaviour. Also I amn't quite aware of the term update stream, can you please tell me what exactly does it mean, and what's exactly the difference between an input stream and an update stream. Thanks.
  • M.M
    M.M about 7 years
    fflush isn't behaving as I would predict and it is not supposed to do some particular thing for an input stream. You are mistakenly assuming that behaviour you observed on one compiler is standard behaviour. "update stream" means one that can be used for reading and writing (opened with + flag)
  • ps_
    ps_ about 7 years
    @M.M I understand what you are trying to point out. Can you please give me a compiler version and a corresponding environment and a particular program where fflush goes haywire. It's just that I want to see it for myself how exactly things go in that case. Also, you say "it isn't supposed to do some particular things for an input stream...", what all is it not supposed to do that it's doing here, can you please be more specific ? All that's visible in the foreground is that it flushed the extra characters present in the stream which I feel is acceptable, correct me if I am wrong. Thanks.
  • M.M
    M.M about 7 years
    See what is undefined behaviour. There is no defined behaviour for fflush on an input stream. You still do not seem to understand this. You could google "fflush stdin does not work" for examples of people who had similar misgivings to yourself, and see what systems they were on.
  • ps_
    ps_ about 7 years
    Got it! Thanks ! Peace out.