Error handling doubles with strings in C++ - c++

My assignment is to take test grades of students in a class room and return the highest, lowest, and the average. I am currently debugging for error that could be entered by the user. I have successfully fixed issues when the user inputs characters for the decimal test score values. What I'm having trouble with is if the user inputs "4k" the program excepts the 4 as a valid input but still gives the error when the program shouldn't approve the score as a valid input but should error and prompt for only numeral values.
I'll provide an output example
heres the code segment:
for (int i = 0; i < students; i++)
{
cout << "Please enter a score: " << flush;
cin >> array[i];
do{
if(cin.fail())
{
cin.clear();
cout<<"Error, that's not a decimal number. Please reenter: ";
std::cin.ignore(numeric_limits<streamsize>::max(), '\n' );
cin >> array[i];
}
}while(cin.fail());
}
Sample output error::
How many students are in class? 3
Please enter 3 scores
- - - - - - - - - - -
Please enter a score: jkl
Error, that's not a decimal number. Please reenter: jkl
Error, that's not a decimal number. Please reenter: 4k
Please enter a score: Error, that's not a decimal number. Please reenter: 0
Please enter a score: 3
4
0
3
The worstest score in the class is: 0
The bestest score in the class is: 4
The average score is: 2.33333

Note: Based on your tags, I'm going to assume that you are using c++11. If not this answer wont work.
Using what you already have, try the following method to get the user input:
#include <iostream>
#include <string>
#include <limits>
#include <stdexcept>
double getValidInput()
{
// Some variables for controlling how this works
std::string user_input ; // Used to store input
bool bad_input(true) ; // Set to true when the input is good
double value(0.0) ; // Value that will be returned
size_t pos(0) ; // Tells us when all of user_input was useable
cout << "Please enter a score: " << flush ;
cin >> user_input;
// Now do the thing
while (bad_input) {
try {
// Note that this may return an invalid string->double conversion
value = std::stod(user_input, &pos) ;
} catch (std::invalid_argument & err) {
// The input isnt a number that can be converted
// to a double
pos = 0 ;
}
// If the entire string was converted then all is good!
if (pos == user_input.size()){
bad_input = false ;
} else {
cout<<"Error, that's not a decimal number. Please reenter: ";
std::cin.ignore(numeric_limits<streamsize>::max(), '\n' );
cin >> user_input ;
}
}
return value ;
}
Ok, so what does all of this do? Lets start with
try {
// Note that this may return an invalid string->double conversion
value = std::stod(user_input, &pos) ;
} catch (std::invalid_argument & err) {
// The input isnt a number that can be converted
// to a double
pos = 0 ;
}
The user provides you with a string and you want to get a number from it (I'm assuming of type double). The above code is going to try to convert the user's input from a string to a double using std::stod(). Note that we also pass another variable pos which stores the length of the string that was able to be converted to a double.
Lets check your inputs:
In the case of your first input jkl a straight conversion to double cant be done. As a result std::stod throws an exception of type std::invalid_argument. The code catches that and sets pos=0. The following if statement notes that the length of the input string is longer than pos, so not all of the input was able to be converted, and the user has to try again.
In the case of your second input, 4k, std::stod can convert the string to a double up to the k, but at that point it stops. No exception is thrown, but pos is now one character smaller than the string, and again the user has to try again.
Now, you would insert this into your for-loop like so:
for (int i = 0; i < students; i++)
{
array[i] = getValidInput() ;
}
Hope that helps!

Related

c++ program to check entered number by user

I am new to programming, started with C++ quite recently and I use CLion IDE.
I need to solve something, but I am not sure how exactly and I need your help with a basic C++ console program.
if the user enters a ten-digit number and the fifth number is one, the output should be this word - "zadochno".
if the user enters a ten-digit number and the fifth number is two, the output should be this word - "redovno".
The user is expected to enter 2101162235 or similar.
In any case, the fifth element should be either 1 or 2.
Examples:
Option 1: input> 2101162235 -> output string "zadochno"
Option 2: input> 2101262235 -> output string "redovno"
I am able to only partially create the program:
#include<iostream>
int number;
cout << "Please, enter number: ";
cin > number;
//I believe there should be an if statement or for loop here:
if(){
}
Can you please help me?
You can take the input from the user as std::string and then check if the element at index 4 is 1 or 2 as shown below:
#include <iostream>
#include <string>
int main()
{
std::string input;
//take input from user
std::getline(std::cin, input);
//check if the 5th letter(at index 4 since indexing starts with 0) is '1' or '2'
if(input.at(4) == '1')
{
std::cout<< "zadochno"<<std::endl;
}
else if(input.at(4) == '2')
{
std::cout << "redovno"<<std::endl;
}
//this below shown for loop is optional. If you're sure that the user input contains only digits then you can skip/remove this for loop.
for(int i = 0; i < input.size(); ++i)
{
//check if the all the characters are digits of a number
if(std::isdigit(input[i]))
{
;//std::cout<<"yes digit";
}
else
{
std::cout<<"Please enter a valid number"<<std::endl;
}
}
return 0;
}
The output of the above program can be seen here.
Assuming the user does enter a 10 digit number (ie you don't need to check if they enter eg "foo" or "bar3000"), you can do the following:
Read the input as a std::string, not as int. User input is a string of characters always. Only if you need it you can get it converted to an integer. You do not need it as int. The n-th character of a std::string called user_input is user_input[n]. You just need to check whether the character in the middle is either '1' or '2'.
If you do need to check that the user did enter digits, you could use std::isdigit.

Problem with C++ understanding chars within float input

#include <iomanip>
#include <math.h>
int main() {
float x, a, b;
char conditions[] = { 'Y', 'y' };
std::cout << "Enter a number: ";
std::cin >> x;
if (!std::cin) {
std::cout << "error";
}
else {
a = x * x;
std::cout << "A is: " << a << std::endl;
}
}
//I need to create an if statement or a loop to
//ask to input float x again if char conditions were input instead.
I have a problem I've been trying to find an answer to for weeks. From the code you can see that !std::cin condition won't accept any chars, therefore an error will be printed. I however need an exception where if 'y' || 'Y' is inputted it loops back to the std::cin >> x; and asks for a float value again until it is provided, however if any other char is inputted like 'h' it would obviously go back to the error message.
I've tried multiple if statements, checked recursives but no luck. The problem is that I can't make the exceptions because if 'y' is inputted then the program doesn't understand it because the std::cin >> is asking for a number not a char...
The task description is unclear. On the one hand, you state that you want the program to ask for a float value again, until one is provided. On the other hand, you state that this should only happen when the user enters "y" or "Y", but when the user enters anything else, it should print an error message instead. This is contradictory.
If you want your program to check whether the user enters a certain character, then you must read the input as a string, instead of as a number. I recommend that you use std::getline for this.
Once you have determined that the user did not enter "Y" or "y", you can use the function std::stof to convert the string to a number.
When the user doesn't enter a number, I don't understand why you say you want to loop back to the input on "y" and "Y", but want to print an error message instead on all other inputs. However, if that is what you want, then this is how you can implement it:
#include <iostream>
#include <string>
int main()
{
std::string input;
float x;
for (;;) //infinite loop, equivalent to while(1)
{
//prompt user for input
std::cout << "Enter a number: ";
//read one line of input
std::getline( std::cin, input );
if ( !std::cin )
throw std::runtime_error( "unexpected stream error!" );
//check if "y" or "Y" was entered
if ( input == "y" || input == "Y" )
continue;
//attempt to convert input to a number
try
{
x = std::stof( input );
}
catch ( std::invalid_argument )
{
printf( "Unable to convert to number\n" );
break;
}
catch ( std::out_of_range )
{
printf( "Number is out of range\n" );
break;
}
std::cout << "You entered the following number: " << x << "\n";
}
}
This program works as intended (based on your contradictory description). If you enter "y" or "Y", it will loop back to the prompt for user input:
Enter a number: y
Enter a number: y
Enter a number: y
Enter a number: 67.5
You entered the following number: 67.5
If you instead provide a non-number input that is not "y" or "Y", it will print an error message, instead of looping back to the input:
Enter a number: y
Enter a number: y
Enter a number: j
unable to convert to number
This behavior does not make sense, but it appears to be what you are asking for.
This program does have one small problem, though. It will accept 6sdfjloj as valid input for the number 6:
Enter a number: 6sdfjloj
You entered the following number: 6
It would probably be more meaningful to reject such input with an error message.
Doing this is also possible, by passing a second argument to std::stof, in order to determine how many characters were converted. If not all characters were converted, you can reject the input. On the other hand, you may want to accept trailing whitespace characters (as determined by std::isspace), but reject the input if there are any other trailing characters. This would make sense: Because std::stof accepts leading whitespace characters, it makes sense to also accept trailing whitespace characters.
In my opinion, it would be more meaningful to demonstrate these programming possibilities with the following task:
The user should instead be prompted with the following message:
"Please enter a number, or enter "q" to quit: "
If the user enters "q" or "Q", the program should exit.
Otherwise, it should determine whether the user entered a valid number. If the input is a valid number, the program should say so and print the number, otherwise it should print an error message. Either way, the program should loop back to the initial prompt.
The solution to this problem would be the following:
#include <iostream>
#include <string>
#include <cctype>
int main()
{
std::string input;
float x;
std::size_t pos;
for (;;) //infinite loop, equivalent to while(1)
{
//prompt user for input
std::cout << "Please enter a number, or enter \"q\" to quit: ";
//read one line of input
std::getline( std::cin, input );
if ( !std::cin )
throw std::runtime_error( "unexpected stream error!" );
//check if "q" or "Q" was entered
if ( input == "q" || input == "Q" )
{
std::cout << "Quitting program!\n";
break;
}
//attempt to convert input to a number
try
{
x = std::stof( input, &pos );
}
catch ( std::invalid_argument )
{
printf( "Unable to convert to number!\n" );
continue;
}
catch ( std::out_of_range )
{
printf( "Number is out of range!\n" );
continue;
}
//make sure that any trailing characters are whitespace,
//otherwise reject input
for ( std::size_t i = pos; input[i] != '\0'; i++ )
{
if ( !std::isspace( static_cast<unsigned char>(input[i]) ) )
{
std::cout << "Unexpected character encountered!\n";
//we cannot use continue here, because that would jump
//to the next iteration of the innermost loop, but we
//want to jump to the next iteration of the outer loop
goto continue_outer_loop;
}
}
std::cout << "Input is valid, you entered the following number: " << x << "\n";
continue_outer_loop:
continue;
}
}
This program has the following output:
Please enter a number, or enter "q" to quit: 67.5
Input is valid, you entered the following number: 67.5
Please enter a number, or enter "q" to quit: 32.1
Input is valid, you entered the following number: 32.1
Please enter a number, or enter "q" to quit: sdfjloj
Unable to convert to number!
Please enter a number, or enter "q" to quit: 6sdfjloj
Unexpected character encountered!
Please enter a number, or enter "q" to quit: q
Quitting program!
As you can see, it now also properly rejects input such as 6sdfjloj.
Note that this program contains one goto statement. It was appropriate to use it, in order to jump out of a nested loop. This is considered an acceptable use of goto. However, you should not use goto except in rare situations, in which there is no cleaner alternative. So please don't get used to using it.
Seems like you want to take a floating number as input.
If the user gives any invalid input like a character, you want to show an error message and take input again.
If this is the case, taking input using string might be a better way.
Take the input as a string, check if the string contains any additional character other than digits and a dot.
If it does, take input again. So you can use a loop to do that.
If you get a valid string, then calculate the result and stop taking input.
Sample code:
int main()
{
float x, a, b;
char conditions[] = { 'Y', 'y' };
string input;
while(true)
{
std::cout << "Enter a number: ";
std::cin >> str;
if (input_contains_any_other_character)
{
std::cout << "error";
// going back to the beginning of the while loop
}
else
{
// first convert the string and keep it in the variable x
// then calculate your result
a = x * x;
std::cout << "A is: " << a << std::endl;
break; // stop taking further input
}
}
}

Hi I want user to enter 5 numbers and then output the sum in the end

I have used a loop for that:
int number1;
int sum=0;
for(int i =1; i<6; i++){
cout<<"Enter number:\n";
cin>>number1;
sum+=number1;
}
cout<<sum;
cout<<"Total Sum is = "<<sum<<"\n";
return 0;
}
My question is how can I print first statement like this ...
"Enter first number"
Enter Second number" and so on
Whenever you are reading numbers (or any value for that matter), you must check the stream-state (see: std::basic_istream State Functions). You have four stream states you must test following every input:
.bad() or .eof(). If badbit is set an unrecoverable error occurred, and if eofbit is set, there is nothing more to read (you can combine both into a single test that exits if either are set)
.fail() is set when a read error occurs, such as the user entering "FIVE" instead of 5 where integer input is expected. You handle failbit being set by calling .clear() to clear failbit and then call ignore() to empty the characters causing the failure before your next read attempt, and finally
.good() - valid input was received from the user, you can proceed to the next input.
By validating your input here, you can Require the user provide 5 valid integer values for you to sum. Do not use a for loop, instead use a while (or do .. while();) and only increment your counter when good input is received.
Putting that altogether, you can do:
#include <iostream>
#include <limits>
int main (void) {
int number = 0,
sum = 0;
const char *label[] = { "first", "second", "third", "fourth", "fifth" };
while (number < 5) /* loop continually until 5 int entered */
{
int tmp; /* temporary int to fill with user-input */
std::cout << "\nenter " << label[number] << " number: ";
if (! (std::cin >> tmp) ) { /* check stream state */
/* if eof() or bad() exit */
if (std::cin.eof() || std::cin.bad()) {
std::cerr << " (user canceled or unreconverable error)\n";
return 1;
}
else if (std::cin.fail()) { /* if failbit */
std::cerr << " error: invalid input.\n";
std::cin.clear(); /* clear failbit */
/* extract any characters that remain unread */
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
else { /* on succesful read of int, add to sum, increment number */
sum += tmp;
number++;
}
}
std::cout << "\nsum: " << sum << '\n';
}
Now your code will gracefully handle an invalid input without exiting just because a stray character was entered.
Example Use/Output
When you write an input routine, go try and break it. Enter invalid data and make sure you handle all error cases correctly. If something doesn't work right, go fix it. Repeat until you input routine can handle all corner-cases as well as the cat stepping on the keyboard:
$ ./bin/sumintlabel
enter first number: 3
enter second number: four five six seven!!
error: invalid input.
enter second number: 4
enter third number: 5
enter fourth number: 6
enter fifth number: 7
sum: 25
Form good habits now regarding handling input, it will pay dividends for the rest of your programming career. Let me know if you have questions.
if you need to print the words "first"... untill "fifth" then I'd do it like this:
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
int number1;
int sum=0;
string positions[5] = {"first", "second", "third", "fourth", "fifth"};
for(int i = 0; i<5; i++){
cout<<"Enter the " << positions[i] << " number:" << endl;
cin>>number1;
sum+=number1;
}
cout<<"Total Sum is = "<<sum<<"\n";
return 0;
}
I used an array of strings to display the words and changed the for loop to start at 0 so that we can go through the array positions and add the 5 numbers as well. If you just want to use: 1st, 2nd, 3rd... then you could change the for loop to what it was and do:
cout<<"Enter the " << i << "st" << " number:" << endl;
But for this you would have to use the if statement to print the right endings("st", "rd", "nd"). I think it would take longer for it to run but its miliseconds so we wouldn't even notice hahaha.
Hope it helped :)
You can use switch():
#include <iostream>
using std::cin;
using std::cout;
using std::string;
int main() {
int number1;
int sum = 0;
for(int i = 1; i < 6; i++) {
string num;
switch(i) {
case 1:
num = "first";
break;
case 2:
num = "second";
break;
//and 3 4 5 like this
}
cout << "Enter " << num << " number:\n";
cin >> number1;
sum += number1;
}
cout << "Total Sum is = " << sum << "\n";
return 0;
}
or you can use struct or containers like vector (in fact you have to use containers if you want to get a huge number of data.)

Input Validation to Accept Only Int Values

I am designing a program to read several user inputs and the specifications include that they are always positive integers. These values will then be modified to keep only the hundreds value then and used to display a bar chart. The problem I am having is with the program's input validation. Should the user disregard instructions and enter a decimal value instead of an integer, immediately the remainder of the program's output displays without the ability for the user to input any additional values. My attempt at catching this problem is shown below in the if statements.
int main() {
int store1;
int store2;
cout << "Enter today's sales for store 1:" << endl;
cin >> store1;
if(store1 < 0 || ((store1 % 1))!=0)
cout << "Value of sales must be an integer greater than zero" << endl;
cout << "Enter today's sales for store 2:" << endl;
cin >> store2;
if(store2 < 0 || ((store2 % 1))!=0)
cout << "Value of sales must be zero or greater" << endl;
If the user inputs a decimal the program output is:
Enter today's sales for store 1:
400.34
Enter today's sales for store 2:
Enter today's sales for store 3:
Value of sales must be zero or greater
Enter today's sales for store 4:
Enter today's sales for store 5:
SALES BAR CHART
(Each * = $100)
Store 1: ****
Store 2:
Store 3:
Store 4:
Store 5:
Process finished with exit code 0
If I had to guess, the values after the decimal (in this case 3 and 4) were passed to input for store 2 and 3 respectively, and since they were less than 100, an * was not displayed next to the appropriate store. I haven't included my code to get hundreds values and output *'s for readability sake, and because I'm almost positive my problem is related to cin.
To summarize, I need to validate user input so that only a positive integer is accepted through any input method. Any help is greatly appreciated!
You can use strtoll to convert and validate an input string encoding an integer.
Value read from cin is of string type and then it is passed to get_positive_integer() that is a wrapper to strtoll, converting and validating the string, it returns -1 when the string is not at the expected format, else it returns the decoded positive integer. Note the use of an intermediate long long type to easy check for overflow, and the use of getline to read a whole input line without breaking strings at spaces which would pass inputs of first line to next readings.
#include <climits>
#include <cstdlib>
#include <iostream>
#include <string>
using namespace std;
int get_positive_integer(const string& str)
{
const char* s = str.c_str();
char* end;
long long val = strtoll(s, &end, 10);
if (end == s) {
// str was not encoding an integer.
return -1;
}
if (*end) {
// Stopped reading before the end of the string
// the whole string was not an integer.
return -1;
}
if (val > INT_MAX) {
// Too big to fit in an int type
return -1;
}
if (val <= 0) {
// Not a positive integer.
return -1;
}
return val;
}
int main()
{
string input;
cout << "Enter a positive integer:" << endl;
getline(cin, input);
int value = get_positive_integer(input);
if (value < 0) {
cout << "Not a valid positive integer" << endl;
return EXIT_FAILURE;
}
cout << "Value: " << value << endl;
return EXIT_SUCCESS;
}

Adding string characters to a for loop after converting int to string in c++

So I'm busy with a school project and new to C++ and I'm a bit stuck, so here is the question:
When your program begins, it should prompt the user to enter an integer number greater than or equal to 1. This number should be assigned to a variable called control.
You must create a for loop that iterates a number of times equal to control. Each time it iterates, it must append a numeric digit to a string, with the first digit added being 1, and for each iteration, the next number is the previous number multiplied by the original number input. Additionally, the spaces that would ordinarily be between the numbers must instead be the ”#” symbol.
Once the loop is finished iterating, it must display the string that you have constructed.
As a hint, consider the use of string streams for converting between integer to string.
Examples of this program are below:
Please enter a number: 3
1#3#9
Please enter a number: 5
1#5#25#125#625
Please enter a number: 1
1
And here is my code so far :
int main()
{
int control;
int value;
string final;
int test;
stringstream convert;
cout << "Please enter a number: " << endl;
cin >> control;
if (control >= 1)
{
value = 1;
for (int count = 2; count <= control; count++)
{
value = value * control; <---- SO IM STUCK HERE
convert << value; TRYING TO INSERT "#"
final = convert.str() + "#"; BETWEEN THE VALUES
}
cout << "1#" << final << endl;
}
else
{
cout << "Please enter a valid number!" << endl;
}
system("pause");
return 0;
}
Thanks in advance for the help.
Okay so it seemed to be a very simple fix, I feel like an idiot but thanks for the help.
Old code : convert << value;
New code : convert << '#' << value;