getline validation - c++

I need help from you about getline validation. I've created 2D Matrix using vector and I would like to fill that 2D Matrix with values from console.
The problem is with validation of the single values in input (one row). When I type for example "d" or any other character, my code converts it to 0 and put the value in the matrix.. however thats not what I want. I want the user to type the values again (until they are valid) and put the new values in the matrix. This is the code:
string number, line;
cin.ignore();
double value = 0;
for(unsigned int i = 0; i < n; i++)
{
while((getline(cin, number, '\n'))) {
cout << "-> ";
stringstream iss(number);
for (unsigned int j = 0; j <= n; j++)
{
if ( !(iss >> value) )
{
cout << "[ERROR] Invalid input. Type a valid number:" << endl;
cin.clear();
cin.ignore(256, '\n');
} else {
A[i][j] = value;
}
}
break;
}
}
//Edit:
What I want to accomplish is to check, if the value in the line which is inputted is a valid number. For example (input)
1 1 1 1
2 2 2 2
3 char 3 3
[ERROR] Invalid input. Type a valid number:
3 3 3 3
And the output of that should be as it was inputted without the error line with random char other than number.
Right now with my code above, it says Invalid input, but it outputs the last line with error as 0 and the followed numbers after that 0 are zeroes too, because it ignores the new inputted fixed lines with valid numbers.
Output looks like this (with the error):
1 1 1 1
2 2 2 2
3 0 0 0

