I am using fgets() to get user input, and then I parse it into a double using sscanf(). Here is my example code:
int menuItem = 0;
char input[3];
printf("Enter valid menu item"); //values are 1, 2, 3, 4, 5, and -1
fgets(input, sizeof input, stdin);
sscanf(input, "%d", &menuItem);
The error occurs if the user enters 3 digits (invalid input, and I want to handle it accordingly), it skips my next fgets() by automatically placing the third digit as the next input. For example, if the user inters 123, it will now skip the next fgets and use the value 3 as the input. How can I clear this, or at most, only read 1 digit (but still being able to handle -1).
Why don't you just make your input array larger? Like 50 bytes... If the user enters that many, they are idiots and deserve strange behaviour =)
This is of course inelegant, but putting it in perspective, you are probably not writing industrial-strength code here. You just want to fix a silly bug, and this is the simplest solution.
[edit]
In case you are confused as to why I suggested this. Your input array is only large enough to hold 2 values, plus a null-terminator. So obviously, you want it to be large enough that you can be sure the user entered a single choice and not two choices
Your input buffer allows 1 digit, 1 newline, and 1 terminal null '\0', which really isn't big enough.
Suppose the user types 100 followed by a newline. The first call to fgets() will read 2 digits (10), then the second call will read the third digit and newline; then the next call will wait for the next input.
Simply increase your buffer size to something more sensible. For a lot of programs that I write, I use a buffer size of 4096. The POSIX standard sets _POSIX2_LINE_MAX to 2048. If you're unhappy with that, simply go with a convenient number like 64 or 128; you won't go too far wrong.
Your technique with fgets() and sscanf() is definitely the better direction to go, but you should check that sscanf() parsed the correct number of values. One of the advantages of fgets() plus sscanf() is that you can make better reports about what was erroneous in the line that the user entered; this is much less easy to do if you use fscanf() or scanf() directly.
Related
I'm in my first steps in C programming, and I came across a task I can not find a solution to.
The task is simple: taking a character from the user.
After that, you receiving a string from the user until the user types the * character.
Then print the number of times the user typed the first character.
I was able to solve the problem using char [SIZE]ת when I placed a maximum input size of 255 bytes (#define SIZE 255).
Nevertheless, my teacher tells me that although the solution is working well, this was not the purpose of the exercise, also, I can not assume a maximum string size.
He asks us to use the input buffer.
No dynamic memory allocation is used in the exercise, and only the stdio.h library is allowed.
I read a lot about the input buffer, but I still have not found the possibility to solve the exercise - how can I absorb value from the user without knowing its size?
I would be happy to receive assistance and tips on how to use the input buffer correctly.
Or more focused, how to input values (string of characters) into the input buffer, and then go over each character separately in this string and process it.
Thank You
There is no need to store all characters. Once you have read a character you can throw it away and just increase a counter. Something like this:
#include <stdio.h>
int main() {
char c, first;
int counter=0;
printf("Enter first character: ");
scanf("%c", &first);
do {
scanf("%c", &c);
if(c == first)
counter++;
} while (c != '*');
printf("You entered '%c' %d times\n", first, counter);
}
Output:
Enter first character: a
aaaaa*
5
or
Enter first character: a
aabbaa*
You entered 'a' 4 times
Note:
As been pointed out in the comments, scanf is not a good tool for this kind of stuff. I would advice against the usage of it, unless you know it is the right tool. But that's beside the point. The point here was to show you that you don't need to store the whole input buffer. If you want to look at alternate input methods (as William Pursell suggested in the comments) you could have a look at fgetc, getc, or getchar for reading single characters. fread is also a tool you should get familiar with.
So I had a code where I use
scanf("%[^\n]s",a);
and has multiple scanf to take different inputs some being string input. So I understand that scanf("%[^\n]s",a) takes input until new line has been reached, however I was wondering suppose my string can only hold up to 10 characters, then after my string has been filled, but new line hasn't been reached how can i get rid of the extra input before going to new line. I was thinking of doing getchar() until new line has been reached however in order to even check if my 10 spots has been filled I need to use getchar, so doesn't that mess up my next scanf input? Anybody have any other way to do it? Still using scanf() and getchar?
scanf("%[^\n]s",a) is a common mistake; the %[ directive is distinct from the %s directive. What you're asking from scanf is:
A group of non-'\n' characters, followed by...
A literal s character.
Perhaps you intended to write scanf("%[^\n]",a)? Note the deleted s...
You can use the * modifier to suppress assignment for a directive, for example scanf("%10[^\n]", a); followed by scanf("%*[^\n]"); to read and discard up to the next newline and getchar(); to read and discard that newline:
scanf("%10[^\n]", a);
scanf("%*[^\n]"); // read and discard up to the next newline
getchar(); // read and discard that newline
As pointed out, the two format strings could be concatenated to reduce the number of calls to scanf. I wrote my answer this way for the sake of documentation, and I'll leave it as is. Besides, I figure that attempt at optimisation would be negligible; a profiler is likely to indicate much more significant bottlenecks for optimisation in realistic scenarios.
You can use this format to hold the first 10 characters and keep the next lines of input:
scanf("%10[^\n]%*[^\n]",a);
getchar();
I read somewhere that with scanf() I can input a maximum of 15 chars. Is it right? Is it bounded?
Has scanf() a limited bound on the number of bytes that the user can input?
NO.
However, FWIW, we can impose a limit on the length of the input actually to be scanned. For that. we use the maximum field width along with the conversion specifier. A simple example will be
char arr[15] = {0};
scanf("%14s", arr);
The above format guarantees that whatever be the length of the user input, (i.e., the data present of the input buffer), scanf() will only read 14 chars, and hence, even in case of longer user input, we can prevent the buffer overflow.
Still, it does not impose any limit on the user input. User can still input an arbitrary number (at least, theoretically) of chars, when asked.
No
you can enter as many characters until you press a newline i.e enter . And, yes you can limit too by using "%ns" here n is no of characters to limit
I am trying to read from the command line either a non negative number or a minus sign and if the input is not one of those the program terminates so I did the following:
while((scanf("%d", &n)==1 && n>-1 && (input=1)) || (scanf("%c", &delete)==1 && delete=='-' && (input=2)))
input is an integer and indicates which was read a number or the minus sign (input=1 & input=2 in the loop are intended).
Now, the program works for the numbers, but if I enter a minus sign the first scanf() reads it but doesn't put it back apparantly, so the second scanf() finds nothing and terminates the program.
However, if I enter -- (two minus signs) the first scanf() reads one and the second scanf() reads the other and it all works correctly.
The input from the command line can't be changed, it has to be one minus sign. What is the best way of solving this?
Note that I do know how to use getchar() to read the input and then check it but I don't want to do that its a hassle.
The best way is to read entire lines of text into a buffer, and then inspect the contents of the buffer, not relying on brittle chains of reading which depend on pushback.
Just use fgets() and sscanf().
Many people said that scanf shouldn't be used in "more serious program", same as with getline.
I started to be lost: if every input function I got across people said that I shouldn't use any of them, then what should I use? Is there is a more "standard" way to get input that I'm not aware of?
Generally, fgets() is considered a good option. It reads whole lines into a buffer, and from there you can do what you need. If you want behavior like scanf(), you can pass the strings you read along to sscanf().
The main advantage of this, is that if the string fails to convert, it's easy to recover, whereas with scanf() you're left with input on stdin which you need to drain. Plus, you won't wind up in the pitfall of mixing line-oriented input with scanf(), which causes headaches when things like \n get left on stdin commonly leading new coders to believe the input calls had been ignored altogether.
Something like this might be to your liking:
char line[256];
int i;
if (fgets(line, sizeof(line), stdin)) {
if (1 == sscanf(line, "%d", &i)) {
/* i can be safely used */
}
}
Above you should note that fgets() returns NULL on EOF or error, which is why I wrapped it in an if. The sscanf() call returns the number of fields that were successfully converted.
Keep in mind that fgets() may not read a whole line if the line is larger than your buffer, which in a "serious" program is certainly something you should consider.
For simple input where you can set a fixed limit on the input length, I would recommend reading the data from the terminal with fgets().
This is because fgets() lets you specify the buffer size (as opposed to gets(), which for this very reason should pretty much never be used to read input from humans):
char line[256];
if(fgets(line, sizeof line, stdin) != NULL)
{
/* Now inspect and further parse the string in line. */
}
Remember that it will retain e.g. the linefeed character(s), which might be surprising.
UPDATE: As pointed out in a comment, there's a better alternative if you're okay with getting responsibility for tracking the memory: getline(). This is probably the best general-purpose solution for POSIX code, since it doesn't have any static limit on the length of lines to be read.
There are several problems with using scanf:
reading text with a plain %s conversion specifier has the same risk as using gets(); if the user types in a string that's longer than what the target buffer is sized to hold, you'll get a buffer overrun;
if using %d or %f to read numeric input, certain bad patterns cannot be caught and rejected completely -- if you're reading an integer with %d and the user types "12r4", scanf will convert and assign the 12 while leaving r4 in the input stream to foul up the next read;
some conversion specifiers skip leading whitespace, others do not, and failure to take that into account can lead to problems where some input is skipped completely;
Basically, it takes a lot of extra effort to bulletproof reads using scanf.
A good alternative is to read all input as text using fgets(), and then tokenize and convert the input using sscanf or combinations of strtok, strtol, strtod, etc.
Use fgets to get the data and use sscanf (or another method) to interpret them.
See this page to learn why it is better to use fgets + sscanf rather than scanf
http://c-faq.com/stdio/scanfprobs.html