Scanf function inside of while runs only one time? - c

Why did my scanf function inside while runs only one time?
#include<stdio.h>
#include<stdlib.h>
int main()
{
char s[9999];
while(scanf("%[^\n]s",s)>0)
{
int count=0, prev=0;
for (int i=0;i<strlen(s);i++)
{
if(s[i]==' ')
{
count=i-prev;
prev=i+1;
printf("%c", (char) (96+count));
}
else if(strlen(s)-1==i)
{
count=i-prev+1; printf("%c", (char) (96+count)); }
}
printf(" ");
}}
my test case and output:
Input is considered as a string with a maximum length 1000

Unless you understand scanf, you shouldn't use it. When you understand scanf, you will not use it. There are several problems with
while(scanf("%[^\n]s",s)>0)
scanf will read the input stream, writing characters into the variable s until it sees a newline. It will then try to match a literal s in the input stream. Clearly, the next character is not an s (it is a newline), so the s in the format string does not match. (This is not really a problem, but is certainly bizarre that you have asked scanf to match a literal s when an s is certainly not there. If you had tried to do further matches with something like "%[^\n]s%d", you might be confused as to why scanf never matches an integer. It is because scanf stops scanning as soon as the input stream does not match the format string, and the s in the format string will not match.) On the second iteration of the loop, the first character scanf sees is that newline, so it makes no conversions and returns 0. If you want to discard that newline and are okay with removing leading whitespace, you can simply use " %[\n]" as a conversion specifier. If you do not want to discard leading whitespace, you can discard the newline with " %[\n]%*c" Note that you really ought to protect against overwriting s, so you should use either:
while(scanf(" %9998[^\n]", s) > 0)
or
while(scanf("%9998[^\n]%*c", s) > 0)

Here, during the first iteration, s stores the first line, and at the second iteration s read \n. Since I used %[^\n], scanf will stop scanning.
Now here, the number of elements scanned is zero. So the while loop condition is failed. Hence, the loop is iterated only for one line.
We can change the condition as:
while(scanf("%[^\n]\n",s)>0)
This will skip scanning \n, and desired output is printed.

Related

Why is this creating two inputs instead of one