I don't think the values are put into the matrix with a value of 0. Instead, they merely stay in the matrix with the value 0! Essentially, you break out out of the while-loop processing lines independent on whether the values have been read successfully. I'd probably move some of the conditions around and avoid the intermediate stream: it doesn't seem helpful as you don't really do line-oriented input.
double value;
for (unsigned int i{0}; i != n && std::cin; ++i) {
for (unsigned int j{0}; std::cin; ) {
if (std::cin >> value) {
A[i][j] = value;
if (++j == n) {
++i;
break;
}
else if (!std::cin.eof()) {
std::cin.clear();
std::string line;
std::getline(std::cin, line); // !std::cin.eof() => this shall be successful!
std::cout << "ERROR invalid number input: ignoring '" << line << "'\n";
}
}
}

I think you need to move the getline out of the while to make it works.
Here an example. I didn't compiled it but it should give you a general idea.
// To be tested
string number, line;
cin.ignore();
double value = 0;
bool validInput;
for(unsigned int i = 0; i < n; i++)
{
validInput = false;
while(!validInput) {
getline(cin, number, '\n');
std::istringstream iss(number);
iss >> value;
if (!iss.fail() && iss.eof())
{
cout << "[ERROR] Invalid input. Type a valid number:" << endl;
cin.clear();
cin.ignore(256, '\n');
continue;
}
validInput = true;
for (unsigned int j = 0; j <= n; j++)
{
A[i][j] = value;
}
}
}

Related

how to make cin only take integer inputs

i new to programming and we are required to create a program that dont exit when the user inputs the wrong input, but i only learned the basics so far.. i already solved when the number is above and below 100 but when the user accidentally inserted a non integer it will go into a error loop. btw this is an average calculator.
#include <iostream>
using namespace std;
int main()
{
int num[100];
int n;
double sum, average;
cout << "how many numbers will you input?: ";
cin >> n;
while ( n > 100 || n <= 0 )
{
cout << "Error! number should in range of (1 to 100) only." << endl;
cout << "Enter the number again: ";
cin >> n;
}
for ( int i = 0; i < n; ++i )
{
cout << i + 1 << ". Enter number: ";
cin >> num[i];
sum += num[i];
}
average = sum / n;
cout << "Average = " << average;
}
If std::istream::operator >> fails, it will set failbit. Therefore, you should check failbit (for example by calling std::cin.fail()) to see whether the conversion was successful, before using the result of the conversion.
If the conversion fails due to bad input, then the next call to std::istream::operator >> will automatically fail due to failbit being set. That is why you are getting stuck in an infinite loop. If you want to attempt input again after a conversion failure, you will first have to clear failbit, by using the function std::cin.clear().
Also, you will have to discard the bad input that caused the conversion to fail, because otherwise, the next time you call std::istream::operator >>, the conversion will fail again for the same reason. In order to clear the bad input, you can use std::cin.ignore(), like this:
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
In order to use std::numeric_limits, you will have to #include <limits>.
After performing these fixes on your code, it should look like this:
#include <iostream>
#include <limits>
using namespace std;
int main()
{
int num[100];
int n;
double sum, average;
bool input_ok;
//repeat until input is valid
do
{
cout << "How many numbers will you input? ";
cin >> n;
if ( cin.fail() )
{
cout << "Error: Conversion to integer failed!\n";
input_ok = false;
}
else if ( n > 100 || n <= 0 )
{
cout << "Error: Number should in range of (1 to 100) only!\n";
input_ok = false;
}
else
{
input_ok = true;
}
//clear failbit
cin.clear();
//discard remainder of line
cin.ignore( numeric_limits<streamsize>::max(), '\n' );
} while ( !input_ok );
for ( int i = 0; i < n; ++i )
{
do
{
cout << i + 1 << ". Enter number: ";
cin >> num[i];
if ( cin.fail() )
{
cout << "Error: Conversion to integer failed!\n";
input_ok = false;
}
else
{
input_ok = true;
}
//clear failbit
cin.clear();
//discard remainder of line
cin.ignore( numeric_limits<streamsize>::max(), '\n' );
} while ( !input_ok );
sum += num[i];
}
average = sum / n;
cout << "Average = " << average;
}
This program has the following behavior:
How many numbers will you input? 200
Error: Number should in range of (1 to 100) only!
How many numbers will you input? -31
Error: Number should in range of (1 to 100) only!
How many numbers will you input? test
Error: Conversion to integer failed!
How many numbers will you input? 4abc
1. Enter number: 1
2. Enter number: 2
3. Enter number: 3
4. Enter number: 4
Average = 2.5
As you can see, the program now works in that it can now handle bad input such as test. It rejects that input and reprompts the user for new input.
However, one problem with this program is that it accepts 4abc as valid input for the number 4. It would probably be appropriate to reject such input instead. One way to fix this would be to inspect the remainder of the line, instead of simply discarding it.
Another issue is that this solution contains a lot of code duplication. Apart from the range check, both do...while loops are nearly identical. Therefore, it would be better to put this loop into a function, which can be called from several places in your code.
However, I generally don't recommend that you use std::istream::operator >>, because its behavior is not always intuitive. For example, as already pointed out above:
It does not always read a whole line of input, so that you must explicitly discard the remainder of the line.
It accepts 4abc as valid input for the number 4.
In my experience, if you want proper input validation of integer input, it is usually better to write your own function that reads a whole line of input using std::getline and converts it with std::stoi. If the input is invalid, then the function should automatically reprompt the user.
In my example below, I am calling this function get_int_from_user.
If you want to additionally ensure that the input is in a certain range, then you can call the function get_int_from_user in an infinite loop, and break out of that loop once you determine that the input is valid.
#include <iostream>
#include <string>
#include <sstream>
#include <cctype>
int get_int_from_user( const std::string& prompt );
int main()
{
int nums[100];
int n;
double sum;
//repeat loop forever, until input is good
for (;;) //equivalent to while(true)
{
n = get_int_from_user( "How many numbers will you input? " );
if ( 1 <= n && n <= 100 )
//input is good
break;
std::cout << "Error! Number should in range of (1 to 100) only.\n";
}
//read one number per loop iteration
for( int i = 0; i < n; i++ )
{
std::ostringstream prompt;
prompt << "Enter number #" << i + 1 << ": ";
nums[i] = get_int_from_user( prompt.str() );
sum += nums[i];
}
std::cout << "Average: " << sum / n << '\n';
}
int get_int_from_user( const std::string& prompt )
{
std::string line;
std::size_t pos;
int i;
//repeat forever, until an explicit return statement or an
//exception is thrown
for (;;) //equivalent to while(true)
{
//prompt user for input
std::cout << prompt;
//attempt to read one line of input from user
if ( !std::getline( std::cin, line ) )
{
throw std::runtime_error( "unexpected input error!\n" );
}
//attempt to convert string to integer
try
{
i = std::stoi( line, &pos );
}
catch ( std::invalid_argument& )
{
std::cout << "Unable to convert input to number, try again!\n";
continue;
}
catch ( std::out_of_range& )
{
std::cout << "Out of range error, try again!\n";
continue;
}
//The remainder of the line is only allowed to contain
//whitespace characters. The presence of any other
//characters should cause the entire input to get rejected.
//That way, input such as "6sdfj23jlj" will get rejected,
//but input with trailing whitespace will still be accepted
//(just like input with leading whitespace is accepted by
//the function std::stoi).
for ( ; pos < line.length(); pos++ )
{
if ( !std::isspace( static_cast<unsigned char>(line[pos]) ) )
{
std::cout << "Invalid character found, try again!\n";
//we cannot use "continue" here, because that would
//continue to the next iteration of the innermost
//loop, but we want to continue to the next iteration
//of the outer loop
goto continue_outer_loop;
}
}
//input is valid
return i;
continue_outer_loop:
continue;
}
}
This program has the following behavior:
How many numbers will you input? 200
Error! Number should in range of (1 to 100) only.
How many numbers will you input? -31
Error! Number should in range of (1 to 100) only.
How many numbers will you input? test
Unable to convert input to number, try again!
How many numbers will you input? 4abc
Invalid character found, try again!
How many numbers will you input? 4
Enter number #1: 1
Enter number #2: 2
Enter number #3: 3
Enter number #4: 4
Average: 2.5
As you can see, it now correctly rejects the input 4abc.
I believe that using the function get_int_from_user makes the code in main much cleaner.
Note that the code above uses one goto statement. Under most circumstances, you should avoid using goto, but for breaking out of nested loops, it is considered appropriate.
#include <iostream>
#include <limits>
using namespace std;
int avg(int sum, int n)
{
int average;
average = sum/n;
cout<<"Avg = "<<average;
}
int main()
{
int n;
cout << "how many numbers will you input?: ";
cin >> n;
int w = n;
int num[w];
int sum;
while(n>100||n<=0)
{
cout << "Error! number should in range of (1 to 100) only." << endl;
cout << "Enter the number again: ";
cin >> n;
}
for(int i = 0; i < n; ++i)
{
cout << i + 1 << "Enter number: ";
cin >> num[i];
if(!cin)
{
cout << "Wrong Choice. " << endl;
cin.clear();
cin.ignore( numeric_limits<std::streamsize>::max(), '\n' );
n++;
continue;
}
else
{
sum += num[i];
}
}
cout<<"Sum = "<<sum<<endl;
avg(sum,w);
}

Infinite loop when using exceptions in c++11

I would like to create a c++11 program that takes in 10 positive integers and gives the user the total. In the event of a negative number or a char input, the exception should be thrown and the user must re enter their value.
The program below works with negative numbers. However, when I enter a character like "a", the program goes into an infinite loop and I cannot figure out why.
Any and all help will be appreciated
#include <iostream>
int main(){
int array[10] = {0};
int total = 0;
for(int i =0; i < 10; i++){
std::cout<<"Number "<< i+1 << ": " <<std::endl;
std::cin >> array[i];
try{
if(array[i] < 0 || std::cin.fail())
throw(array[i]);
}
catch(int a){
std::cout<< a <<" is not a positive number! "<<std::endl;
i-=1; // to go back to the previous position in array
}
}
for(int k = 0; k < 10; k++)
total+=array[k];
std::cout<<"Total: " <<total<<std::endl;
}
If you get invalid input there are two things to thing you need to do:
Clear the stream status. This is done using the clear function.
Remove the invalid input from the buffer. This is usually done using the ignore function.
As for your program, you don't need exceptions here, just using unsigned integers and checking the status is enough:
unsigned int array[10] = { 0 };
...
if (!(std::cin >> array[i])
{
std::cout << "Please input only non-negative integers.\n";
// First clear the stream status
std::cin.clear();
// Then skip the bad input
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Make sure the index isn't increased
--i;
}
To use exceptions similar to what you do now, the solution is almost exactly the same as above:
unsigned int array[10] = { 0 };
...
if (!(std::cin >> array[i])
{
throw i;
}
catch (int current_index)
{
std::cout << "The input for number " << current_index + 1 << " was incorrect.\n";
std::cout << "Please input only non-negative integers.\n";
// First clear the stream status
std::cin.clear();
// Then skip the bad input
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Make sure the index isn't increased
--i;
}
Do not forget to include limits header file while using following line in your code :
std::cin.ignore(std::numeric_limits::max(), '\n');
because numeric_limits template is defined in this header file !

C++ Excluding non-integer user inputs

I am making a number-guessing game where the user is asked to input a four-digit number. It is possible, however, that the user inputs less or more than four digits and/or a non-integer input (i.e. invalid input). My code stores the user input into an integer-type array. I just realized now that my code will still recognize "invalid inputs" as valid since the array where the input is being stored is declared as an integer-type. Below is a portion of my code:
#include <iostream>
using namespace std;
void guess(int num_guess[], int size);
int main(){
int list[4];
guess(list, 4);
for(int i = 0; i < 4; i++){
cout << list[i];
}
cout << endl;
}
void guess(int num_guess[], int size){
int number;
cin >> number;
for(int i = size-1; i >= 0; i--){
num_guess[i] = number%10;
number /= 10;
}
}
cout << list[i]; isn't really part of the original code, but this was how I found out that invalid inputs are still accepted. I encountered a similar problem before when I was making a rational roots calculator program in Python, but it was much easier then to detect and exclude unwanted inputs. My question is, how do I fix my code so that it can detect invalid inputs and output something like "Invalid input" and then proceed to ask the user for another input.
The following is a function to check if a string is a 4 digit positive integer. If the number could be negative, you just need to check if the s[0] == '-'.
bool check(string &s){
if(s.size() != 4) return false;
for(int i=0; i < 4; i++){
if(s[i] < '0' || s[i] > '9') return false;
}
return true;
}
The following is a function to convert a string to an int:
#include <stringstream>
int strToInt(string &s){
stringstream ss(s);
int ans;
ss >> ans;
return ans;
}
To exclude non integer inputs try the following:
void skip_to_int(){
// if is not an integer
if(cin.fail()){
// check character type
cin.clear();
char ch;
while(cin>>ch){
// throw away non digits
if(isdigit(ch)){
// put back if digit to be written
cin.unget();
return;}
}
}
else error ("no input");
}
And your input prompt function will look like this:
cout << "Please enter an integer" << endl;
int n=0;
if(cin>>n){
// integer OK, proceed
}
else{
cout << "That was not a numeric value, try again." << endl;
skip_to_int();}
Here's my solution. Beware, it uses C++11. Certainly not necessary if you use std::stringstream, but this should work pretty well.
I presume you don't want negative numbers. I also presume that any number of 0's in front doesn't make the number a 4-digit number. It will cut off padded 0's, so 01234 is a 4 digit number, but 0123 isn't.
void guess(int num_guess[], int size)
{
int number;
// if the length of the number isn't 4, try again until it is
do {
std::cin >> number;
if(std::to_string(number).length() != size)
std::cout << "You messed up the input. How hard could it be? Try again..." << std::endl;
} while(std::to_string(number).length() != size);
// by now, the size is definitely 4. insert it by digit into num_guess
for(int i = size-1; i >= 0; i++) {
num_guess[i] = number%10;
number /= 10;
}
}
#include <iostream>
#include <limits>
int main() {
int i = 0;
std::cout << "Please enter a number with four digits: ";
while( !(std::cin >> i) || !(i / 1000.0f >= 1.0f) )
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Invalid entry." << std::endl;
std::cout << "Please enter a number with four digits: ";
}
}
the std::cin.clear() clears all errors flags on current stream structure and std::cin.ignore() cleans up the input stream itself. Once we don't know the size of stream 'til this operation I have used the maximum possible value of a stream size to make sure any stream length could be cleaned.
add #include "math.h"
and change guess
void guess(int num_guess[], int size){
int number = 0;
bool firstTime = true;
do
{
if (!firstTime)
cout << " Error, try again " << endl;
firstTime = false;
cin >> number;
} while (number<pow(10, size-1) || number>=pow(10, size));
for(int i = size-1; i >= 0; i--){
num_guess[i] = number%10;
number /= 10;
}
}

Incorrect sum when adding up numbers

Ok, here's the code to add indefinite numbers and present the sum in c++. But error is that addition taking place is of first number and the last digits of all the other numbers. For example if i want to add 30 + 40 + 55 + 70, my program counts 30 + 0 + 0 + 5 + 0 = 35. What am I doing wrong?
#include <iostream>
using namespace std;
int main()
{
int num = 0;
int sum = 0;
cout << "Please enter numbers you want to add and end with N or n: ";
for (;;)
{
cin >> num;
sum += num;
cout << endl;
char indicator ('q');
cin >> indicator;
if (( indicator == 'n') || (indicator == 'N'))
break;
}
cout << "The sum is: " << sum << " ";
return 0;
}
I'm not sure I fully understand what you are trying to do, but if you want to add a list of integers terminated by an N (or n) character, then you should read each entity as a string, see if it's the terminating character, and if it's not, then convert it to an integer:
int sum = 0;
while (true) {
std::string s;
std::cin >> s;
if (tolower(s[0]) == 'n')
break;
sum += std::stoi(s);
}
Of course, the above code is only a skeleton -- in production code, you should always check if I/O operations succeeded and sanitize your input. A more complete example would be:
std::string s;
while (std::cin >> s) {
int ch = s[0];
if (ch > 0 && tolower(ch) == 'n')
break;
try {
sum += std::stoi(s);
} catch (const std::invalid_argument &e) {
// handle conversion error
break;
} catch (const std::out_of_range &e) {
// handle out-of-range error
break;
}
}
When you read the indicator, you extract the next non-blank character from the input stream; if the user has entered a number, this is the first digit. There are several ways of working around this.
The simplest is simply to loop on:
while ( std::cin >> num ) {
sum += num;
}
The input will fail if the next input doesn't have the form of a number (without extracting it). (This also has the advantage that you don't use the input if it fails for some reason.) This is more or less the standard idiom.
If you really do want to check for the 'n', you can use std::cin.peek() to look ahead one character, without extracting it. This doesn't skip white space, however, so you might want to do std::cin >> std::ws first. In this case, you'd probably want to wrap it in a function:
bool
terminationRequested( std::istream& source )
{
source >> std::ws;
return source.peek() == 'n' || source.peek() == 'N';
}
and then
while ( ! terminationRequested( std::cin ) ) {
int num;
std::cin >> num;
if ( ! std::cin ) {
// error...
}
sum += num;
}
You still have to check for a possible error after std::cin >> num. Otherwise, if the user enters "a", you'll end up in an endless loop, adding an undefined value to sum.
Alternatively, another frequent idiom is too use putback to return the indicator to the stream:
while ( std::cin >> indicator && indicator != 'n' && indicator != 'N' ) {
std::cin.putback( indicator );
std::cin >> num;
if ( ! std::cin ) {
// error...
}
sum += num;
}
Again, you'll have to handle the errors somehow. Using num if std::cin >> num fails is undefined behavior.
It's because you read the indicator character which will remove and ignore the next input digit by the user from the input stream.

How can I check if the user has entered valid value?

I'm writing a project and I have to check if the user has entered a valid value for specific things. For example, first case is to check whether he inputted an integer, which is no longer than 6 length and >0. I am working with struct, so my code is this:
#include <iostream>
using namespace std;
int dolzina_int(int vlez);
int main()
{
struct pole{
int sifra; // sifra na artiklot
string opis; // opis na artiklot
float cena; // edinecna cena
int vlez_kol; // vlezna kolicina
int izlez_kol; // izlezna kolicina
float dan_stapka; // danocna stapka
float iznos; // iznos
int datum; // datum na vlez i izlez (GGMMDD)
}artikli[100]; // maksimalen broj na artikli e 100
for (int i = 0; i < 5; i++){
cin >> artikli[i].sifra;
while(!(cin >> artikli[i].sifra) ||
(artikli[i].sifra < 0 || (dolzina_int(artikli[i].sifra) > 6)))
{
cout << "Error" << endl;
cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
return 0;
}
// funkcija za dolzina na integer
int dolzina_int(int vlez){
int dolzina = 1;
while(vlez > 0){
dolzina++;
vlez /= 10;
}
return dolzina;
}
So, my code seems to work, the first part, it does check if it's >6 or <0, but the second else if, it doesn't work properly to check if it's an integer or not. So my question is the following, how can i make sure that it's an integer value that the user enters and how can I make sure the length of integer is not >6 or the value is <0 and meanwhile, if it is, to make him re-enter it, and also check the newly entered value, as my code doesn't do that currently.
for (int i = 0; i < 5; i++){
artikli[i].sifra = 1;
do{
cout << "Enter a code: ";
while(!(cin >> artikli[i].sifra)){
cin.clear();
cin.ignore();
cout << "Invalid entry. Enter a new value: ";
}
}while(artikli[i].sifra > 0 && dolzina_int(artikli[i].sifra) > 6);
}
You should note that the extraction will only succeed if the contents read from the file can be used as a correct value of the type of the object (in this case the integer sifra). If it doesn't work, ios_base::failbit will be set in the stream state.
So what needs to be done is that when an incorrect value is given, we discard the wrong text, clear the stream state, and re-try the extaction. For example:
#include <iostream>
#include <string>
#include <limits>
int main()
{
for (int i = 0; i < 5; ++i)
{
while (!(std::cin >> artikli[i].sifra) ||
((artikli[i].sifra < 0) || (artikli[i].sifra > 6)))
{
std::cout << "Entered an incorrect value, try again.\n";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
// ...
}
}
First you should check this out:
http://www.cplusplus.com/reference/cctype/
Second, I think your over complicating it...
1) Read in int
2) check value of int
3) repeat
So I would do this
for (i = 0 to i < 5 add one to i)
while (entered value is not digit)
get digit until value is valid
Something like this:
for(i = 0; i < 5; i++) {
cout << "Enter the code" << endl;
cin >> artikli[i].sifra;
while(!is_digit) {
cout << "Invalid, please repeat" << endl;
cin >> artikli[i].sifra;
}
}
Assuming you want to restrict your input to integers and have them in a specific [min, max] range, you would do it like this:
int input = -1;
do
{
std::cout << "Enter a value in the range [min, max]: ";
while (!(std::cin >> input)) // while the input is invalid
{
std::cin.clear(); // clear the fail bit
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // ignore the invalid entry
std::cout << "Invalid Entry! Please Enter a valid value: ";
}
} while (min > input || max < input);
Where min and max are whatever values you are looking to keep the value between.