Im using this code to allow the use to enter a numerical value for the variable:
float day;
printf("Day?: ");
scanf("%f",&day);
how can i make the program produce an error message if the user did not enter ANY value for "Day"??
Try this:
if(scanf("%f",&day) != 1)
printf("Error");
Use fgets()/sscanf()
char buf[100];
fgets(buf, sizeof(buf), stdin);
if (sscanf(buf, "%f", &day) != 1) {
if (buf[0] == '\n')
HandleNothingInput();
else
HandleBadInput();
}
}
fgets() typically reads until a Enter or '\n' is entered. By using sscanf() to parse the buffer, empty inputs ("user did not enter ANY value"), bad input ("abc") are readily detected as the result of scanf() will be 0.
Alternatives: If you want to insure no additional data is entered, one could use a sentinel:
int ch;
if (sscanf(buf, "%f %c", &day, &ch) != 1) {
atof() is another approach.
Related
I found some challenge on reddit to make a program which will sum up all DnD dice rolls. Number of throws is unlimited therefore I created this while loop.
I used fgets to input the string, (I can't input only integers because the input is for example 1d3, where 1 is number of dice thrown, and 3 is number of sides of the dice thrown.)
When the user is prompted to input dice, fgets never stops reading user input.
For example:
To end inputting dice type 0
1d3
1d4
1d5
0
0
^C
Main function:
int main(void)
{
char input[MAXSIZE];
int sum = 0;
printf("To end inputting dice type 0\n");
while(*(input) != 0);
{
fgets(input, sizeof(input), stdin);
printf("Debug: input = ");
puts(input);
printf("\n");
sum += dice(input);
printf("Debug: sum = %d\n", sum);
}
printf("Sum of dice rolls is %d.", sum);
return 0;
}
Firstly, the literal value of the character input 0 is not 0. In ASCII, it is 48 (decimal).
Try
while(*(input) != '0') // (1) - use the character literal form
// (2) remove the ;
That said, the standard output is usually line buffered. You need to force a flush if you want to see the outputs in the terminal. You can do that by either
add a newline
printf("Debug: input = \n");
use fflush(stdout).
Try this:-
while(fgets(input, sizeof input, stdin) != NULL)
or
while(fgets(input, sizeof input, stdin))
The issue was really simple and such a beginner mistake I feel shameful for even asking the question.
The semicolon after the while loop.
Thanks all for helping me out.
char input[MAXSIZE] = { 0 }; // initialise input!
// otherwise you get to here and access an uninitialised variable:
while(*(input) != 0); // <--- and a semicolon right there!!! Remove that!
In fact I think the loop you want is while (fgets(input, sizeof input, stdin) && strcmp(input, "0\n"))... note that I've hoisted the fgets into the loops control expression.
You should probably do a check after calling fgets to ensure a newline is read, for example
while (fgets(input, sizeof input, stdin) && strcmp(input, "0\n")) {
size_t n = strcspn(input, "\n");
if (input[n] == '\n') input[n] = '\0';
else assert(input[n] == '\0'), // #include <assert.h>
fscanf(stdin, "%*[^\n]"),
fgetc(stdin);
There's no undefined behaviour associated with reading unsigned integers when using fscanf, so if you only plan on using positive values you can use that instead of fgets if you wish, i.e.
unsigned dice_count, dice_sides;
while (fscanf(stdin, "%ud%u", &dice_count, &dice_sides) == 2) {
printf("You chose to roll %u times with dice that contain %u sides\n", dice_count, dice_sides);
}
When I'm inputting data like a last name I have got it so it limits it to 10 characters, but when I try to enter the last name, the characters that were excluded from the first name are put into the last name. For example, if I enter aaaaaaaaaab it will keep the a's but the b will be put into last name.
Any suggestions how I would fix this? I want it to limit the length to the correct amount.
printf("you chose add new record\n");
printf("enter the person information: \n");
printf("Please enter the first name: \n");
//limits to size 10
char namein[11];
fgets(namein, 11, stdin);
printf("the first name was: %s\n", namein);
printf("Please enter the last name: \n");
//limits to size 20
char lastin[21];
fgets(lastin, 21, stdin);
printf("the last name was: %s\n", lastin);
Examine the result of using fgets().
If the buffer contains a \n, no need to look for more. Otherwise consume potential extra data until '\n' or EOF.
int ConsumeExtra(const char *buf) {
int found = 0;
if (strchr(buf, '\n') == NULL) {
int ch;
// dispose of extra data
while ((ch = fgetc(stdin)) != '\n' && ch != EOF) {
found = 1;
}
}
return found;
}
char namein[11];
if (fgets(namein, sizeof namein, stdin) == NULL) Handle_EOForIOError();
if (ConsumeExtra(namein)) Handle_ExtraFound();
Note: Recommend not being so small with input buffers. Better to reads into a general large buffer and then qualify the input before saving to namein. IOWs, prefer to keep input and scanning/parsing separate.
char buffer[100]
char namein[11];
if (fgets(namein, sizeof buf, stdin) == NULL) Handle_EOForIOError();
if (ConsumeExtra(buf)) Handle_InsaneLongInput();
int n = 0;
sscanf(buffer, "%10s %n", namein, &n);
if (n == 0 || buf[n]) Handle_NothingOrExtraFound();
You have to read the entire input buffer before doing the next read. Such an operation is called "draining" the input.
So your code should look like
get the first name
read the first name
drain the input
print the prompt for the last name
read the last name
draining the input looks roughly like
while (there is data that can be read) {
read a character
}
basically in codeblocks for windows before each printf I have "fflush(stdin);" which works. When I copied my code to Linux, it doesn't work, nor does any of the alternatives for "fflush(stdin);" that I've found. No matter which way I seem to do it, the input doesn't seem to be clearing in the buffer or something in my code is incorrect.
#include <stdio.h>
#include <math.h>
#include <limits.h>
#include <ctype.h>
int main()
{
char pbuffer[10], qbuffer[10], kbuffer[10];
int p=0, q=0, k=0;
int r, i, Q, count, sum;
char a[3];
a[0]='y';
while(a[0]=='y' || a[0]=='Y')
{
printf("Enter a p value: \n");
fgets(pbuffer, sizeof(pbuffer), stdin);
p = strtol(pbuffer, (char **)NULL, 10);
printf("Enter a q value: \n");
fgets(qbuffer, sizeof(qbuffer), stdin);
q = strtol(qbuffer, (char **)NULL, 10);
printf("Enter a k value: \n");
fgets(kbuffer, sizeof(kbuffer), stdin);
k = strtol(kbuffer, (char **)NULL, 10);
while(p<q+1)
{
Q=p;
sum=0;
count=0;
while(Q>0)
{
count++;
r = Q%10;
sum = sum + pow(r,k);
Q = Q/10;
}
if ( p == sum && i>1 && count==k )
{
printf("%d\n",p);
}
p++;
a[0]='z';
}
while((a[0]!='y') && (a[0]='Y') && (a[0]!='n') && (a[0]!='N'))
{
printf("Would you like to run again? (y/n) ");
fgets(a, sizeof(a), stdin);
}
}
return 0;
}
Calling fflush(stdin) is not standard, so the behavior is undefined (see this answer for more information).
Rather than calling fflush on stdin, you could call scanf, passing a format string instructing the function to read everything up to and including the newline '\n' character, like this:
scanf("%*[^\n]%1*[\n]");
The asterisk tells scanf to ignore the result.
Another problem is calling scanf to read a character into variable a with the format specifier of " %s": when the user enters a non-empty string, null terminator creates buffer overrun, causing undefined behavior (char a is a buffer of one character; string "y" has two characters - {'y', '\0'}, with the second character written past the end of the buffer). You should change a to a buffer that has several characters, and pass that limit to scanf:
char a[2];
do {
printf("Would you like to run again? (y/n) \n")
scanf("%1s", a);
} while(a[0] !='y' && a[0] !='Y' && a[0]!='n' && a[0]!='N' );
}
I think what you are trying to do is more difficult than it seems.
My interpretation of what you are trying to do is disable type ahead so that if the user types some characters while your program is processing other stuff, they don't appear at the prompt. This is actually quite difficult to do because it is an OS level function.
You could do a non blocking read on the device before printing the prompt until you get EWOULDBLOCK in errno. Or the tcsetattr function family might help. It looks like there is a way to drain input for a file descriptor in there, but it might interact badly with fgets/fscanf
A better idea is not to worry about it at all. Unix users are used to having type ahead and what you want would be unexpected behaviour for them.
Drop the need for flushing the input buffer.
OP is on the right track using fgets() rather than scanf() for input, OP should continue that approach with:
char a;
while(a !='y' && a !='Y' && a!='n' && a!='N' ) {
printf("Would you like to run again? (y/n) \n");
if (fgets(kbuffer, sizeof(kbuffer), stdin) == NULL)
Handle_EOForIOerror();
int cnt = sscanf(kbuffer, " %c", &a); // Use %c, not %s
if (cnt == 0)
continue; // Only white-space entered
}
Best to not use scanf() as it tries to handle user IO and parsing in one shot and does neither that well.
Certain present OP's woes stem from fgets() after scanf(" %s", &a); (which is UB as it should be scanf(" %c", &a);. Mixing scanf() with fgets() typically has the problem that the scanf(" %c", &a); leaves the Enter or '\n' in the input buffer obliging the code to want to flsuh the input buffer before the next fgets(). Else that fgets() gets the stale '\n' and not a new line of info.
By only using fgets() for user IO, there need for flushing is negated.
Sample fgets() wrapper
char *prompt_fgets(const char *prompt, char dest, long size) {
fputs(prompt, stdout);
char *retval = fgets(dest, size, stdin);
if (retval != NULL) {
size_t len = strlen(dest);
if (len > 1 && dest[len-1] == '\n') { // Consume trailing \n
dest[--len] = '\0';
}
else if (len + 1 == dest) { // Consume extra char
int ch;
do {
ch == fgetc(stdin);
} while (ch != '\n' && ch != EOF);
}
return retval;
}
This question already has answers here:
Why doesn't getchar() wait for me to press enter after scanf()?
(10 answers)
Closed 3 years ago.
I'm trying to have the user enter in a number as many times as they want (and create a linked list node for each of the numbers).
However, I've tried multiple method of clearing the character input buffer but to no avail. Strangely, the code will execute once through but not execute correctly the second.
For example, with the code below, the terminal reads:
would you like to enter an integer?
y
Enter an integer: 4
would you like to enter an integer?
y
**program terminates**
And before when I was using scanf("%c", yesno); I would not even be able to input 'y' on the last line. It just terminated.
struct node *read_numbers(void){
struct node *first = NULL;
int n; char yesno;
yesno = 'y';
while( yesno == 'y'){
printf("Would you like enter an integer ((y) for yes/(n) for no):\n");
yesno = getchar();
while(getchar() != '\n');
if(yesno == 'y'){
printf("Enter an Integer:");
scanf(" %d", &n);
first = add_to_list(first, n);
} else {
return first;
}
} // end while
}
I read up on character inputs and buffers, and supposedly the getchar() method should work. Am I utilizing it wrong? I've also tried scanf() with extra spaces before and after the "%c", but to no avail.
You need to digest the newline after the scanf. You can do what you're doing above in the code:
scanf(" %d", &n);
while(getchar() != '\n');
first = add_to_list(first, n);
Can I recommend that you use fgets as a safer alternative to getchar and scanf?
As you've noticed these functions can buffer the newline and pass it on to the next function that reads from the standard input.
With fgets you can store the input in a char array and avoid such problems. Additionally, you can still check easily if the input consists of only a newline:
char user_input[10] = "";
printf("Would you like enter an integer ((y) for yes/(n) for no):\n");
/* get input or quit if only newline is entered, we only check the first char */
while(fgets(user_input, 3, stdin)[0] != '\n')
{
/* check if the first char is 'y', quicker to do than using strcmp */
if(user_input[0] == 'y')
{
int input = 0;
printf("Enter an Integer: ");
fgets(user_input, 5, stdin); /* get input again */
input = atoi(user_input); /* convert to int */
printf("Your integer is %d\n", input);
printf("Would you like to go again? y/n:\n");
}
else
{
return printf("No input there.\n");
}
}
getcharis get the data from stdin, while(getchar() != '\n'); just like clear the stdin buffer.
so the following code can work correctly
I write console application which performs several scanf for int
And after it ,I performs getchar :
int x,y;
char c;
printf("x:\n");
scanf("%d",&x);
printf("y:\n");
scanf("%d",&y);
c = getchar();
as a result of this I get c = '\n',despite the input is:
1
2
a
How this problem can be solved?
This is because scanf leaves the newline you type in the input stream. Try
do
c = getchar();
while (isspace(c));
instead of
c = getchar();
Call fflush(stdin); after scanf to discard any unnecessary chars (like \r \n) from input buffer that were left by scanf.
Edit: As guys in comments mentioned fflush solution could have portability issue, so here is my second proposal. Do not use scanf at all and do this work using combination of fgets and sscanf. This is much safer and simpler approach, because allow handling wrong input situations.
int x,y;
char c;
char buffer[80];
printf("x:\n");
if (NULL == fgets(buffer, 80, stdin) || 1 != sscanf(buffer, "%d", &x))
{
printf("wrong input");
}
printf("y:\n");
if (NULL == fgets(buffer, 80, stdin) || 1 != sscanf(buffer, "%d", &y))
{
printf("wrong input");
}
c = getchar();
You can use the fflush function to clear anything left in buffer as a consquence of previous comand line inputs:
fflush(stdin);
A way to clean up anyspace before your desired char and just ignore the remaining chars is
do {
c = getchar();
} while (isspace(c));
while (getchar() != '\n');
For a start the scanf should read scanf("%d\n", &x); or y. That should do the trick.
man scanf