Why does scanf_s() isn't working second time I am calling it in order to verify if user provided correct input? - c++

I am writing an application with a menu and I am asking the user to provide an integer representing an option
from the menu
1. Option 1
2. Option 2
3. Option 3
...
This option is stored in a variable called
option
I want to avoid wrong input such as "12a", "1a2", "anyString" and I've read that this can be achieved by storing return value of scanf_s() function.
So I stored it in a variable called
ret
and now I want that every time user provides wrong input to prompt them to enter a new value.
So I wrote something like this:
int ret = scanf_s("%d", &option);
while (!ret)
{
cout << "Provide an integer, not a string! :)\n";
ret = scanf_s("%d", &option);
}
The problem is when it enters the while it is not allowing user to enter a new value and hence the value of ret never changes, making it run endlessly.
How can I achieve what I am looking for?

When scanf_s fails to convert an integer, the offending input stays in the input stream. Calling scanf_s("%d", &option) again will produce the same result until some characters are removed from the input stream. Note also that using scanf_s or scanf directly from stdin is error prone: the newline entered by the user stays in the input stream and will be read by a subsequent call to getchar() or fgets(), potentially causing unexpected behavior.
To avoid these pitfalls, it is recommended to read one line at a time with fgets() and convert it with sscanf() this way:
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
int main() {
char buf[80];
int option;
char cc;
for (;;) {
print_menu(); // output the menu options
if (!fgets(buf, sizeof buf, stdin)) {
/* end of file reached: break from the loop */
break;
}
/* parse exactly one integer with optional leading and trailing whitespace */
if (sscanf(buf, "%d %c", &option, &cc) != 1) {
printf("invalid input: %s", buf);
printf("enter one integer exactly\n");
continue;
}
printf("option is %d\n", option);
// handle option
}
return 0;
}

Related

fgets() does not return NULL on empty string

I recently tried to use fgets() instead of scanf() to read a string for code security reasons. I used a simple function that I found here to check for errors (no input and too long input). The problem is that whenever i press "ENTER" without actually writing anything, fgets() doesn't return NULL and my program is not able to show the NO_INPUT error.
Here's main.cpp:
#include <stdlib.h>
#include <stdio.h>
#include "utilities.h"
int main() {
int rc;
char str[20];
rc = getLine("Enter string: ", str, sizeof(str));
if(rc == NO_INPUT) {
printf("[ERROR] No input\n\n");
} else if(rc == TOO_LONG) {
printf("[ERROR] Input is too long\n\n");
} else {
printf("This is your input: \"%s\"\n\n", str);
}
system("pause");
}
Here's utilities.h:
#include <stdio.h>
#include <string.h>
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
int getLine(const char *msg, char *buff, size_t len) {
if(msg != NULL) {
printf("%s", msg);
fflush(stdout);
}
if(fgets(buff, len, stdin) == NULL /*[+]*/ || strcmp(buff, "\n") == 0) {
//[-] fflush(stdin);
return NO_INPUT;
} else if(buff[strlen(buff)-1] != '\n') {
//[-] fflush(stdin);
return TOO_LONG;
} else {
buff[strlen(buff)-1] = '\0';
//[-] fflush(stdin);
return OK;
}
}
And here's the output:
Enter string:
This is your input: ""
Press any key to continue . . .
I solved my problem by replacing the first if statement in utilities.h with if(fgets(buff, len, stdin) == NULL || strcmp(buff, "\n") == 0). Doing this, my program will check for input errors OR for empty strings and return the NO_INPUT flag.
Thanks to everybody who commented and #Peter for answering. I added the aforementioned if statement in utilities.h and removed every fflush(stdin) occurrence. The code now looks as above.
Your problem that you "fixed" is believing that a end of line should be treated as end of input.
NULL is an indication from fgets() that it encountered an error or the end of input when reading from the file (or stream). A blank line is neither an error nor a marker of end of input. A human (typing on a keyboard) might choose to interpret a newline as end of input, but a computer program does not - after all, there is nothing stopping a user entering more than one line of input.
Practically, fgets() reads a line and indicates the end of that line with a '\n' character. Let's say, we have a file containing
ABC
DE
FGHIJ
(blank lines interspersed in three lines of text, followed by end of the file).
Let's also that buffer is an array of five char, and that we read that file using consecutive statements of the form fgets(buffer, 5, file).
So what will fgets(buffer, 5, file) do on each call. Well, with 1 representing the first call, 2 representing the second call, etc we will see results of
"ABC\n" stored into buffer;
"\n" stored into buffer; (first blank line)
"DE\n" stored into buffer;
"\n" stored into buffer; (second blank line)
"FGHI" stored into buffer;
"J\n" stored into buffer; and
fgets() returns NULL, and nothing is stored into buffer.
The first six calls will all return &buffer[0] - not NULL - since no error is encountered reading from the file. Even though there are two blank lines in the input. The last line, which is longer than the buffer (with the '\n' counted) is read in two parts.
Incidentally, your code is using fflush(stdin). Unfortunately, fflush() only has defined behaviour on OUTPUT streams or files. Using it on stdin (or any input stream) gives undefined behaviour. If it is actually discarding input (which it does with some implementations of the C standard library), you are getting lucky - there are real-world compilers where the resultant behaviour does not discard input.

