I am trying to create a program that repeatedly asks the user for input. However, in this case, the program just keeps printing "Enter your input" until it crashes after I enter something for the first time.
#include <stdio.h>
int main() {
while (1) {
char input[100];
printf("Enter a input: ");
scanf("%[^\n]s", input);
}
}
In:
scanf("%[^\n]s", input);
There are 2 problems:
The s is not part of that specific specifier, it should be only %[^\n].
That specifier leaves the \n newline character in the input buffer.
Your cycle will enter an infinite loop because there is always something to read there, but it's something that must not be parsed and should remain in the buffer.
A simple way to get rid of it is to place a space before the specifier:
scanf(" %[^\n]", input);
^
|
You are asking scanf() to read everything up to, but not including, the line break that ends the user's input.
So, the line break stays in the input buffer. Then on subsequent calls to scanf(), the line break is still not read from the input buffer, preventing scanf() from reading any new input.
You need to read that line break from the input buffer so that a subsequent call to scanf() can read the user's next input.
Related
This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
Closed 6 years ago.
I have this block of code (functions omitted as the logic is part of a homework assignment):
#include <stdio.h>
int main()
{
char c = 'q';
int size;
printf("\nShape (l/s/t):");
scanf("%c",&c);
printf("Length:");
scanf("%d",&size);
while(c!='q')
{
switch(c)
{
case 'l': line(size); break;
case 's': square(size); break;
case 't': triangle(size); break;
}
printf("\nShape (l/s/t):");
scanf("%c",&c);
printf("\nLength:");
scanf("%d",&size);
}
return 0;
}
The first two Scanf's work great, no problem once we get into the while loop, I have a problem where, when you are supposed to be prompted to enter a new shape char, it instead jumps down to the printf of Length and waits to take input from there for a char, then later a decimal on the next iteration of the loop.
Preloop iteration:
Scanf: Shape. Works Great
Scanf: Length. No Problem
Loop 1.
Scanf: Shape. Skips over this
Scanf: length. Problem, this scanf maps to the shape char.
Loop 2
Scanf: Shape. Skips over this
Scanf: length. Problem, this scanf maps to the size int now.
Why is it doing this?
scanf("%c") reads the newline character from the ENTER key.
When you type let's say 15, you type a 1, a 5 and then press the ENTER key. So there are now three characters in the input buffer. scanf("%d") reads the 1 and the 5, interpreting them as the number 15, but the newline character is still in the input buffer. The scanf("%c") will immediately read this newline character, and the program will then go on to the next scanf("%d"), and wait for you to enter a number.
The usual advice is to read entire lines of input with fgets, and interpret the content of each line in a separate step. A simpler solution to your immediate problem is to add a getchar() after each scanf("%d").
The basic problem is that scanf() leaves the newline after the number in the buffer, and then reads it with %c on the next pass. Actually, this is a good demonstration of why I don't use scanf(); I use a line reader (fgets(), for example) and sscanf(). It is easier to control.
You can probably rescue it by using " %c" instead of "%c" for the format string. The blank causes scanf() to skip white space (including newlines) before reading the character.
But it will be easier in the long run to give up scanf() and fscanf() and use fgets() or equivalent plus sscanf(). All else apart, error reporting is much easier when you have the whole string to work with, not the driblets left behind by scanf() after it fails.
You should also, always, check that you get a value converted from scanf(). Input fails — routinely and horribly. Don't let it wreck your program because you didn't check.
Try adding a space in the scanf.
scanf(" %d", &var);
// ^
// there
This will cause scanf() to discard all whitespace before matching an integer.
Use the function
void seek_to_next_line( void )
{
int c;
while( (c = fgetc( stdin )) != EOF && c != '\n' );
}
to clear out your input buffer.
The '\n' character is still left on the input stream after the first call to scanf is completed, so the second call to scanf() reads it in. Use getchar().
When you type the shape and ENTER, the shape is consumed by the first scanf, but the ENTER is not! The second scanf expects a number so, the ENTER is skipped because is considered a white space, and the scanf waits for a valid input ( a number) that, again, is terminated by the ENTER. Well, the number is consumed, but the ENTER is not, so the first scanf inside the while uses it and your shape prompt is skipped... this process repeats. You have to add another %c in the scanfs to deal with the ENTER key. I hope this helps!
You can also use
scanf("%c%*c", &c);
to read two characters and ignore the last one (in this case '\n')
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
In my program I'm just calculating the costs of things. However, at the end I want a little break at the program asking for the user to just press the Enter button. I supposed getchar() would work here but it doesn't even stop, it just continues to keep printing. I even tried to put a space after the scant formats like scanf("%s ").
So two things how do I stop the program to ask for input at getchar() and how do I make it recognize just a enter button.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char hotels_houses[5];
int houses, hotels, cost;
printf("Enter amount of houses on board: \n");
scanf("%s", hotels_houses);
houses = atoi(hotels_houses);
printf("Enter amount of hotels on board: \n");
scanf("%s", hotels_houses);
hotels = atoi(hotels_houses);
printf("Cost of houses: %d\n", houses);
printf("Cost of hotels: %d\n", hotels);
cost = (houses *40) + (hotels * 115);
puts("Click enter to calculate total cash ");
getchar(); /* just a filler */
printf("Total cost: %d\n", cost);
return(0);
}
My best guess is that it is retrieving the remaining newline after the user has entered their input. You can print out the return value to verify. If I'm correct, it'll be "10" or "13" depending on your OS.
You might want to change your program to use getline. There are other examples on how to write a get line at How to read a line from the console in C?
When code calls scanf("%s", ... the program waits for input.
You type "123" and nothing happens yet as stdin is buffered input and waits for a \n thus the system has not given any data to scanf().
Then you type "\n" and "123\n" is given to stdin.
scanf("%s",...) reads stdin and scans optional leading white-space then the non-white space "123". Finally it sees "\n" and puts it back in stdin and completes.
Code calls scanf("%s", ... again. scanf() scans the "\n" as part of its scanning optional leading white-space. Then it waits for more input.
You type "456" and nothing happens yet as stdin is buffered input and waits for a \n thus the system has not given any data to scanf().
Then you type "\n" and "456\n" is given to stdin.
scanf("%s",...) reads stdin and scans optional leading white-space then the non-white space "456". Finally it sees "\n" and puts it back in stdin and completes.
Finally you call getchar() and puff, it reads the previous line's \n from stdin.
So how to do I stop the program to ask for input at getchar() and how do I make it recognize just a enter button.
Best approach: use fgets()
char hotels_houses[5+1];
// scanf("%s", hotels_houses);
fgets(hotels_houses, sizeof hotels_houses, stdin);
houses = atoi(hotels_houses);
...
// scanf("%s", hotels_houses);
fgets(hotels_houses, sizeof hotels_houses, stdin);
hotels = atoi(hotels_houses);
...
puts("Click enter to calculate total cash ");
fgets(bhotels_houses, sizeof hotels_houses, stdin); // do nothing w/hotels_houses
printf("Total cost: %d\n", cost);
Checking for a NULL return value from fgets() is useful to test for a closed stdin.
Using strtol() has error checking advantages over atoi().
I'm new to programming and have been working on an assignment in class. For some strange reason the program keeps printing 2 different printf's on the same line and not giving me a chance to input information
Here is the code:
#include <stdio.h>
#include <stdlib.h>
int main (void)
{ char Name[20];
char cid1[6]="", cid2[6]="", cid3[6]="", cid4[6]="", cid5[6]="", cid6[6]="";
char Description1[21]="", Description2[21]="", Description3[21]="", Description4[21]="", Description5[21]="", Description6[21]="";
int hrs1 = 0, hrs2=0, hrs3=0, hrs4=0, hrs5=0, hrs6=0;
char grade1[2]="",grade2[2]="",grade3[2]="",grade4[2]="",grade5[2]="",grade6[2]="";
printf("Enter Students Name ");
fgets(Name, 20, stdin);
printf("Enter Class ID ");
scanf("%5s", cid1);
printf("Enter Class Description "); // Problem
fgets(Description1, 20, stdin); // here
printf("Enter Class Hours ");
scanf("%d", &hrs1);
printf("Enter Class Grade ");
fgets(grade1, 1, stdin);
printf("%s\n", Name);
printf("%s\n", cid1);
printf("%s\n", Description1);
printf("%d\n", hrs1);
printf("%s\n", grade1);
system("pause");
return 0;
The area marked “Problem here” is where the problem is currently occurring. In stead of prompting for the class description it will skip straight to entering class hours and completely ignore the enter class grade at the bottom.
It prints it as: Enter Class DescriptionEnter Class Hours.
They are trying to teach you the difference between scanf and fgets. And they are probably tricking you by telling you that the Class ID has to be 4 characters.
So if your Class ID is "1234" and you hit Enter after, what ends up in stdin is:
1234\r\n
The %5s format in scanf says to read 5 characters and then move on. So, you read in 1234\r and leave \n in the stdin stream. Then when fgets executes, it reads in the \n and moves on.
From the above on fgets:
Get string from stream
Reads characters from stream and stores them as a C string into str
until (num-1) characters have been read or either a newline or the
end-of-file is reached, whichever happens first.
There is a newline left in the input buffer, from the previous input operation. One way to get rid of it is to read character by character until you've read a '\n'.
You did not consume the newline characters by your scanf calls. As fgets returns when it reads a newline character, it returns immediatelly.
You could change the scanf format string to consume newline characters as follow
scanf("%5s\r\n", cid1);
It seems like you are running this on windows. Windows has issues with flushing its stdin properly. Try using an
fflush(stdin);
after any reads from the console.
This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
Closed 6 years ago.
I have this block of code (functions omitted as the logic is part of a homework assignment):
#include <stdio.h>
int main()
{
char c = 'q';
int size;
printf("\nShape (l/s/t):");
scanf("%c",&c);
printf("Length:");
scanf("%d",&size);
while(c!='q')
{
switch(c)
{
case 'l': line(size); break;
case 's': square(size); break;
case 't': triangle(size); break;
}
printf("\nShape (l/s/t):");
scanf("%c",&c);
printf("\nLength:");
scanf("%d",&size);
}
return 0;
}
The first two Scanf's work great, no problem once we get into the while loop, I have a problem where, when you are supposed to be prompted to enter a new shape char, it instead jumps down to the printf of Length and waits to take input from there for a char, then later a decimal on the next iteration of the loop.
Preloop iteration:
Scanf: Shape. Works Great
Scanf: Length. No Problem
Loop 1.
Scanf: Shape. Skips over this
Scanf: length. Problem, this scanf maps to the shape char.
Loop 2
Scanf: Shape. Skips over this
Scanf: length. Problem, this scanf maps to the size int now.
Why is it doing this?
scanf("%c") reads the newline character from the ENTER key.
When you type let's say 15, you type a 1, a 5 and then press the ENTER key. So there are now three characters in the input buffer. scanf("%d") reads the 1 and the 5, interpreting them as the number 15, but the newline character is still in the input buffer. The scanf("%c") will immediately read this newline character, and the program will then go on to the next scanf("%d"), and wait for you to enter a number.
The usual advice is to read entire lines of input with fgets, and interpret the content of each line in a separate step. A simpler solution to your immediate problem is to add a getchar() after each scanf("%d").
The basic problem is that scanf() leaves the newline after the number in the buffer, and then reads it with %c on the next pass. Actually, this is a good demonstration of why I don't use scanf(); I use a line reader (fgets(), for example) and sscanf(). It is easier to control.
You can probably rescue it by using " %c" instead of "%c" for the format string. The blank causes scanf() to skip white space (including newlines) before reading the character.
But it will be easier in the long run to give up scanf() and fscanf() and use fgets() or equivalent plus sscanf(). All else apart, error reporting is much easier when you have the whole string to work with, not the driblets left behind by scanf() after it fails.
You should also, always, check that you get a value converted from scanf(). Input fails — routinely and horribly. Don't let it wreck your program because you didn't check.
Try adding a space in the scanf.
scanf(" %d", &var);
// ^
// there
This will cause scanf() to discard all whitespace before matching an integer.
Use the function
void seek_to_next_line( void )
{
int c;
while( (c = fgetc( stdin )) != EOF && c != '\n' );
}
to clear out your input buffer.
The '\n' character is still left on the input stream after the first call to scanf is completed, so the second call to scanf() reads it in. Use getchar().
When you type the shape and ENTER, the shape is consumed by the first scanf, but the ENTER is not! The second scanf expects a number so, the ENTER is skipped because is considered a white space, and the scanf waits for a valid input ( a number) that, again, is terminated by the ENTER. Well, the number is consumed, but the ENTER is not, so the first scanf inside the while uses it and your shape prompt is skipped... this process repeats. You have to add another %c in the scanfs to deal with the ENTER key. I hope this helps!
You can also use
scanf("%c%*c", &c);
to read two characters and ignore the last one (in this case '\n')