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.
Related
There is a problem with gets function. The first gets I write does not work but the ones comes next works properly.
I put an extra gets() function at the beginning, program just skips it and gets the string I want. But it is not safe and reliable. So what is the problem with gets and how can I fix it?
if (choice == 1) {
printf("Please enter an English phrase with upper case: ");
gets(a);
gets(engphr);
for (i = 0; engphr[i] != '\0'; i++) {
As Eraklon mentions in their comment, the most likely cause is that you have a scanf call before the gets call, and the trailing newline from the previous input is getting consumed by gets before you have a chance to enter anything else.
You should never use gets anyway - it was removed from the standard library in the 2011 version of the language. It is inherently unsafe to use, and will introduce a security hole in your code. Use fgets instead. Its behavior is slightly different (it will save the trailing newline to the input buffer if there's room, where gets discarded it), but it's much safer:
if ( fgets( engphr, sizeof engphr, stdin ) ) // assumes engphr is declared as an array, not a pointer
{
// process engphr
}
Having said that, you really shouldn't mix calls to scanf and fgets, again because scanf will leave trailing newlines in the input stream from previous inputs, and fgets will immediately return after seeing that newline. Either read all input using fgets and use sscanf to read specific items from the input buffer, or read all input with scanf.
I'm just asking what does the getchar do in this code and how does it work? I don't understand why the getchar affects the code, to me it seems as if its just getting the value but nothing is being done with the value.
int c=0;
while (c>=0)
{
scanf("%d", &c);
getchar();
}
Some possibilities of why getchar() might have been used there:
1) If it's done to ignore whitespaces (typically used when scanning chars with %c), it's not needed here because %d ignores whitespaces anyway.
2) Other possibility is that after this loop, some further scanning is done where the last \n left by the last call to scanf() might be a problem. So, getchar() might be used to ignore it.
3) In case you enter characters do not match %d, scanf() will fail. In that the characters you entered are left in the input stream and you'll never be able to read an int again (For example, if you input abcdddgdfg without that getchar() call). So, getchar() here will consume all those
chars (one per iteration) and eventually you'll be able to read int (using %d) again.
But this is all really not needed; it's just an attempt to fix flaws of scanf(). Reading inputs using scanf() and getting it correct is really difficult. That's why it's always recommended to use fgets() and parse using sscanf() or using strto*() functions if you are just scanning integers.
See: Why does everyone say not to use scanf? What should I use instead?
In this code, getchar is being called for its side effects: it reads a character from standard input and throws it away.
Probably this is reading input from the user. scanf will consume a number, but leave the newline character after the number untouched. The getchar consumes the newline and throws it away. This isn't strictly necessary in this loop, because the next scanf will skip over whitespace to find the next number, but it might be useful if the code after the loop isn't expecting to have a newline as the first thing on stdin.
This code is buggy, because it doesn't check for EOF, because it doesn't do anything sensible when the input is not a number or when there's more text on the line after the number, and because it uses scanf, which is broken-as-specified (for instance, it's allowed to crash the program if the input overflows the range of an int). Better code would be something like
char *linep = 0;
size_t asize = 0;
char *endp;
long c;
while (getline(&linep, &asize, stdin) > 0) {
errno = 0;
c = strtol(linep, &endp, 10);
if (linep == endp || *endp != '\0' || errno) {
puts("?Redo from start");
continue;
}
if (c == 0) break;
do_something_with(c);
}
free(linep);
Most likely the code is for reading in a list of integers, separated by a new line.
scanf will read in an integer, and put it into variable c.
The getchar is reading in the next character (assuming a new line)
Since it doesn't check, there is some potential that it wasn't a new line, or that scanf failed as the what it tried to read wasn't a number.
getchar(); is simply reading and consuming the character after the number, be it a space, comma, new line or the beginning of another integer or anything else.
IMO, this is not robust code. Good code would 1) at least test the result of scanf() and 2) test or limit the consumption of the following character to prevent "eating" a potential sign of the following number. Remember code cannot control what a user types, but has to cope with whatever is entered.
v space
"123 456"
v comma
"123,456"
v negative sign
"123-456"
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.
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);
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;
}