What does scanf REMOVES from input after scanning?

2019-09-21 02:33发布

问题:

I have gone through many questions and blogs and books, but I guess I'm just not able to relate things properly. What does scanf do after scanning? It reads everything except space, tab and newline, but what does it do to newline?? I'm unable to remove newline any way after scanning input. For example, consider this as input:-

5
Abcdefgh

Now, I have scanned 5 as integer,

 scanf("%d", &i); 

but how do I remove '\n' in order to read everything ahead one character at a time? I want to use:-

 while((c=getchar())!='\n'){//Do something} 

The '\n' is supposed to be the one AFTER the string, but getchar() gets the one after 5 and loop terminates before even running once. I guess I'm just missing a very little trick.

scanf("%d", &i);
while((c=getchar())!='\n'){
    //Do something with the character
}

Input File:-
5
ABCDEF
Expecting while loop to run, while it doesn't run. Because it catches '\n' after 5. I have tried adding getchar() in between scanf() and while(), but then program stucks and does nothing.

回答1:

If you add a space after the %d in your scanf format specifier, scanf will not return until it encounters any non-whitespace character. This will effectively consume any number of newlines or other spaces in your input. As pointed out by @BlueMoon, note that this relies on the program receiving more non-whitespace input after the newline. So it works for this example but might cause trouble elsewhere.

Here's a minimal example:

#include <stdio.h>

int main()
{
    int i, j=0;
    char c;
    scanf("%d ", &i);
    while((c=getchar())!='\n') printf("%d: %c\n", j++, c);    
    return 0;
}

sample input:

5   


abcdefg

output:

0: a
1: b
2: c
3: d
4: e
5: f
6: g

edit: Note that this issue can be circumvented by using fgets to read a line into a character buffer, then extracting the integer using sscanf:

char buff[SIZE];
fgets(buff, SIZE, stdin);
sscanf(buff, "%d ", &i);
while((c=getchar())!='\n') printf("%d: %c\n", j++, c);

fgets reads until a newline or end of file is encountered, or SIZE-1 bytes have been read. Assuming you're only expecting the line to contain one integer, this limitation shouldn't be an issue. As long as SIZE is large enough, the newline will be consumed by fgets and the subsequent getchar in the loop will work as expected.



回答2:

Since you are using Windows, there is a '\r' character before the '\n' character.

The "adding a getchar(); before your while loop" trick doesn't work because this getchar() is getting the '\r' character. So when the while condition is first evaluated, c is '\n'.

So a trivial fix would be to use TWO getchar() calls to consume the '\r\n'. However, this is not very portable, that is, it won't work on other systems.

So I would use the following:

int main() {
    int i;
    char c;
    scanf("%d", &i);
    if(getchar()=='\r') getchar();
    while((c=getchar())!='\n') {
        printf("%c\n", c);
    }
    return 0;
}


回答3:

If you take character or string inputs, use getchar() after every integer inputs. This will remove the \n from the input buffer.

scanf("%d", &i);
getchar();
while((c=getchar())!='\n'){//Do something} 


回答4:

You can use a getchar() right after the scanf() call to consume the \n so that it doesn't interfere with your loop.

scanf("%d", &i); 
getchar(); // To consume the trailing newline left 
           //in the input stream by scanf().

 while((c=getchar())!='\n'){
   //Do something
 } 

#include <stdio.h>

int main(void)
{
    int i, j=0;
    char c;
    scanf("%d", &i);
    getchar();
    printf("%d\n", i);

    while((c=getchar())!='\n'){
      printf("%c-", c);
    }
    return 0;
}

I ran the above code in the same as you do: ./a.out < file on Linux and on windows using mingw and I don't see any problem.



标签: c scanf getchar