I wrote the following code:
int N;
scanf("%d", &N);
int i;
for (i = 0; i < N; i++) {
char line[LINE_MAX];
if (fgets(line, LINE_MAX, stdin) != NULL) {
// do stuff with line here
printf("%c - %c\n", line[0], line[1]);
}
}
I have an input file which has the number of lines it has, and then that number of lines followed which I want to process. So I read in the number of lines into N. After that, I use fgets to get the line to be able to process it.
However, fgets does not seem to wait for a stdin the first time. I always get output of -, and then it waits for input. Meaning, the first iteration of the loop, it is not waiting for standard input at fgets and just prints out two empty characters separated by - as my printf does.
Why is that? How can I get fgets to wait for input each time? I feel like it is a threading issue.
You can place a call to fflush() just after the scanf() like this:
int N;
scanf("%d", &N);
fflush (stdin);
int i;
... (rest of code)...
So the newline character ges erased from the stdin buffer and the next fgets() will stop to ask for input.
As geekosaur said, you are not handling the newline left behind by scanf. You can modify your scanf format string to take it into account:
scanf("%d *[^\n]", &N);
*[^\n] says to ignore everything after your integer input that isn't a newline, but don't do anything with the newline (skip it).
Test program output:
emulawsk#cs:~/testing$ ./test2
3
13
1 - 3
26
2 - 6
59
5 - 9
It has nothing to do with threading. scanf() reads exactly what you ask it to; it's leaving everything else unread, notably the newline following the data. (You also aren't dealing with the possibility that the user didn't type what you intended.)
If you want to do line oriented input, use fgets(). Don't use scanf() and hope the system can magically intuit that you want to ignore what you didn't read.
Related
This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
Closed 2 years ago.
This question might look stupid but I am not used to work with C and I'm losing my mind here not knowing what is wrong.
Basically what I want is to get a number from the user, then a string, the user may write whatever he feels like, I want to keep just the first caracter of that string.
My code is the following:
#include <stdio.h>
int main()
{
int b, n;
char frase [2];
scanf("%d", &n);
fgets(frase, 2, stdin);
puts(frase);
return 0;
}
My problem is, after the fgets the program stops, no matter what I have after it, it only stops, no error messages or anything. What is happening?
What is happening?
Your code will:
For an input 123 abc:
Store 123 in n, store the space in frase followed by a null byte. Then it will print that single space and end its execution with no errors.
For an input 123 Enter abc:
Store 123 in n and store in frase the newline character \n added to the buffer when you pressed Enter, followed by a null byte, next it will print that \n and end its execution with no errors.
So it doesn't just stop, it does what it's supposed to do.
What you shoud do, to make your code more robust, is to also parse the number with fgets, and convert it with sscanf or strtol:
int n = 0;
char buffer[20];
char frase[2];
fgets(buffer, sizeof buffer, stdin);
if(sscanf(buffer, "%d", &n) != 1){
//value not parsed
}
fgets(frase, sizeof frase, stdin);
puts(frase);
Using scanf to parse inputs is rarely, if ever, a good ideia.
The fgets is grabbing the newline character that is in the buffer after scanf reads the int. Putting a getchar() before your fgets should fix the problem.
This question already has answers here:
What is the effect of trailing white space in a scanf() format string?
(4 answers)
Why is the gets function so dangerous that it should not be used?
(13 answers)
Closed 2 years ago.
I have an unusual problem regarding the code below.
void Menu()
{
bool end = 0;
int n;
while (!end)
{
scanf("%d", &n);
switch(n)
{
case 1:
my_strlen_show();
break;
//other irrelevant cases 2-6
case 7:
end = 1;
break;
default:
printf("ERROR");
break;
}
}
}
int my_strlen(const char *str)
{
int count = 0;
for (; *str != '\0' ; str++)
{
count++;
}
return count;
}
void my_strlen_show()
{
char tab[1000];
printf("\n\nEnter a sentence: ");
gets(tab);
gets(tab);
printf("\nWritten sentence has %d characters.\n\n", my_strlen(tab));
return;
}
I have no idea why I have to write gets(tab) twice to get the program to work properly. When I use it once, my_strlren_show() function executes instantly and shows that the sentence has 0 characters. I am aware that I can use other methods such as a scanf() function inside a for loop, but I am curious why this method works in a peculiar way.
Can anyone explain why that is the case? I would be very thankful.
Do not use gets(). Its dangerous unsafety has earned it the dubious distinction of belonging to a very small set of functions that have been withdrawn from the C language standard.
However, you would probably experience the same issue if you changed to fgets:
fgets(tab, sizeof(tab), stdin);
The issue is that gets() and fgets() read through the end of the current line (or until the buffer is filled in the case of fgets()). The preceding scanf() consumed only the bytes through the end of a decimal integer, leaving the rest of that line on the input stream, waiting to be read. That includes at least a newline marking the end of the line. That has to be consumed before the wanted input can be read with fgets() or gets(). One way to accomplish that would be:
if ((scanf("%*[^\n]") == EOF) || (getchar() == EOF)) {
// handle end-of-file or I/O error ...
}
The scanf reads and discards any characters preceding the next newline, and, supposing that the end of the file is not reached and no I/O error occurs, the getchar() consumes the newline itself.
Your first scanf only reads a single integer from stdin. When you press enter after inputting the integer, a newline (\n) is sent to the stdin, which just stays there - waiting to be picked up by the next function reading from stdin.
The next gets then reads this newline and instantly returns. So you needed another gets to actually read the input.
With that said, you should never even use gets in the first place - it's a deprecated function. On top of that, consider using fgets for reading input. scanf is really an input parsing function, not a reading function. It only reads what it can parse, and leaves everything else in the stdin.
If you still decide to go the scanf route, you should consume the newline on the first input using "%d\n" - not only that, you must also check the return value for scanf, it returns the number of values it was able to parse.
Now the next fgets call won't have to consume the left over newline. It'll wait for another line of user input (note that the newline will be included in the buffer fgets reads into)-
char tab[1000];
printf("\n\nEnter a sentence: ");
if (fgets(tab, 1000, stdin) == NULL)
{
// handle error during reading
return;
}
// tab now has the user input, delimited with a `\n`
// if you want to get rid of this newline - use `strcspn`
tab[strcspn(name, "\n")] = 0
Docs on strcspn
I would however, recommend you to go the full fgets route and do the integer parsing with sscanf.
int n;
char buff[4096];
if (fgets(buff, 4096, stdin) == NULL)
{
// handle error during reading
return;
}
if (sscanf(tab, "%d", &n) != 1)
{
// parsing failed - sscanf should've parsed exactly 1 value
// handle error
return;
}
// use n here
Here's a full guide on how to move away from scanf - which will mention this specific problem.
I got this code:
#include <stdio.h>
int main(void){
char ordet;
int again = 1;
while(again == 1){
printf("Write a name: \n");
while (ordet!='\n'){
scanf("%c",&ordet);
if('A'<= ordet && ordet <='W')
{
printf("%c",ordet+3);
}
else if('W'<=ordet){
printf("%c", ordet-22);
}
}
printf("\nDo you want to write a new name? 1/0");
scanf("%d", &again);
}
return 0;
}
It runs fine the first time but as soon as you press 1 to write a new name you never get the chance to write it, it just keeps asking "Do you want to write a new name?" and ignores "Write a name:". I have tested with fflush(stdin), != EFO and space infront of %c but nothing works. How could I fix this since I really have no idea, started out with C a few days ago.
while (ordet!='\n'){
ordet is used without initialization here. Not quite UB (if your implementation uses unsigned char or signed char has no trap-representations), but bad enough.
scanf("%c",&ordet);
The above line is the only line potentially setting ordet. Please take note that the loop starting with it is only entered when ordet is not '\n'.
You probably want to reset it before entering the inner loop, or use a do-while-loop.
Actually, changing both loops to do-while-loops would be good.
scanf("%d", &again);
The above line reads a number from beginning of stdin, but leaves the newline.
This must be dealt with by consuming all whitespace on repeat.
Luckily, that's easily done as the inner loop ignores whitespace.
Change "%c" to " %c".
Also, all your scanf-invocations can fail. Check them!
There are 2 problems with your code:
ordet is not initialized before its first usage. It is undefined behavior.
You do not reset ordet anywhere outside the inner loop. That is, once ordet becomes equal to \n, the body of the inner loop is never executed again.
To fix it, you can write something like ordet = 0 before inner loop. And don't forget to skip new line character that is left in the buffer after reading again variable.
All input you write in the console from the keyboard is placed in a buffer, scanf reads from this buffer however if there are more characters in the buffer than what your format specifier specifies those characters will remain in the buffer.
e.g.
scanf( "%d", &n );
when you enter a numerical value 100 and press ENTER afterwards, the ENTER character is placed in the buffer as well "100\n" when you do scanf on the buffer (stdin) the 100 is extracted from the buffer but the \n remains.
Next time you write scanf("%d", &n ); the \n is still in there and will not be read by %d since it is not a %d number.
IMO the best way to handle this is instead to read from the keyboard using fgets, then after the content has been read use sscanf to extract the information you want:
char buffer[128];
fgets( buffer, sizeof(buffer), stdin );
sscanf( buffer, "%d", &n );
you also then can have additional error checks:
if (fgets( buffer, sizeof(buffer), stdin ) != NULL )
{
if (sscanf( buffer, "%d", &n ) ==1)
{
...
}
}
now to your code:
if you want to read character by character from the keyboard use fgetc() not scanf()
Use the C-runtime function isalpha()/toupper() to recognize a character.
In C, a character is an int, that is why most functions like fgetc return an int and not a char.
In general I would recommend using fgets() instead of reading one character at a time.
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.
I wrote the following code:
int N;
scanf("%d", &N);
int i;
for (i = 0; i < N; i++) {
char line[LINE_MAX];
if (fgets(line, LINE_MAX, stdin) != NULL) {
// do stuff with line here
printf("%c - %c\n", line[0], line[1]);
}
}
I have an input file which has the number of lines it has, and then that number of lines followed which I want to process. So I read in the number of lines into N. After that, I use fgets to get the line to be able to process it.
However, fgets does not seem to wait for a stdin the first time. I always get output of -, and then it waits for input. Meaning, the first iteration of the loop, it is not waiting for standard input at fgets and just prints out two empty characters separated by - as my printf does.
Why is that? How can I get fgets to wait for input each time? I feel like it is a threading issue.
You can place a call to fflush() just after the scanf() like this:
int N;
scanf("%d", &N);
fflush (stdin);
int i;
... (rest of code)...
So the newline character ges erased from the stdin buffer and the next fgets() will stop to ask for input.
As geekosaur said, you are not handling the newline left behind by scanf. You can modify your scanf format string to take it into account:
scanf("%d *[^\n]", &N);
*[^\n] says to ignore everything after your integer input that isn't a newline, but don't do anything with the newline (skip it).
Test program output:
emulawsk#cs:~/testing$ ./test2
3
13
1 - 3
26
2 - 6
59
5 - 9
It has nothing to do with threading. scanf() reads exactly what you ask it to; it's leaving everything else unread, notably the newline following the data. (You also aren't dealing with the possibility that the user didn't type what you intended.)
If you want to do line oriented input, use fgets(). Don't use scanf() and hope the system can magically intuit that you want to ignore what you didn't read.