This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
Closed 6 years ago.
I have written a program that is far too long to copy to this site. But what is needed will be pasted into the website.
Here is the switch statement:
void enterName();
int adminChoice;
printf("\nEnter Numeric Choice: ");
scanf("%d", &adminChoice);
switch(adminChoice)
{
case(1):
{
enterName();
}
}
Here is the actual function:
void enterName()
{
FILE *fp = fopen("/home/matthew/Desktop/BBE.txt", "w");
if (fp == NULL)
{
printf("Error opening file!\n");
exit(1);
}
char comment[100];
printf("Enter, String\n");
fgets(comment, sizeof comment, stdin);
fputs(comment,fp);
}
What happens is the program asks for user input of a string. But does not allow for time to put in a desired string. It just ends the program.
The problem is that scanf() leaves a \n character which terminates the fgets() immediately without reading anything. fgets() would stop reading when it sees a newline character or EOF.
You could use a hacky approach and use a getchar(); right before fetgs() call. Better option is to use fgets() to read the adminChoice (and convert it to integer using sscanf() or strto* functions) as well so that you avoid scanf(). In any case, you always have to watch out for newline character when using fgets().
Related
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.
This question already has answers here:
fflush(stdin) function does not work
(3 answers)
fflush() is not working in Linux
(9 answers)
Why fflush(stdin) does not remove buffer (stdin) [duplicate]
(2 answers)
How to clear input buffer in C?
(18 answers)
Closed 5 years ago.
This is the code which I'm trying to run on my Mac. In this the statement after fflush doesn't work. After fflush the compiler should stop and wait for the user input but it doesn't.
Can anyone tell me why this is happening or is there any other way to do it?
int main()
{
int pos,neg,zero,num;
char ans = 'y';
pos=neg=zero=0;
while(ans == 'y' || ans=='Y')
{
printf("\nEnter a number : ");
scanf("%d",&num);
if(num==0)
zero++;
if(num>0)
pos++;
if(num<0)
neg++;
fflush(stdin);
printf("\nDo you want to continue?\n\n");
scanf("%c",&ans);
}
printf("You entered %d positive numbers\n",pos);
printf("You entered %d negative numbers\n",neg);
printf("You entered %d zeros \n",zero);
return 0;
}
From standard 7.21.5.2
If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes
any unwritten data for that stream to be delivered to the host
environment to be written to the file; otherwise, the behavior is
undefined.
You were having undefined behavior in your code. More clearly, fflush won't work. The most common way to do it would be something as shown below:
int c;
while ((c = getchar()) != '\n' && c != EOF){}
Another solution would be to use (much easier for you but not robust)
scanf(" %c",&ans);
^^
This will make sure all white space is being consumed. This will solve one of the problem that may arise, but not all. (The others arise due to use of scanf and wrong input).
Side note
Also another way to get rid of this problem altogether would be to use fgets or similar to read one line and then use strtol or strtod to get the desired input parsed from the inputted line. scanf is extremely useful for formatted input. The scenario which you will have - it is better to use fgets, there are too many cases with scanf that you have to deal with otherwise.
For wrong input you need to flush the standard input so that you don't have to deal with them again in the next scanf. If you use fgets then you will get the input line from the stdin and then if you can parse it and the input is correct - you go on processing it, else you discard the whole line and wait for the next fgets call.
This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
Closed 5 years ago.
I am aware of scanf() usage and is not encouraged. But I've the problem, where scanf sends the stdin value to the next function stdin. I'm wondering why it's doing like this.
code:
#include <stdio.h>
void ffgets() {
char name[40];
printf("What's your name? ");
if (fgets(name, 40, stdin)) {
printf("Hello %s", name);
}
}
int main(int argc, char **argv) {
int a;
printf("enter a number: ");
int res = scanf("%d", &a);
if (res > 0) {
printf("Valid Integer %d.\n", a);
} else {
printf("It's not a number\n");
}
ffgets();
return 0;
}
Output:
Test case 1:
Why the function doesn't ask for stdin, it just print empty string
./a.out
enter a number: 23
Valid Integer 23.
What's your name? Hello
Test case 2: I entered the string with the special character that is passed name.
./a.out
enter a number: random##¤
It's not a number
What's your name? Hello random##¤
I dont want stdin value from main passed to the function, how to do that?
If you input something that scanf can not match to the format specification then it will stop immediately and leave the input in the input buffer for the next input function.
Also, when using scanf it will not consume the trailing newline in the input buffer, also leaving it for the next input function.
To solve both problems consider using fgets to get the whole line from the input, and then use sscanf to parse the string.
I am aware of scanf() usage and is not encouraged.
This is exactly the issue that comes from scanf() (namely, that input not used by scanf is left in the input buffer, contrary to what the user expected). So, as you seem to already know, the solution is to not use the function.
It's not that hard to make a function to read a complete line of input, and parse an int from there with sscanf() or strtol or friends:
#include <stdio.h>
#include <limits.h>
int getint(void)
{
char buffer[120] = {0}; /* arbitrary limit */
fgets(buffer, 120, stdin);
int a;
if (sscanf(buffer, "%d", &a) == 1) {
return a;
}
return INT_MIN;
}
(Of course INT_MIN is a valid number to enter, so you might want to have some better way of returning errors. And perhaps consider what to do with garbage following the number.)
The reason is that in the first case, the matching input is consumed by scanf() but the newline \n is present in the input buffer. That makes a valid input and terminator for fgets() in the first case.
Related , quoting C11, chapter §7.21.6.2
Trailing white space (including new-line characters) is left unread unless matched by a
directive. [....]
In the second case, the matching failure happens, which makes the entire input to be available in the input buffer at the time of fgets() call, so fgets() reads the whole thing.
This question already has answers here:
How do you allow spaces to be entered using scanf?
(11 answers)
Closed 5 years ago.
I'm writing an fuction and I got a problem, the scanf function cant read spacebar " ", how can I solve it?
void add()
{
char choose2;
FILE *fp;
struct booking book;
system("cls");
fp=fopen("hotelbooking.txt","a");
if(fp == NULL)
{
printf("There are no data file!");
}
else
{
printf("Add New Hotel Booking Record(s)\n");
printf(" Name of Traveller: \n");
scanf("%s",book.travellername);
fprintf(fp,"\n%s",book.travellername);
printf(" Destination: ");
scanf("%s",book.destination);
fprintf(fp,"\n%s",book.destination);
fclose(fp);
}
}
In the tervellername part, If I want to enter e.g. "Jason George", How can I scan the space bar between the name?
I'm using the structure below:
struct booking
{
char travellername[20];
char destination[20];
}book;
scanf() with %s format specifier stops scanning as soon as it hits a whitespace. You cannot scan space using it.
Quoting C11, chapter §7.21.6.2,
s Matches a sequence of non-white-space characters.
For a better and robust alternative, you can use fgets() to scan an entire line, terminated by a newline. Remember, in this case, fgets() scans and stores the terminating newline also in the supplied buffer, so you need to manually get rid of it, if that matters.
Try this
scanf("%[^\n]", book.travellername);
Input string will read space separated words and terminate upon encountering a newline character (i.e. \n). Also be Careful that this does not get buffer overflows. so define size of book.travellername accordingly.
update: I have updated the format specifier.
This question already has answers here:
Why does scanf appear to skip input?
(7 answers)
Closed 8 years ago.
Here i have a simplified piece of code that asks and displays a number on a loop, it works fine for all numbers i type in, But if i input a letter or a special character (!"£$%^&*-_=+ etc ) it goes mental and skips the input.
#include<stdio.h>
int number;
int main()
{
do
{
system("cls");
printf("Enter a number");
scanf("%d",&number);
}
while(1==1);
}
My question is, what can i do to stop this from happening?, is there some code that filters out this nonsense or is scanf pretty much worthless?
//Edit: This is somehow been marked as a duplicate, heh.
From here:
if the input doesn't conform to the expected format scanf() can be
impossible to recover sensibly [..] A "better" alternative here is to
use an input function like fgets() or fgetc() to read chunks of input,
then scan it with sscanf() or parse it with string handling functions
like strchr() and strtol().
scanf with %d will fail to scan an integer and returns 0 when a character was entered. So just check if it doesn't return 1. If it doesn't , a character was entered (if it returned 0) or else, an integer was entered. Note that if EOF was encountered, scanf will return -1.
if(scanf("%d", &number) != 1)//character entered
{
printf("Invalid input\n");
scanf("%*s");//clear the invalid character(s) from stdin
}
else
{
//a number was entered
}
The reason that scanf becomes "mental" and the program prints Enter a number many times when you enter a character is that when the scanf fails to scan an integer from the standard input stream(stdin), it returns 0 and the execution continues. When scanf is called the next time, it sees the characters which you had entered the last time and again fails and this process continues. To prevent it, just clear the stdin like I've done in the code above.
Another popular way of clearing the stdin is using:
int c;
while((c = getchar()) != '\n' && c != EOF);