https://i.imgur.com/FLxF9sP.png
As shown in the link above I have to input '<' twice instead of once, why is that? Also it seems that the first input is ignored but the second '<' is the one the program recognizes.
The same thing occurs even without a loop too.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
int randomGen, upper, lower, end, newRandomGen;
char answer;
upper = 100;
lower = 1;
end = 1;
do {
srand(time(0));
randomGen = rand()%(upper + lower);
printf("%d\n", randomGen);
scanf("%s\n", &answer);
}while(answer != '=');
}
Whitespace in scanf format strings, like the \n in "%c\n", tries to match any amount of whitespace, and scanf doesn’t know that there’s no whitespace left to skip until it encounters something that isn’t whitespace (like the second character you type) or the end of input. You provide it with =\n, which fills in the %c and waits until the whitespace is over. Then you provide it with another = and scanf returns. The second time around, the character could be anything and it’d still work.
Skip leading whitespace instead (and use the correct specifier for one character, %c, as has been mentioned):
scanf(" %c", &answer);
Also, it’s good practice to make sure you actually succeeded in reading something, especially when failing to read something means leaving it uninitialized and trying to read it later (another example of undefined behaviour). So check scanf’s return value, which should match the number of conversion specifiers you provided:
if (scanf(" %c", &answer) != 1) {
return EXIT_FAILURE;
}
As has been commented, you should not use the scanf format %s if you want to read a single character. Indeed, you should never use the scanf format %s for any purpose, because it will read an arbitrary number of characters into the buffer you supply, so you have no way to ensure that your buffer is large enough. So you should always supply a maximum character count. For example, %1s will read only one character. But note: that will still not work with a char variable, since it reads a string and in C, strings are arrays of char terminated with a NUL. (NUL is the character whose value is 0, also sometimes spelled \0. You could just write it as 0, but don't confuse that with the character '0' (whose value is 48, in most modern systems).
So a string containing a single character actually occupies two bytes: the character itself, and a NUL.
If you just want to read a single character, you could use the format %c. %c has a few differences from %s, and you need to be aware of all of them:
The default maximum length read by %s is "unlimited". The default for %c is 1, so %c is identical to %1c.
%s will put a NUL at the end of the characters read (which you need to leave space for), so the result is a C string. %c does not add the NUL, so you only need to leave enough space for the characters themselves.
%s skips whitespace before storing any characters. %c does not ignore whitespace. Note: a newline character (at the end of each line) is considered whitespace.
So, based on the first two rules, you could use either of the following:
char theShortString[2];
scanf("%1s", theShortString);
char theChar = theShortString[0];
or
char theChar;
scanf("%c", &theChar);
Now, when you used
scanf("%s", &theChar);
you will cause scanf to write a NUL (that is, a zero) in the byte following theChar, which quite possibly is part of a different variable. That's really bad. Don't do that. Ever. Even if you get away with it today, it will get you into serious trouble some time soon.
But that's not the problem here. The problem here is with what comes after the %s format code.
Let's take a minute (ok, maybe half an hour) to read the documentation of scanf, by typing man scanf. What we'll see, quite near the beginning, is: (emphasis added)
A directive is one of the following:
A sequence of white-space characters (space, tab, newline, etc.; see isspace(3)). This directive matches any amount of white space, including none, in the input.
So when you use "%s\n", scanf will do the following:
skip over any white-space characters in the input buffer.
read the following word up to but not including the next white-space character, and store it in the corresponding argument, followed by a NUL.
skip over any white-space following the word which it just read.
It does the last step because \n — a newline — is itself white-space, as noted in the quote from the manpage.
Now, what you actually typed was < followed by a newline, so the word read at step 2 will be just he character <. The newline you typed afterwards is white-space, so it will be ignored by step 3. But that doesn't satisfy step 3, because scanf (as documented) will ignore "any amount of white space". It doesn't know that there isn't more white space coming. You might, for example, be intending to type a blank line (that is, just a newline), in which case scanf must skip over that newline as well. So scanf keeps on reading.
Since the input buffer is now empty, the I/O library must now read the next line, which it does. And now you type another < followed by a newline. Clearly, the < is not white-space, so scanf leaves it in the input buffer and returns, knowing that it has done its duty.
Your program then checks the word read by scanf and realises that it is not an =. So it loops again, and the scanf executes again. Now there is already data in the input buffer (the second < which you typed), so scanf can immediately store that word. But it will again try to skip "any amount of white space" afterwards, which by the same logic as above will cause it to read a third line of input, which it leaves in the input buffer.
The end result is that you always need to type the next line before the previous line is passed back to your program. Obviously that's not what you want.
So what's the solution? Simple. Don't put a \n at the end of your format string.
Of course, you do want to skip that newline character. But you don't need to skip it until the next call to scanf. If you used a %1s format code, scanf would automatically skip white-space before returning input, but as we've seen above, %c is far simpler if you only want to read a single character. Since %c does not skip white-space before returning input, you need to insert an explicit directive to do so: a white-space character. It's usual to use an actual space rather than a newline for this purpose, so we would normally write this loop as:
char answer;
srand(time(0)); /* Only call srand once, at the beginning of the program */
do {
randomGen = rand()%(upper + lower); /* This is not right */
printf("%d\n", randomGen);
scanf(" %c", &answer);
} while (answer != '=');
scanf("%s\n", &answer);
Here you used the %s flag in the format string, which tells scanf to read as many characters as possible into a pre-allocated array of chars, then a null terminator to make it a C-string.
However, answer is a single char. Just writing the terminator is enough to go out of bounds, causing undefined behaviour and strange mishaps.
Instead, you should have used %c. This reads a single character into a char.

Why this c program fall into infinity loop?

#include <stdio.h>
int main()
{
int sum=0;
char s[10];
while(scanf("%[^\n]s", s)!=EOF)
{
printf("%s", s);
}
return 0;
}
This while loop fall into infinity loop for any string input.
Given
while(scanf("%[^\n]s", s)!=EOF)
{
printf("%s", s);
}
you ask "Why this c program fall into infinity loop?"
Therefore, you have to understand how scanf() works. scanf() uses your format string to parse input from stdin, which is a stream that delivers character by character.
Assume you have the following in stdin:
foo\n
bar\n
<<EOF>>
Now your format string has this conversion %[^\n] which means "match anything but newline and copy into a char buffer". The s following it is just a literal s because it doesn't have a % in front of it ... so it would match a literal s if there was one. In other words, it doesn't matter here.
Now, calling your scanf() the first time, it WILL match foo and consume it. it returns 1 because it matched one element. After that, stdin looks like this:
\n
bar\n
<<EOF>>
Note the unmatched newline is still there. Your next call again starts with a format string to match anything but newline, but the next character is a newline. scanf() matches nothing and therefore returns 0. It cannot return EOF because, as you can see, EOF is not reached yet. Here is your infinite loop.
So, you have to fix your format string. First, remove the s that never matches anything. It doesn't really hurt here, but it's still wrong. Then, you can take advantage of the whitespace matching of scanf(). Whitespace is either space, tab or newline. If your format string contains whitespace, scanf() will match as much whitespace as is there (this can be none as well). Therefore, an easy fix would be to just start your format string with a space, this will "eat" the left-over newline:
while(scanf(" %[^\n]", s)!=EOF)
{
printf("%s", s);
}
Now this is still dangerous code, because [^\n] matches any amount of characters as long as there is no newline, but your buffer has only room for 9 character plus terminating 0. So you MUST tell scanf() not to match more than that limit, and this can be done by putting the number between the % and the conversion specification:
while(scanf(" %9[^\n]", s)!=EOF)
{
printf("%s", s);
}
This code will do what you want in a safe manner, but assume you wanted to match something more specific, e.g. numbers, and you get some unexpected input: By waiting for EOF, you'd have your infinite loop again, because there is input that doesn't match, and so you can never reach EOF (as above with the unmatched newline). Therefore, always check for the number of successful matches instead. Here you expect exactly one match, so the loop should look like this:
while (scanf(" %9[^\n]", s) == 1)
{
printf("%s", s);
}
In practice, for reading whole lines, you don't need scanf(), just using fgets() would be easier. Your code could look as simple as this (the newlines will be read into s as well):
while (fgets(s, 10, stdin))
{
printf("%s", s);
}
Note the second parameter 10 here: fgets() automatically accounts for the terminating 0 character, so you just give it the size of your buffer.
Just a final hint: this could be even simpler without using printf() when there's no formatting to do:
while (fgets(s, 10, stdin))
{
fputs(s, stdout);
}
int main()
{
int sum = 0;
char s[10];
int ret = scanf("%[^\n]s", s);
while (ret != EOF)
{
printf("%s", s);
memset(s,0,10);
ret = scanf("%[^\n]s", s);
}
return 0;
}
with the debug, you can see the second ret value in the while block is 0, that's , and not equal EOF, so infinity loop.
man scanf:
RETURN VALUE
Upon successful completion, these functions shall return the number of successfully matched and assigned input items; this number can be zero in the event of an early matching failure.
That mean the other scanf is matching failure, except the first one.
But why?
The stdio has cache, and the matching only read "\n" from the stdin, but when you input the "Enter", it input "\n\r", so, the "\r" will in the stdin cache and become the input value for other scanf, but cannot match the input, so matching failure. And scanf return 0, and goto infinity loop.
But if you only input "\n" for each input, it's OK!
You can press "Alt" and at same time press "0" + "1" + "0", and the release the "Alt", the console will input "\n" only and you will get the right result , and the program will be OK, not into infinity loop!
And this's my test result:enter image description here

C code, scanf and getchar

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"

Why won't this scanf format-string work? "%[^\n]\n"

I've seen a few examples where people give scanf a "%[^\n]\n" format string to read a whole line of user input. If my understanding is correct, this will read every character until a newline character is reached, and then the newline is consumed by scanf (and not included in the resulting input).
But I can't get this to work on my machine. A simple example I've tried:
#include <stdio.h>
int main(void)
{
char input[64];
printf("Enter some input: ");
scanf("%[^\n]\n", input);
printf("You entered %s\n", input);
}
When I run this, I'm prompted for input, I type some characters, I hit Enter, and the cursor goes to the beginning of the next line but the scanf call doesn't finish.
I can hit Enter as many times as I like, and it will never finish.
The only ways I've found to conclude the scanf call are:
enter \n as the first (and only) character at the prompt
enter Ctrl-d as the first (and only) character at the prompt
enter some input, one or more \n, zero or more other characters, and enter Ctrl-d
I don't know if this is machine dependent, but I'm very curious to know what's going on. I'm on OS X, if that's relevant.
According to the documentation for scanf (emphasis mine):
The format string consists of whitespace characters (any single whitespace character in the format string consumes all available consecutive whitespace characters from the input), non-whitespace multibyte characters except % (each such character in the format string consumes exactly one identical character from the input) and conversion specifications.
Thus, your format string %[^\n]\n will first read (and store) an arbitrary number of non-whitespace characters from the input (because of the %[^\n] part) and then, because of the following newline, read (and discard) an arbitrary number of whitespace characters, such as spaces, tabs or newlines.
Thus, to make your scanf stop reading input, you either need to type at least one non-whitespace character after the newline, or else arrange for the input stream to end (e.g. by pressing Ctrl+D on Unix-ish systems).
Instead, to make your code work as you expect, just remove the last \n from the end of your format string (as already suggested by Umamahesh P).
Of course, this will leave the newline still in the input stream. To get rid of it (in case you want to read another line later), you can getc it off the stream, or just append %*c (which means "read one character and discard it") or even %*1[\n] (read one newline and discard it) to the end of your scanf format string.
Ps. Note that your code has a couple of other problems. For example, to avoid buffer overflow bugs, you really should use %63[^\n] instead of %[^\n] to limit the number of characters scanf will read into your buffer. (The limit needs to be one less than the size of your buffer, since scanf will always append a trailing null character.)
Also, the %[ format specifier always expects at least one matching character, and will fail if none is available. Thus, if you press enter immediately without typing anything, your scanf will fail (silently, since you don't check the return value) and will leave your input buffer filled with random garbage. To avoid this, you should a) check the return value of scanf, b) set input[0] = '\0' before calling scanf, or c) preferably both.
Finally, note that, if you just want to read input line by line, it's much easier to just use fgets. Yes, you'll need to strip the trailing newline character (if any) yourself if you don't want it, but that's still a lot easier and safer that trying to use scanf for a job it's not really meant for:
#include <stdio.h>
#include <string.h>
void chomp(char *string) {
int len = strlen(string);
if (len > 0 && string[len-1] == '\n') string[len-1] = '\0';
}
int main(void)
{
char input[64];
printf("Enter some input: ");
fgets(input, sizeof(input), stdin);
chomp(input);
printf("You entered \"%s\".\n", input);
}
Whitespace characters in format of scanf() has an special meaning:
Whitespace character: the function will read and ignore any whitespace
characters encountered before the next non-whitespace character
(whitespace characters include spaces, newline and tab characters --
see isspace). A single whitespace in the format string validates any
quantity of whitespace characters extracted from the stream (including
none).
Thus, "%[^\n]\n" is just equivalent to "%[^\n] ", telling scanf() to ignore all whitespace characters after %[^\n]. This is why all '\n's are ignored until a non-whitespace character is entered, which is happened in your case.
Reference: http://www.cplusplus.com/reference/cstdio/scanf/
Remove the the 2nd new line character and the following is sufficient.
scanf("%[^\n]", input);
To answer the original one,
scanf("%[^\n]\n", input);
This should also work, provided you enter a non white space character after the input. Example:
Enter some input: lkfjdlfkjdlfjdlfjldj
t
You entered lkfjdlfkjdlfjdlfjldj

scanf in a while loop reads on first iteration only

NOTE: Please notice this is not a duplicate of Why is scanf() causing infinite loop in this code? , I've already seen that question but the issue there is that he checks for ==0 instead of !=EOF. Also, his problem is different, the "infinite loop" there still waits for user input, it just does not exit.
I have the following while loop:
while ((read = scanf(" (%d,%d)\n", &src, &dst)) != EOF) {
if(read != 2 ||
src >= N || src < 0 ||
dst >= N || dst < 0) {
printf("invalid input, should be (N,N)");
} else
matrix[src][dst] = 1;
}
The intention of which is to read input in the format (int,int), to stop reading when EOF is read, and to try again if an invalid input is received.
The probelm is, that scanf works only for the first iteration, after that there is an infinite loop. The program does not wait for user input, it just keeps assuming that the last input is the same.
read, src, and dst are of type int.
I have looked at similar questions, but they seem to fail for checking if scanf returns 0 instead of checking for EOF, and the answers tells them to switch to EOF.
You need to use
int c;
while((c=getchar()) != '\n' && c != EOF);
at the end of the while loop in order to clear/flush the standard input stream(stdin). Why? The answer can be seen below:
The scanf with the format string(" (%d,%d)\n") you have requires the user to type
An opening bracket(()
A number(For the first %d)
A comma(,)
A number(For the last %d)
The space(First character of the format string of your scanf) and the newline character(\n which is the last character of the format string of your scanf) are considered to be whitespace characters. Lets see what the C11 standard has to say about whitespace characters in the format string of fscanf(Yes. I said fscanf because it is equivalent to scanf when the first argument is stdin):
7.21.6.2 The fscanf function
[...]
A directive composed of white-space character(s) is executed by reading input up to the first non-white-space character (which remains unread), or until no more characters can be read. The directive never fails
So, all whitespace characters skips/discards all whitespace characters, if any, until the first non-whitespace character as seen in the quote above. This means that the space at the start of the format string of your scanf cleans all leading whitespace until the first non-whitespace character and the \n character does the same.
When you enter the right data as per the format string in the scanf, the execution of the scanf does not end. This is because the \n hadn't found a non-whitespace character in the stdin and will stop scanning only when it finds one. So, you have to remove it.
The next problem lies when the user types something else which is not as per the format string of the scanf. When this happens, scanf fails and returns. The rest of the data which caused the scanf to fail prevails in the stdin. This character is seen by the scanf when it is called the next time. This can also make the scanf fail. This causes an infinite loop.
To fix it, you have to clean/clear/flush the stdin in each iteration of the while loop using the method shown above.
scanf prompts the user for some input. Assuming the user does what's expected of them, they will type some digits, and they will hit the enter key.
The digits will be stored in the input buffer, but so will a newline character, which was added by the fact that they hit the enter key.
scanf will parse the digits to produce an integer, which it stores in the src variable. It stops at the newline character, which remains in the input buffer.
Later, second scanf which looks for a newline character in the input buffer. It finds one immediately, so it doesn't need to prompt the user for any more input.

Resources