fscanf reading newline character - c

I have been slowly tracking down my error for my program. I have narrowed it down to this.
I have a user input
fscanf(stdin, "%c %c %d", &car, &dir, &amount);
the first time I access it it works fine, correctly reading in the values. The second time in the loop it reads a \n into car instead of the char I give it. it then reads what should have been in car into dir. amount reads correctly. As car is passed to other functions for counting I eventually end up with a segfault.
Is it reading in the \n from the previous line or something?

The "%c" conversion specifier does not do the usual whitespace trimming.
Try adding a space before the first conversion specifier
if (fscanf(stdin, " %c %c %d", &var, &dir, &amount) != 3) { /* error */ }
Or, maybe better, read a full line and parse it within your program
char buf[1000];
fgets(buf, sizeof buf, stdin);
parse(buf);

Related

What is the use of scanf("\n"); statement before scanf("%[^\n]%*c", s)?

What is the use of scanf("\n"); statement before scanf("%[^\n]%*c", s) ?
int main()
{
char ch;
char str [100];
char s[100];
scanf("%c",&ch);
printf("%c",ch);
scanf("%s",&str);
printf("\n%s",str);
scanf("\n"); // <<< what is the purpose of this line
scanf("%[^\n]%*c",s);
printf("\n%s",s);
return 0;
}
So what is the use of scanf("\n"); statement before scanf("%[^\n]%*c", s) ?
What is the use of scanf("\n");
The true answer is probably that the original author of this code was flailing, desperately trying to get scanf to work, despite scanf's various foibles.
Other evidence that the original author was having problems:
scanf("%c", &ch);
When reading individual characters, the %c often does not work as expected or as desired. Most of the time, at least in code like this, it is necessary to add a space, like this: " %c".
scanf("%[^\n]%*c", s);
This line, also, is difficult to understand. It is attempting to read one full line of text, a task which scanf is not well-suited for.
Overall the code appears to be attempting to read one single character, followed by one string (not containing whitespace), followed by one full line of text (possibly containing whitespace).
Given its shortcomings (and scanf's shortcomings), I'd say it's not even worth trying to figure out what the original code will do. A considerably cleaner way of accomplishing this task (still using scanf) would be
if(scanf(" %c", &ch) != 1) exit(1);
printf("%c\n",ch);
if(scanf("%99s", str) != 1) exit(1);
printf("%s\n", str);
if(scanf(" %99[^\n]", s) != 1) exit(1);
printf("%s\n", s);
Note these changes:
checking return value of scanf
extra space in " %c", as mentioned
%99s instead of plain %s, to avoid array overflow
no & before str with %s
extra space with %[…] also
length modifier 99 with %[…] also
no %*c after %[…]
(cosmetic/stylistic) printing \n at the end of each line
If you're trying to do anything at all fancy, it's often much easier to just skip scanf, and go with more powerful techniques. I might use something like this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char chbuf[5];
char ch;
char str [100];
char s[100];
printf("enter a character:\n");
if(fgets(chbuf, 5, stdin) == NULL) exit(1);
ch = *chbuf;
printf("%c\n", ch);
printf("enter a string:\n");
if(fgets(str, 100, stdin) == NULL) exit(1);
str[strcspn(str, "\n")] = 0; /* strip \n */
printf("%s\n", str);
printf("enter a line:\n");
if(fgets(s, 100, stdin) == NULL) exit(1);
s[strcspn(s, "\n")] = 0;
printf("%s\n", s);
}
This simply used fgets to read all input, one line at a time. To fetch a single character, it then grabs the first character of a short line. (Also it's printing explicit prompts, since that helps to avoid confusion.)
One small drawback of fgets is that it always leaves the \n in the buffer. I've used a common albeit somewhat obscure trick to strip it back off; see this question for an explanation.
This modified program works, although it is different from the original in one significant respect: it will allow whitespace in the first string read as well as the second.
Also, the modified program insists that the three inputs be on three separate lines, while the original would have accepted them all on the same line (or on two lines, or on three lines). Whether that is an improvement or a disimprovement, I can't say. :-)
If you want to limit yourself to a subset of scanf's full complexity, using simple invocations of it for the simple uses it's well-suited for, and avoiding it for the more complicated problems that it's dreadfully painful to use for, you might read the suggestions at this answer.
After this incorrect call of scanf
scanf("%s",&str);
where the second parameter shall be
scanf("%s",str);
the input buffer can contain the new line character '\n' and the next call of scanf
scanf("%[^\n]%*c",s);
can read as a result an empty string.
So this call
scanf("\n");
is an attempt to remove the new line character from the input buffer.
However it will be better just to write
scanf(" %[^\n]%*c",s);
See the leading space in the format string. It allows to skip white space characters in the input buffer.

Behavior of C scanf() formatting

Disclaimer. I've seen tons of questions including almost the exact same code snippets, but none seem to answer this question.
For an entry level CS class we are tasked with making a simple program that takes ID, name and age input from a user and saves it to a file. This was simple enough and I got it working pretty quick. The problem is, to get one part, the name input, working properly, I had to "cheat" my way around a problem I met.
The code snippet in question.
int id, age;
char name[40]={0};
printf("ID: ");
scanf("%i",&id);
printf("Name: ");
scanf("%*c");
scanf("%[^\n]%*c",name);
printf("Age: ");
scanf("%i",&age);
This works fine. But this line annoys me; scanf("%*c"); Its only purpose is disposing of a '\n' character lurking in the stream, probably from the previous input. For some reason I feel like this is cheating or that I'm doing something wrong if I have to use this workaround. Any tips appreciated.
But this line annoys me; scanf("%*c"); Its only purpose is disposing
of a '\n' character lurking in the stream, probably from the previous
input.
scanf() is pretty heavyweight for reading a single character. I would typically go with getchar() for that, and just ignore the result if you don't care what it is.
For your particular case, however, I would go with the suggestion made by #OlafDietsche in comments: insert a space (or a newline or tab) at the beginning of the format string for the next scanf:
scanf(" %[^\n]%*c",name);
That will match any run of zero or more whitespace characters, and thus will eat up your newline, plus any subsequent blank lines and any leading whitespace on the next line that has any non-whitespace. That's the standard behavior for most other field directives anyway, which is why you don't have the same issue with your numeric fields, but it is intentionally not done automatically for %[ and %c fields, so that these can read and return whitespace.
That also means that you don't need to explicitly consume the newline at the end of the name line, either ...
scanf(" %[^\n]",name);
... because it will be consumed automatically by the %i directive in the subsequent scanf() call.
Consider using fget() to read a line of user input #Barmar, then parse.
char buffer[100];
int id, age;
char name[40]={0};
printf("ID: ");
fgets(buffer, sizeof buffer, stdin);
sscanf(buffer, "%i", &id);
printf("Name: ");
fgets(buffer, sizeof buffer, stdin);
sscanf(buffer, "%[^\n]", name);
printf("Age: ");
fgets(buffer, sizeof buffer, stdin);
sscanf(buffer, "%i", &age);
As one's skills improve, add error checking.
printf("ID: ");
if (fgets(buffer, sizeof buffer, stdin) == NULL) Handle_end_of_file();
if (sscanf(buffer, "%i",&id) != 1) Handle_non_numeric_input();
// also research strtol()
printf("Name: ");
if (fgets(buffer, sizeof buffer, stdin) == NULL) Handle_end_of_file();
if (sscanf(buffer, " %99[^\n]",name) != 1) Handle_space_only_name();
// Later, additional code to detect excessively long name

scanf not getting called

I'm trying to read a whole line using scanf multiple times and for some reasons it only works the first time.
The second time the loop runs the compiler ignores the scanf function
Here is my code:
#include <stdio.h>
int main()
{
char msg[100];
char to[100];
while (1)
{
printf("[]:Msg to ? :");
scanf("%s", to);
printf("[]:Msg: ");
scanf("%99[^.]", msg);
printf("Sending %s\n", msg);
}
return 0;
}
And this is the output Im given:
[]:Msg to ? :Him []:Msg: Hello mister him!. Sending Hello mister
him! []:Msg to ? :[]:Msg:
And here I was expecting to be able to change the variable to ...
Adding a space before %s for some reason has no effect here
The problem is here:
scanf("%99[^.]", msg);
This statement reads up to 99 characters, but only until the next non-matching character. Now if you put
Hello mister him!.
into the input buffer, you indeed have
"Hello mister him!.\n"
in the stdin input stream buffer. Now, the scanf processes everything up to (but not including) the dot, so the dot and the newline remains in the input buffer. The next call to scanf()
scanf("%s", to);
now fetches the dot and the newline from the output buffer, which automatically concludes the next line to read. Now the input buffer is empty and the following scanf waits for the next message.
To fix this, you can skip the dot and the newline like this:
scanf("%99[^.]", msg);
getchar(); // Pacman (Eat the dot)
and in the other scanf use
// scanf(" %s", to); // Skip the preceding newline
(this is unnecessary, as H.S. pointed out)
Please note, that the case of an input message >99 chars is not handled properly yet.
If you wants to read a whole line using scanf you can use %[^\n] instead of %99[^.]. And make sure to add a getchar() if any 'enter' is pressed just before scanning with %[^\n].
The changes showed in the code bellow may be useful:
while (1)
{
printf("[]:Msg to ? :");
scanf("%[^\n]", to);
getchar();
printf("[]:Msg: ");
scanf("%[^\n]", msg);
getchar();
printf("Sending %s\n", msg);
}

Confused about GCC and scanf in C

I am using GCC to compile my C code.
My second scanf is not stopping to get the input.
It only reads in the first scanf and prints the two statements, one with what I entered in string and the other is just blank.
int main (void) {
setvbuf(stdout, NULL, _IONBF, 0);
char string[25] = {'\0'};
char c;
scanf(" %s", string);
scanf(" o%c", &out);
printf("Input is : %s \n\n", string);
printf("Out is: %c", out);
return 0;
}
Instead of getting
Input is whatever I typed and a prompt to enter a char for out
I got output as shown below
Input is : whatever i typed
Out is:
The program terminates. Can someone help. I've done some research and tried to put a space before %c for out and for string and still nothing happened.
You haven't defined out. And c is unused here. Having said that
Change
scanf(" o%c", &out); //What is that o in here? Is it a typo?
to
scanf(" %c", &out);
If your terminal uses line-buffered input
scanf(" %s", string);
can read the input till the first white-space. So the input buffer from the white-space is unused which is available for the next scanf which automatically starts reading from the buffer. So if you enter a string with spaces, the white-space will be assigned to the character out in your case
Change first scanf like below to clear the buffer:
if( scanf(" %s", string) == 1)
{
while(getchar()!='\n')
continue;
}
Also you might wish to replace
scanf(" %s", string);
with
fgets(string,25,stdin);
/* Use 26 if you actually wish to have max 25 characters
* ie char string[26]={'\0'}
*/
fgets has the advantage that it can read the white spaces and the newline charcter '\n' and it will automatically trim the output in case of an overflow.

Reading newline from previous input when reading from keyboard with scanf()

This was supposed to be very simple, but I'm having trouble to read successive inputs from the keyboard.
Here's the code:
#include <string.h>
#include <stdio.h>
int main()
{
char string[200];
char character;
printf ("write something: ");
scanf ("%s", string);
printf ("%s", string);
printf ("\nwrite a character: ");
scanf ("%c", &character);
printf ("\nCharacter %c Correspondent number: %d\n", character, character);
return 0;
}
What is happening
When I enter a string (e.g.: computer), the program reads the newline ('\n') and puts it in character. Here is how the display looks like:
write something: computer
computer
Character:
Correspondent number: 10
Moreover, the program does not work for strings with more than one word.
How could I overcome these problems?
First scanf read the entered string and left behind \n in the input buffer. Next call to scanf read that \n and store it to character.
Try this
scanf (" %c", &characte);
// ^A space before %c in scanf can skip any number of white space characters.
Program will not work for strings more than one character because scanf stops reading once find a white space character. You can use fgets instead
fgets(string, 200, stdin);
OP's first problem is typically solved by prepending a space to the format. This will consume white-space including the previous line's '\n'.
// scanf("%c", &character);
scanf(" %c", &character);
Moreover, the program does not work for strings with more than one word. How could I overcome these problems?
For the the 2nd issue, let us go for a more precise understanding of "string" and what "%s" does.
A string is a contiguous sequence of characters terminated by and including the first null character. 7.1.1 1
OP is not entering a string even though "I enter a string (e.g.: computer)," is reported. OP is entering a line of text. 8 characters "computer" followed by Enter. There is no "null character" here. Instead 9 char "computer\n".
"%s" in scanf("%s", string); does 3 things:
1) Scan, but not save any leading white-space.
2) Scan and save into string any number of non-white-space.
3) Stop scanning when white-space or EOF reached. That char is but back into stdin. A '\0' is appended to string making that char array a C string.
To read a line including spaces, do not use scanf("%s",.... Consider fgets().
fgets(string, sizeof string, stdin);
// remove potential trailing \r\n as needed
string[strcspn(string, "\n")] = 0;
Mixing scanf() and fgets() is a problem as calls like scanf("%s", string); fgets(...) leave the '\n' in stdin for fgets() to read as a line consisting of only "\n". Recommend instead to read all user input using fgets() (or getline() on *nix system). Then parse the line read.
fgets(string, sizeof string, stdin);
scanf(string, "%c", &character);
If code must user scanf() to read user input including spaces:
scanf("%*[\n]"); // read any number of \n and not save.
// Read up to 199 `char`, none of which are \n
if (scanf("%199[^\n]", string) != 1) Handle_EOF();
Lastly, code should employ error checking and input width limitations. Test the return values of all input functions.
What you're seeing is the correct behavior of the functions you call:
scanf will read one word from the input, and leave the input pointer immediately after the word it reads. If you type computer<RETURN>, the next character to be read is the newline.
To read a whole line, including the final newline, use fgets. Read the documentation carefully: fgets returns a string that includes the final newline it read. (gets, which shouldn't be used anyway for a number of reasons, reads and discards the final newline.)
I should add that while scanf has its uses, using it interactively leads to very confusing behavior, as I think you discovered. Even in cases where you want to read word by word, use another method if the intended use is interactive.
You can make use of %*c:
#include <string.h>
#include <stdio.h>
int main()
{
char string[200];
char character;
printf ("write something: ");
scanf ("%s%*c", string);
printf ("%s", string);
printf ("\nwrite a character: ");
scanf ("%c%*c", &character);
printf ("\nCharacter %c Correspondent number: %d\n", character, character);
return 0;
}
%*c will accept and ignore the newline or any white-spaces
You cal also put getchar() after the scanf line. It will do the job :)
The streams need to be flushed. When performing successive inputs, the standard input stream, stdin, buffers every key press on the keyboard. So, when you typed "computer" and pressed the enter key, the input stream absorbed the linefeed too, even though only the string "computer" was assigned to string. Hence when you scanned for a character later, the already loaded new line character was the one scanned and assigned to character.
Also the stdout streams need to be flushed. Consider this:
...
printf("foo");
while(1)
{}
...
If one tries to execute something like this then nothing is displayed on the console. The system buffered the stdout stream, the standard output stream, unaware of the fact it would be encounter an infinite loop next and once that happens, it never gets a chance to unload the stream to the console.
Apparently, in a similar manner whenever scanf blocks the program and waits on stdin, the standard input stream, it affects the other streams that are buffering. Anyway, whatsoever may be the case it's best to flush the streams properly if things start jumbling up.
The following modifications to your code seem to produce the desired output
#include <string.h>
#include <stdio.h>
int main()
{
char string[200];
char character;
printf ("write something: ");
fflush(stdout);
scanf ("%s", string);
fflush(stdin);
printf ("%s", string);
printf ("\nwrite a character: ");
fflush(stdout);
scanf ("%c", &character);
printf ("\nCharacter %c Correspondent number: %d\n", character, character);
return 0;
}
Output:
write something: computer
computer
write a character: a
Character a Correspondent number: 97

Resources