C++ User enters a non-integer value for integer variable

I am working on program where a list of options is displayed to the user and he would then enter an integer to specify which option he wants to select.Now I have pre-empted the situation where the user might enter an integer value apart from the valid ones. But if he enters any other value, say a character or a string, the program goes into an infinite loop with the list of options being printed infinitely. How can i rectify this? I mean, I should be able to give my user an error when for a predefined integer variable he enters a value that is not an integer.
Any help appreciated. Here is a sample code.
do{
printf("Select appropriate option.\n");
printf("Press 1 to do this");
printf("Press 2 to do that.\n");
printf("Press 3 to exit the program.\n");
scanf("%d",&choice);
if(choice!=1 && choice!=2 && choice!=3)
printf("You entered an invalid choice. Please enter again.\n");
switch(choice){
case 1:
//do this
break
case 2:
//do that
break;
case 3:
exit(1);
}}
while(choice!=3);
So basically when a user enters a non-integer value for choice I want the program to notify the user and ask him for another input.
It cannot be done with direct scanf into an integer variable. Such scanf will not only accept 1.23, it will also accept 1abcde and other inputs. scanf (and other conversion functions) reads as much as it can in accordance with the requested format. It stops when it finds something that does not satisfy format requirements and simply leaves it untouched.
If you want to perform this sort of analysis, you have to read the input as string and then parse and analyze that string manually.
A C-style code sketch (since you insist on C-style code, despite having tagged it as [C++]) might look as follows
char buffer[100]; /* 100 should be enough for everyone :) */
int n = scanf("%s", buffer);
if (n < 1)
/* ERROR, can't read */;
char *end;
long choice = strtol(buffer, &end, 10);
if (end == buffer || *end != '\0' || errno == ERANGE)
/* ERROR, bad format */;
/* ... */
scanf will not consume any non-digits when converting %d. It will return 0 because it didn't convert anything, and the "bad input" will still be there waiting to be consumed. You have to consume it in some way to be ready for a valid input.
(also note you're excluding 3 in your if before testing for it in your switch)
Use iostream - see http://www.cplusplus.com/reference/iostream/
Having said that if you insist on using scanf - check the return value - i.e. read http://linux.die.net/man/3/scanf
isdigit will check for any input that is a digit(number) type.
For this include header ctype.h.
Also terminate your program using exit(0) if input is incorrect.
For this include header stdlib.h.
#include<ctype.h>
#include<stdlib.h>
char c;
scanf("%c", &c);
if (isdigit(c))
{
case statement...
...
...
}
else
{
printf("Wrong input");
exit(0);
}

Program for Password in C++

Password program not working....pls help....for right input also it says wrong password
#include<stdio.h>
#include<conio.h>
#include<string.h>
#include<iostream.h>
void main()
{
clrscr();
int ctr=0;
int o;
char pass[5];
cout<<"enter password";
for(int i=0;i<5 && (o=getch())!=13 ;i++)
{
pass[i]=o;
putch('*');
}
ctr=strcmp(pass,"luck");
cout<<ctr;
if(ctr==0)
{
cout<<"welcome";
}
else
{
cout<<"wrong password";
}
getch();
}
I want to know why this password program not working....is their any other way
To be able to use strcmp(), you need to NUL-terminate pass. You also need to make sure that pass is large enough to accommodate the NUL.
As <conio.h> is in use, I'm assuming Windows is being used. For those who are interested, here is a start on the proper way to do this. I input a line as the password, ending when enter is pressed, and don't show asterisks, as they give away the length pretty easily.
//stop echoing input completely
HANDLE inHandle = GetStdHandle(STD_INPUT_HANDLE); //get handle to input buffer
DWORD mode; //holds the console mode
GetConsoleMode(inHandle, &mode); //get the current console mode
SetConsoleMode(inHandle, mode & ~ENABLE_ECHO_INPUT); //disable echoing input
//read the password
std::string password; //holds our password
std::getline(std::cin, password); //reads a line from standard input to password
//compare it with the correct password
std::cout << (password == "luck" ? "Correct!\n" : "Wrong!\n"); //output result
//return console to original state
SetConsoleMode(inHandle, mode); //set the mode back to what it was when we got it
Of course there are things you can do to improve it (a hardcoded password string is never a good thing), and go ahead and do so if you wish, but the point is that it works as a basic password input system and has an easy-to-follow structure. You can still use the things you love when getting a password input, rather than going one character at a time and resorting to C strings and code.

Why does scanf appear to skip input?

I am confused about scanf's behaviour in the following program. scanf appears to input once, and then not input again, until a stream of characters is printed.
Below in a C program
#include<stdio.h>
int main()
{
int i, j=0;
do
{
++j;
scanf("%d", &i);
printf("\n\n%d %d\n\n", i, j);
}
while((i!=8) && (j<10));
printf("\nJ = %d\n", j);
return 0;
}
here, Till i am inputting any integer program works perfectly fine, but when a character is inputted it goes on printing the last inputed value of i and never stops(untill j is 10 when loop exits) for scanf to take next input.
output::
1 <-----1st input
1 1
2 <---- 2nd input
2 2
a <---- character input
2 3
2 4
2 5
2 6
2 7
2 8
2 9
2 10
J = 10
same thing is happening in c++ also.
#include<iostream>
using namespace std;
int main()
{
int i, j=0;
do
{
++j;
cin>>i;
cout<<i<<" "<<j<<"\n";
}
while((i!=8) && (j<10));
cout<<"\nj = "<<j<<"\n";
}
output of c++ program ::
1 <-----1st input
1 1
2 <-----2nd input
2 2
a <------ character input
0 3
0 4
0 5
0 6
0 7
0 8
0 9
0 10
j = 10
only change in c++ is that 0 is being printed instead of last value.
I know here integer values are expected by the program, but i want to know what happens when character is inputted in place of an integer?
what is the reason of all happening above?
When you enter a, then cin >> i fails to read it because the type of i is int to which a character cannot be read. That means, a remains in the stream forever.
Now why i prints 0 is a different story. Actually it can print anything. The content of i is not defined once the attempt to read fails. Similar thing happens with scanf as well.
The proper way to write it this:
do
{
++j;
if (!(cin>>i))
{
//handle error, maybe you want to break the loop here?
}
cout<<i<<" "<<j<<"\n";
}
while((i!=8) && (j<10));
Or simply this (if you want to exit loop if error occurs):
int i = 0, j = 0;
while((i!=8) && (j<10) && ( cin >> i) )
{
++j;
cout<<i<<" "<<j<<"\n";
}
If scanf sees a character in the input stream that doesn't match the conversion specifier, it stops the conversion and leaves the offending character in the input stream.
There are a couple of ways to deal with this. One is to read everything as text (using scanf with a %s or %[ conversion specifier or fgets) and then use atoi or strtol to do the conversion (my preferred method).
Alternately, you can check the return value of scanf; it will indicate the number of successful conversions. So, if scanf("%d", &i); equals 0, then you know there's a bad character in the input stream. You can consume it with getchar() and try again.
You can never expect your users to enter valid things. The best practice is to read the input into a string and try to convert it to integer. If the input is not an integer, you can give an error message to the user.
The problem is that when you enter an input that is not of the expected type (specified by %d for scanf, and the int type for cin>>i;, the inputstream is not advanced, which results in both operations trying to extract the same type of data from the exact same incorrect input (and failing just as well this time around too), thus you will never asked for another input.
To ensure this does not happen you will need to check the return value of both operations (read the manual for how each reports errors). If an error does happen (as when you enter a character), you will need to clear the error, consume the invalid input and try again. I find it better in C++ to read a whole line using std::gtline() instead of int or even std::string when geting input from ther user interactively, so you get into this "infinite" loop you experienced.
You are ignoring the return value. See what the manual says about scanf(3):
RETURN VALUE
These functions return the number of input items successfully matched and assigned, which can be fewer than provided for, or even zero in the event of an early matching failure.
It fails matching an integer.
You could check the return value of scanf to determine if an integer has been parsed correctly (return should =1). On failure, you have choices: either notify the user of the error and terminate, or recover by reading the next token with a scanf("%s" ...) perhaps with a warning.
For scanf, you need to check its return value to see if the conversion on the input worked. scanf will return the number of elements successfully scanned. If the conversion did not work, it will leave the input alone, and you can try to scan it differently, or just report an error. For example:
if (scanf("%d", &i) != 1) {
char buf[512];
fgets(buf, sizeof(buf), stdin);
printf("error in line %d: got %s", j, buf);
return 0;
}
In your program, since the input is left alone, your loop repeats trying to read the same input.
In C++, you check for failure using the fail method, but the input stream failure state is sticky. So it won't let you scan further without clearing the error state.
std::cin >> i;
if (std::cin.fail()) {
std::string buf;
std::cin.clear();
std::getline(cin, buf);
std::cout
<< "error in line " << j
<< ": got " << buf
<< std::endl;
return 0;
}
In your program, since you never clear the failure state, the loop repeats using cin in a failure state, so it just reports failure without doing anything.
In both cases, you might find it easier or more reliable to work with the input if you would read in the input line first, and then attempt to parse the input line. In pseudocode:
while read_a_line succeeds
parse_a_line
In C, the catch to reading a line is that if it is longer than your buffer, you will need to check for that and concatenate multiple fgets call results together to form the line. And, to parse a line, you can use sscanf, which is similar to scanf but works on strings.
if (sscanf(buf, "%d", &i) != 1) {
printf("error in line %d: got %s", j, buf);
return 0;
}
In C++, for quick low level parsing of formatted input, I also prefer sscanf. But, if you want to use the stream approach, you can convert the string buffer into a istringstream to scan the input.
std::getline(cin, buf);
if (std::cin.fail()) {
break;
}
std::istringstream buf_in(buf);
buf_in >> i;
if (buf_in.fail()) {
std::cout << "error in line " << j
<< ": got " << buf
<< std::endl;
return 0;
}

Wait until user presses enter in C++?

waitForEnter() {
char enter;
do {
cin.get(enter);
} while ( enter != '\n' );
}
It works, but not always. It doesn't work when an enter is pressed just before the function is called.
You can use getline to make the program wait for any newline-terminated input:
#include <string>
#include <iostream>
#include <limits>
void wait_once()
{
std::string s;
std::getline(std::cin, s);
}
In general, you cannot simply "clear" the entire input buffer and ensure that this call will always block. If you know that there's previous input that you want to discard, you can add std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); above the getline to gobble up any left-over characters. However, if there was no extra input to begin with, this will cause an additional pause.
If you want full control over the console and the keyboard, you may have to look at a platform-specific solution, for instance, a terminal library like ncurses.
A select call on a Posix system that can tell you if reading from a file descriptor would block, so there you could write the function as follows:
#include <sys/select.h>
void wait_clearall()
{
fd_set p;
FD_ZERO(&p);
FD_SET(0, &p);
timeval t;
t.tv_sec = t.tv_usec = 0;
int sr;
while ((sr = select(1, &p, NULL, NULL, &t)) > 0)
{
char buf[1000];
read(0, buf, 1000);
}
}
On Windows, you can do this:
void WaitForEnter()
{
// if enter is already pressed, wait for
// it to be released
while (GetAsyncKeyState(VK_RETURN) & 0x8000) {}
// wait for enter to be pressed
while (!(GetAsyncKeyState(VK_RETURN) & 0x8000)) {}
}
I don't know the equivalent on Linux.
(the first parameter) The name of the array of type char[] in which the characters read from cin are to be stored.
(the second parameter) The maximum number of characters to be read. When the specified maximum has been read, input stops.
(the third parameter) The character that is to stop the input process. You can specify any character here, and the first occurrence of that character will stop the input process.
cin.getline( name , MAX, ‘\n’ );
Page 175 IVOR HORTON’S BEGINNING VISUAL C++® 2010