Why this c program fall into infinity loop? - c

#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

Related

Scanf function inside of while runs only one time?

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.

Difference between `"%[^\n]"` and `"%[^\n]\n"` and `"%[^\n]%*c"` in C how do they work?

I could not find the answer anywhere else.
%[^\n] - When I run this one, scanf is getting input and terminating after I press enter. ( Probably leaving \n in the input system)
%[^\n]\n - this one is getting the input but scanf is NOT terminating immediately after I press enter like the one above. I hit more enter and it makes more newlines. When I give a character and then press enter it finally terminates. Example:
int main(void)
{
char s[100];
scanf("%[^\n]\n", s);
printf("%s", s);
return 0;
}
The results:
Last one:
%[^\n]%*c - When I give some input and press enter. scanf immediately terminates.
How do those 3 work and how do they differ?
All 3 format begin with "%[^\n]".
"%[^\n]" is poor code2 that lacks a width limit and is susceptible to buffer overrun. Use a width limit like "%99[^\n]" with char s[100];.
"%[...]" does not consume leading whitespace like many other specifiers.
This specifier directs reading input until a '\n'1 is encountered. The '\n' is put back into stdin. All other characters are saved in the matching destination's array s.
If no characters were read (not counting the '\n'), the specifier fails and scanf() returns without changing s - rest of the format is not used. No null character appended.
If characters were read, they are saved and a null character is appended to s and scanning continues with the next portion of the format.
"\n" acts just like " ", "\t", "any_white_space_chracter" and reads and tosses 0 or more whitespace characters. It continues to do so until a non-white-space1 is read. That non-whitespace character is put back into stdin.
Given line buffered input, this means a line with non-whitespace following input is needed to see the next non-whitespace and allow scanf() to move on.
With scanf(), a "\n" at the end of a format is bad and caused OP's problem.
"%*c" reads 1 character1 and throws it away - even if it is not a '\n'. This specifier does not contribute to the return count due to the '*'.
A better alternative is to use fgets().
char s[100];
if (fgets(s, sizeof s, stdin)) {
s[strcspn(s, "\n")] = '\0'; // To lop off potential trailing \n
A lesser alternative is
char s[100] = { 0 };
scanf("%99[^\n]", s);
// With a separate scanf ....
scanf("%*1[\n]"); // read the next character if it is a \n and toss it.
1 ... or end-of-file or rare input error.
2 IMO, worse than gets().

C Program won't terminate after compared to empty string

I am attempting to terminate my C program by checking for an empty string ("") but it seems not to work. I have tried to compare to "\0" as well but it was to no avail.
#include <stdio.h>
#include <string.h>
int main(void) {
char nameInput[128];
for(;;) {
printf("Enter nation name: ");
scanf("%s", nameInput);
if(!strcmp(nameInput, "")){
break;
}
printf("Got nation named \"%s\"\n", nameInput);
}
printf("All done getting nations!\n");
return 0;
}
The "%s" specifier in scanf("%s", nameInput); first consumes1 and discards leading white-space including all '\n' from the Enter before scanning and saving to nameInput.
That is why repeated entries of empty lines do not advance the scan. "%s" is waiting for some non-white-space input.
A better alternative to scanf() is to read all user input with fgets() and then parse the string.
fgets() reads a line and saves the result as a string - usually including the line's ending '\n'.
// scanf("%s", nameInput);
if (fgets(nameInput, sizeof nameInput, stdin)) {
// Success at reading input.
nameInput[strcspn(nameInput, "\n")] = '\0'; // lop off the potential trailing \n
if(!strcmp(nameInput, "")){ // or simply `if(nameInput[0] == '\0')
break;
}
...
have tried to compare to "\0" as well but it was to no avail.
if(!strcmp(nameInput, "")) and if(!strcmp(nameInput, "\0")) do the same thing. strcmp() is comparing strings.
"" is a string literal of 1 char: the null character.
"\0" is a string literal of 2 char: two null characters.
The string compare stops at the first null character.
"%s" by itself also lacks a width limit. Code has no safe guard against input like "BlahBlah...(120_some_more)Blah" and can lead to undefined behavior due a buffer overrun of char nameInput[128];. Code could use "%127s" to prevent that, yet that only handles one of the short-comings of scanf().
1
Input white-space characters (as specified by the isspace function) are skipped, unless the specification includes a [, c, or n specifier. C17dr § 7.21.6.2 8
It's not that it won't terminate, it is awaiting the input that wasn't (yet) typed in.
scanf is not using the right pattern string to scan in anything (including nothing) before the carriage return. You'll need to look into scanf patterns, and alter your pattern from "%s" to something that scanf will accept as input.
If you test out your program, you will see that after pressing "enter" you can type in a word and press enter again, and since you now have a word in the input, the scanf picks it up (discarding the whitespace, as it should with "%s").

Scanf clarification in c language

Is it possible to read an entire string including blank spaces like gets() function in scanf()?
I am able to do it using the gets() function.
char s[30];
gets(s);
This will read a line of characters. Can this be done in scanf()?
You can read a line, including blank spaces, with scanf(), but this function is subtle, and using it is very error-prone. Using the %[^\n] conversion specifier, you can tell scanf() to match characters to form a string, excluding '\n' characters. If you do this, you should specify a maximum field width. This width specifies the maximum number of characters to match, so you must leave room for the '\0' terminator.
It is possible that the first character in the input stream is a '\n'. In this case, scanf() would return a value of 0, since there were no matches before encountering the newline. But, nothing would be stored in s, so you may have undefined behavior. To avoid this, you can call scanf() first using the %*[\n] conversion specifier, discarding any leading '\n' characters.
After the string has been read, there will be additional characters in the input stream. At least a '\n' is present, and possibly more characters if the user entered more than the maximum field width specifies. You might then want to discard these extra characters so that they don't interfere with further inputs. The code below includes a loop to do this operation.
The first call to scanf() will consume all newline characters in the input stream until a non-newline character is encountered. While I believe that the second call to scanf() should always be successful, it is good practice to always check the return value of scanf() (which is the number of successful assignments made). I have stored this value in result, and check it before printing the string. If scanf() returns an unexpected result, an error message is printed.
It is better, and easier, to use fgets() to read entire lines. You must remember that fgets() keeps the trailing newline, so you may want to remove it. There is also a possibility that the user will enter more characters than the buffer will store, leaving the remaining characters in the input stream. You may want to remove these extra characters before prompting for more input.
Again, you should check the return value of fgets(); this function returns a pointer to the first element of the storage buffer, or a NULL pointer in the event of an error. The code below replaces any trailing newline character in the string, discards extra characters from the input stream, and prints the string only if the call to fgets() was successful. Otherwise, an error message is printed.
#include <stdio.h>
int main(void)
{
char s[30];
int result;
printf("Please enter a line of input:\n");
scanf("%*[\n]"); // throw away leading '\n' if present
result = scanf("%29[^\n]", s); // match up to 29 characters, excluding '\n'
/* Clear extra characters from input stream */
int c;
while ((c = getchar()) != '\n' && c != EOF)
continue; // discard extra characters
if (result == 1) {
puts(s);
} else {
fprintf(stderr, "EOF reached or error in scanf()\n");
}
printf("Please enter a line of input:\n");
char *ps = fgets(s, 30, stdin); // keeps '\n' character
if (ps) {
while (*ps && *ps != '\n') {
++ps;
}
if (*ps) { // replace '\n' with '\0'
*ps = '\0';
} else {
while ((c = getchar()) != '\n' && c != EOF)
continue; // discard extra characters
}
puts(s);
} else {
fprintf(stderr, "EOF reached or error in fgets()\n");
}
return 0;
}
Note that these two methods of getting a line of input are not exactly equivalent. The scanf() method, as written here, does not accept an empty line (i.e., a line consisting of only the '\n' character), but does accept lines consisting of other whitespace characters. The fscanf() method will accept an empty line as input.
Also, if it is acceptable to ignore leading whitespace characters, it would be simpler to follow the recommendation given by Jonathan Leffler in the comments to use only a single call to scanf():
result = scanf(" %29[^\n]", s);
This will ignore leading whitespace characters, including newlines.
Do not use scanf() or gets() function — use fgets() instead. But for the above question please find the answer.
int main() {
char a[30];
scanf ("%29[^\n]%*c", name);
printf("%s\n", a);
return 0;
}
Its also highly recommended like I told in the beginning to use fgets() instead. We clearly do not understand the weird requirement. I would have used the fgets() to read the character.
fgets(a, size(a), stdin);

Changing the scanf() delimiter

My objective is to change the delimiter of scanf to "\n".
I tried using scanf("%[^\n]s",sen); and works fine for single inputs.
But when i put the same line inside a for loop for multiple sentences it gives me garbage values.
Does anyone know why?
Here's my code:
char sen[20];
for (i=0;i<2;i++)
{
scanf("%[^\n]s",sen);
printf("%s\n",sen);
}
Consider this (C99) code:
#include <stdio.h>
int main(void)
{
char buffer[256];
while (scanf("%255[^\n]", buffer) == 1)
printf("Found <<%s>>\n", buffer);
int c;
if ((c = getchar()) != EOF)
printf("Failed on character %d (%c)\n", c, c);
return(0);
}
When I run it and type in a string 'absolutely anything with spaces TABTABtabs galore!', it gives me:
Found <<absolutely anything with spaces tabs galore!>>
Failed on character 10 (
)
ASCII (UTF-8) 1010 is newline, of course.
Does this help you understand your problem?
It works in this case (for a single line) but if I want to take multiple lines of input into an array of arrays then it fails. And I don't get how scanf returns a value in your code?
There are reasons why many (most?) experienced C programmers avoid scanf() and fscanf() like the plague; they're too hard to get to work correctly. I'd recommend this alternative, using sscanf(), which does not get the same execration that scanf() and fscanf() do.
#include <stdio.h>
int main(void)
{
char line[256];
char sen[256];
while (fgets(line, sizeof(line), stdin) != 0)
{
if (sscanf(line, "%255[^\n]", sen) != 1)
break;
printf("Found <<%s>>\n", sen);
}
int c;
if ((c = getchar()) != EOF)
printf("Failed on character %d (%c)\n", c, c);
return(0);
}
This reads the line of input (using fgets() which ensures no buffer overflow (pretend that the gets() function, if you've heard of it, melts your computer to a pool of metal and silicon), then uses sscanf() to process that line. This deals with newlines, which are the downfall of the original code.
char sen[20];
for (i=0;i<2;i++)
{
scanf("%[^\n]s",sen);
printf("%s\n",sen);
}
Problems:
You do not check whether scanf() succeeded.
You leave the newline in the buffer on the first iteration; the second iteration generates a return value of 0 because the first character to read is newline, which is the character excluded by the scan set.
The gibberish you see is likely the first line of input, repeated. Indeed, if it were not for the bounded loop, it would not wait for you to type anything more; it would spit out the first line over and over again.
Return value from scanf()
The definition of scanf() (from ISO/IEC 9899:1999) is:
§7.19.6.4 The scanf function
Synopsis
#include <stdio.h>
int scanf(const char * restrict format, ...);
Description
2 The scanf function is equivalent to fscanf with the argument stdin interposed
before the arguments to scanf.
Returns
3 The scanf function returns the value of the macro EOF if an input failure occurs before
any conversion. Otherwise, the scanf function returns the number of input items
assigned, which can be fewer than provided for, or even zero, in the event of an early
matching failure.
Note that when the loop in my first program exits, it is because scanf() returned 0, not EOF.
%[^\n] leaves the newline in the buffer. %[^\n]%*c eats the newline character.
In any case, %[^\n] can read any number of characters and cause buffer overflow or worse.
I use the format string %*[^\n]%*c to gobble the remainder of a line of input from a file. For example, one can read a number and discard the remainder of the line by %d%*[^\n]%*c. This is useful if there is a comment or label following the number, or other data that is not needed.
char sen[20];
for (i=0;i<2;i++)
{
scanf("%[^\n]s",sen);
printf("%s\n",sen);
getchar();
}
Hope this helps ... actually "\n" remains in stream input buffer... Ee need to flush it out before scanf is invoked again
I know I am late, but I ran into same problem after testing C after a long time.
The problem here is the new line is considered as input for next iteration.
So, here is my solution, use getchar() to discard the newline the input stream:
char s[10][25];
int i;
for(i = 0; i < 10; i++){
printf("Enter string: ");
scanf("%s", s[i]);
getchar();
}
Hope it helps :)
While using scanf("%[^\n]", sen) in a loop, the problem that occurs is that the \n stays within the input buffer and is not flushed. As a result next time, when the same input syntax is used, it reads the \n and considers it as a null input. A simple but effective solution to address this problem is to use:
char sen[20];
for (i=0;i<2;i++)
{
scanf("%[^\n]%*c",sen);
printf("%s\n",sen);
}
%*c gets rid of the \n character in the input buffer.

Resources