Whenever I do a scanf before a fgets the fgets instruction gets skipped. I have come accross this issue in C++ and I remember I had to had some instrcution that would clear the stdin buffer or something like that. I suppose there's an equivalent for C. What is it?
Thanks.
I'll bet it's because of the \n stuck in the input stream.
See one of these questions:
I am not able to flush stdin.
How do I go about Flushing STDIN here?
scanf() causing infinite loop
or this answer.
Also: Why not to use scanf().
P.S. fgets() is a function, not an instruction.
The fgets() function following the call to scanf() is probably1 not getting skipped. It is probably1 returning immediately having found a newline in the input stream.
Calling scanf() before fgets() almost always results in scanf() leaving an unused newline ('\n') in the input stream, which is exactly what fgets() is looking out for.
In order to mix scanf() and fgets(), you need to remove the newline left behind by the call to scanf() from the input stream.
One solution for flushing stdin (including the newline) would be something along the lines of the following:
int c;
/* discard all characters up to and including newline */
while ((c = getchar()) != '\n' && c != EOF);
1 - It is difficult to be certain without seeing the actual code.
Or, as Jerry Coffin suggested in his comment below, you could use scanf("%*[^\n]");. The "%*[^\n]" directive instructs scanf() to match things that are not newlines and suppress assignment of the result of the conversion.
/* match up to newline */
scanf("%*[^\n]");
/* discard the newline */
scanf("%*c");
From http://c-faq.com/stdio/gets_flush1.html:
An initial scanf() with “%*[^\n]” will either eat everything up to but not including a newline, or fail. A subsequent “%*c” (or plain old getchar()) will consume the newline, if there was one.
That last “if” matters too: perhaps the user signalled EOF. In this case, the getchar() or scanf("%*c") might -- this decision is left to the people who write your compiler -- either immediately return EOF, or go back to the user for more input. If the implementors choose the latter, the user might have to click on “end this thing” (^D, ^Z, mouse button, front panel switch, or whatever) one extra time. This is annoying, if nothing else.
Or, as Chris Dodd suggested in his comment below, you could use scanf("%*[^\n]%*1[\n]");. The "%*[^\n]%*1[\n]" directive instructs scanf() to match things that are not newlines and then match one newline and suppress assignment of the results of the conversion.
/* match and discard all characters up to and including newline */
scanf("%*[^\n]%*1[\n]");
You can just put this line before your fgets() call and that'll get the trailing '\n' generated when you pressed enter
scanf("%c", (char *) stdin);
Related
According to the man page for sscanf(), the * character
An optional '*' assignment-suppression character: scanf() reads input
as directed by the conversion specification, but discards the input.
From this, I (rightly?) assume that something like
sscanf(string,"%*[^|]%*c%[^|]%*c", vars)
Would take the input, "text|neededtext|", ignore all text before the first "|" (ie deleting it from stdin?), ignore (and delete from stdin) the next character, ie the "|" store the "neededtext" and then delete the final "|" character, leaving stdin empty?
If yes, then is it ever needed to run a cleanup function after this sscanf() call, to catch some weird exception just in case something goes wrong, or is the code above always guaranteed to work?
I have run some tests, and it appears that sscanf() does eat up all characters from stdin, but I just want to make sure.
Not always. See #2
A #Jonathan Leffler commented, sscanf() works with strings and does not affect stdin. Let us assume the question is about the *scanf() family instead.
Problems with *scanf(string,"%*[^|]%*c%[^|]%*c", vars)
Code does not check the result of *scanf(). This leads to subtle to detect problems. Best to code a check.
char vars[100];
if (sscanf(string,"%*[^|]%*c%99[^|]%*c", vars) != 1) Handle_Error();
"%*[^|]" scans nothing and stops the whole scan function if the leading character is '|'. "%*[^|]" scans 1 or more non-'|', not 0 or more. Hence the "Not always" above. With scanf(), no characters are consume - they remain in stdin.
The only possible character after "%*[^|]" to continue scanning is '|'. Might as well code "%*[^|]%|" than "%*[^|]%*c"
sscanf() differs from scanf() and fscanf() in that the later 2 can scan and save a null character '\0'. sscanf() stops scanning upon reaching the null character. IMO: Use of "%s" and "%[^...] with fscanf() scanf() should be avoided to prevent a hacker exploit. OP's fgets()+sscanf() is the better approach.
%[^|] lacks a width. Without this limit, buffer overrun is not prevented. See #1.
"%*c" at the end may or may not scan a character. The result value does not reflect its success or failure as scan directives with '*' do not contribute directly to the return value. If successful trailing scanning of "%*c" was needed (which could be "|" per point #3), suggest using "%n" to detect is scanning proceed that far.
char vars[100];
int n = 0;
sscanf(string,"%*[^|]|%99[^|]| %n", vars);
if (n > 0) Success();
// May also want to use
if (string[n]) Fail_ExtraTextOnLine();
In C, %*[^|] is a scanf specifier, not delimiter.
I am using gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
I am writing a very simple script to take string as input and print the same with the some custom message. First user enters the T(no. of times to take string) and then takes input by fgets.. I used this&this as reference. I am getting a very strange output ie fgets is adding some extra new lines and even loop is not working properly for T=2 it is asking input only once. Can anybody explain me what is wrong with snippet. Thanks in advance!
#include<stdio.h>
#include<string.h>
int main()
{
int T;
scanf("%d",&T);
while(T--){
char str[100]={""};
int i;
printf("Hello\n");
fgets(str,80,stdin);
i = strlen(str)-1;
if(str[i]=='\n')
str[i]='\0';
printf("World\n");
printf("%s\n",str);
}
return 0;
}
Please see the image reference for T=2, even T=2 it is taking string only once and order of printing statement is also not as expected.
This is because your scanf() call
scanf("%d",&T);
does not consume the new line character \n accompanied by your input.
When you input T, your input is 2Enter.
scanf() consumes the 2, sees \n and stops consuming, leaving \n in the input buffer.
When the fgets() gets called, it sees the \n in the buffer and treats this as the input.
To solve this, you have a few choices (in decreasing order of my subjective preference):
Use fgets() to get the first input, then parse it using strtol() to get T.
Add an extra fgets() after the scanf().
Add getchar() to consume one extra character. This works if you are certain that exactly one \n will be present after the input. So for example it won't work if you type 2SpaceEnter. Alternatively, you may use while(getchar() != '\n'); after the scanf() to consume everything up to a new line, but this may cause problems if an empty line is a valid input to your later fgets() calls.
If your implementation supports it, you may use fpurge(stdin) or __fpurge(stdin).
And, very importantly, do not use fflush(stdin) unless your implementation clearly defines its behavior. Otherwise it is undefined behavior. You may refer to this question for more details. Also, note that the fpurge() and fflush() methods may not work correctly if your input can be piped into the program.
This line
scanf("%d",&T);
reads the input until the first non-numeral is found, which is newline. Then fgets() reads that newline for its first input.
I suggest using fgets() to read the number too.
fgets(str,80,stdin);
sscanf(str, "%d", &T);
With your first call to scanf you allow the user to input an integer for the number of loops. They do so, and use a carriage return to signal the end of input. At this point scanf reads the integer, but leaves the end-of-line (\n) in the stream..
So when you call fgets, fgets gets from the stream until it reaches the first newline -- in you code, on the first loop, this is the very first character it encounters.
If you discard the newline before calling fgets, you should get your desired results. You can do this, for example by changing your first three lines to:
int T;
char newline;
scanf("%d%c",&T, &newline);
Although there are probably stylistically superior ways of doing this.
You have a newline character in the input stream when you press "enter" after typing 2 for the first scanf. This is consumed by fgets() initially, hence it prints nothing (You replace the newline by \0).
In the next line, your input is read and echoed after World because you are printing it after it.
I spent the past hour trying to figure out why
char buffer[101];
scanf("%100[^\n]", buffer);
works as intended, reading a string until in encounters a newline, while
char buffer[101];
scanf("%100[^\n]\n", buffer);
does not return after pressing Enter.
Explicitly flushing the input buffer with CtrlD (in linux)
immediately after pressing Enter seems to fix the problem,
forcing the scanf to return. Am I missing something here?
Yes, you have missed an important detail that's well documented. According to the scanf manual...
A directive composed of one or more white-space characters shall be executed by reading input until no more valid input can be read, or up to the first byte which is not a white-space character, which remains unread.
This implies that scanf will indeed not return when you press enter; It'll continue waiting to see if you press enter (or space, or tab) again... and again... until it sees something that isn't white-space.
If you want to discard the '\n' that's left following the scanset directive, you could use %*c like so: int x = scanf("%100[^\n]%*c", buffer);...
P.S. Don't forget to check the value of x. It's particularly important when you use scanset directives, because an empty line will result in an uninitialised buffer, in this case.
Is there any other method to clear the input buffer in c withut using
fflush();
or
while(getchar()!='\n');
Because i have read it everywhere and cant find any other way to do it.
The best solution is to not depend on the input buffer's state so much.
Read input as whole lines, using fgets(), then parse those. Don't use e.g. scanf() to read individual values, since it interacts with the buffer in annoying ways.
Using fgets() as suggester #unwind best approach.
To flush to the end of the line.
void FlushStdin(void) {
int ch;
while(((ch = getchar()) !='\n') && (ch != EOF));
}
If stdin is all ready flushed to the end-of-line, calling FlushStdin() or other posted scanf(), fgetc() solutions, will flush to the end of the next line.
Note scanf("%*[^\n]%*1[\n]"); does not work if the next char is '\n'.
Another method to clear the input buffer(stdin) would be to use
scanf("%*[^\n]%*1[\n]");
Here,%*[^\n] instructs scanf to scan everything until a new-line character(\n) is found and then discard it.The %1*[\n] tells scanf to scan 1 character including a \n character and discard it also.
I'm having a weird problem
i'm trying to read a string from a console with scanf()
like this
scanf("%[^\n]",string1);
but it doesnt read anything. it just skips the entire scanf.
I'm trying it in gcc compiler
Trying to use scanf to read strings with spaces can bring unnecessary problems of buffer overflow and stray newlines staying in the input buffer to be read later. gets() is often suggested as a solution to this, however,
From the manpage:
Never use gets(). Because it is
impossible to tell without knowing the
data in advance how many characters
gets() will read, and because gets()
will continue to store characters past
the end of the buffer, it is extremely
dangerous to use. It has been used to
break computer security. Use fgets()
instead.
So instead of using gets, use fgets with the STDIN stream to read strings from the keyboard
That should work fine, so something else is going wrong. As hobbs suggests, you might have a newline on the input, in which case this won't match anything. It also won't consume a newline, so if you do this in a loop, the first call will get up to the newline and then the next call will get nothing. If you want to read the newline, you need another call, or use a space in the format string to skip whitespace. Its also a good idea to check the return value of scanf to see if it actually matched any format specifiers.
Also, you probably want to specify a maximum length in order to avoid overflowing the buffer. So you want something like:
char buffer[100];
if (scanf(" %99[^\n]", buffer) == 1) {
/* read something into buffer */
This will skip (ignore) any blank lines and whitespace on the beginning of a line and read up to 99 characters of input up to and not including a newline. Trailing or embedded whitespace will not be skipped, only leading whitespace.
I'll bet your scanf call is inside a loop. I'll bet it works the first time you call it. I'll bet it only fails on the second and later times.
The first time, it will read until it reaches a newline character. The newline character will remain unread. (Odds are that the library internally does read it and calls ungetc to unread it, but that doesn't matter, because from your program's point of view the newline is unread.)
The second time, it will read until it reaches a newline character. That newline character is still waiting at the front of the line and scanf will read all 0 of the characters that are waiting ahead of it.
The third time ... the same.
You probably want this:
if (scanf("%99[^\n]%*c", buffer) == 1) {
Edit: I accidentally copied and pasted from another answer instead of from the question, before inserting the %*c as intended. This resulting line of code will behave strangely if you have a line of input longer than 100 bytes, because the %*c will eat an ordinary byte instead of the newline.
However, notice how dangerous it would be to do this:
scanf("%[^n]%*c", string1);
because there, if you have a line of input longer than your buffer, the input will walk all over your other variables and stack and everything. This is called buffer overflow (even if the overflow goes onto the stack).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *text(int n);
int main()
{
char str[10];
printf("enter username : ");
scanf(text(9),str);
printf("username = %s",str);
return 0;
}
char *text(int n)
{
fflush(stdin);fflush(stdout);
char str[50]="%",buf[50],st2[10]="[^\n]s";
char *s;itoa(n,buf,10);
// n == -1 no buffer protection
if(n != -1) strcat(str,buf);
strcat(str,st2);s=strdup(str);
fflush(stdin);fflush(stdout);
return s;
}