Calculator. How to fix if user types letters isto numbers

Pages: 12
Hi, Im trying to learn som C++
Im trying to make a calcylator.
If the user types ex (nr1/n2) 2/b it crashes.
How do I define nr1 nr2 to only digits?

Oh, does anyone understand my dilema?

Pls help

Note that Im a complete noob. tried som Basic in the eighties but not much.


using namespace std;
#include <iostream>

float main()
{
float nr1, nr2; //skapar variabler, alltså tal 1 och tal 2//
cout << "write two numbers\n";
//Här får användaren skriva in sina siffror//
cin >> nr1;
cin >> nr2;

//Själva uträkningarna//
float summa = nr1 + nr2;
cout << "Addition" << endl << nr1 << "+ " << nr2 << " =" << summa << endl;

float diff= nr1 - nr2;
cout << "Subtraktion" << endl << nr1 << "- " << nr2 << " =" << diff << endl;

float produkt = nr1 * nr2;
cout << "Multiplikation"<<endl << nr1 << "* " << nr2 << " =" << produkt << endl;

float kvot = nr1 / nr2;
if (nr2 == 0) // Om siffra 2 är noll går det ju inte att dividera//
cout << "Division"<< endl << "går inte att dividera med noll, starta om och skriv in en annan siffra";
// så därför får användaren starta om igen//

//Om det går att dividera så skrivs denna rad ut//
else
cout << "Division"<< endl << nr1 << "/ " << nr2 << " =" << kvot << endl;

cout <<endl<< "press Enter to exit";
system("pause>0");
}
Last edited on
Hi, we would love to help you with your calcylator. Show us the code that is causing the issue, and tell us specifically examples of input that should fail, and examples of input that should succeed.
I have added it into the topic now
My understanding is that you have to trust your user will enter in the appropriate values if you are just using cin. If you want to check your user input you can create a function which does this and pass the user input into it. When writing full-stack programs there is usually some validation that happens at the user-level that would accommodate this. Since you don't have this kind of interface cin is going to take whatever you give it. You could give it a string here and it would attempt to caste it...it's going to do its best, but it's never going to auto-validate for you.

Here is an example of that https://www.thetopsites.net/article/53549674.shtml
1) main() should have a return type of int, not float.

2) for only valid numeric input. This is a common issue. The problem is with stream extraction as entering a non-valid input causes the stream to enter a fail state. You need to test for this and if it occurs set the stream state to good and to remove any existing bad input from the stream.

This can be done in a function something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include <string>
#include <limits>

float getNum(const std::string& prm)
{
	float num;

	while ((std::cout << prm) && !(std::cin >> num)) {
		std::cout << "Invalid number entered\n";
		std::cin.clear();
		std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
	}

	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

	return num;
}

using namespace std;

int main()
{
	const float nr1 = getNum("Enter a number: ");
	const float nr2 = getNum("Enter another number: ");

	const float summa = nr1 + nr2;
	cout << "Addition" << endl << nr1 << "+ " << nr2 << " =" << summa << endl;

	const float diff = nr1 - nr2;
	cout << "Subtraktion" << endl << nr1 << "- " << nr2 << " =" << diff << endl;

	const float produkt = nr1 * nr2;
	cout << "Multiplikation" << endl << nr1 << "* " << nr2 << " =" << produkt << endl;

	if (nr2 == 0)
		cout << "Division" << endl << "går inte att dividera med noll, starta om och skriv in en annan siffra";
	else {
		const float kvot = nr1 / nr2;

		cout << "Division" << endl << nr1 << "/ " << nr2 << " =" << kvot << endl;
	}
}


Note that with this 'simple' method, then entering something like 2..4 becomes 2. with the extra .4 ignored. Same as 6q. This becomes 6 with the q ignored. If you want that the whole of the input is a valid number then this can be done but it's slightly more involved.
Last edited on
I was playing around with something like this awhile back. The way id suggest going about it is having the user input be saved as a string and then loop through the string and do some verification of whats inside of it b4 moving on to the next stages of the program. I will say that doing a legit calculator that goes well beyond what you have here is some very serious buisness. Theres many different scenarios to consider and the code will get very complicated in a hurry. As a pro tip, converting a char to a number only requires subtracting 48 from the char. That only works for single digits. If the number is greater than 9 you have to add zeros to it. If you're converting a char number that is a decimal to a float you have divide the numbers after the decimal point by powers of 10 b4 its added to the resulting number. From what im describing you can see how fast this all becomes a pain. Also use the ascii table.
Last edited on
It seems another person recently asked this question here: http://www.cplusplus.com/forum/beginner/272713/
With a similar answer!
Yes :) might be worth updating the title of this topic to be....more clear. Then others can find it too!
title "fixed". Im new to this so pls have patience with me.
@Seeplus

Could u add comments.
Its all blury for me. U have to remember i´m new to this.
First open c++ book last week :)
The real problem is that your original requirement 'define nr1 nr2 to only digits' is not provided 'as is' within the C++ language. The provided code is one of the simplest for this functionality (but has limitations such as 2..4 treated as 2 etc. To only allow all input to be a valid number is more complicated - and that code deals with float. If you wanted an integer, or double etc then it would have to be changed. Because of the way that C++ deals with input this is much more complicated than it could have been.

Nobody would expect you to really understand that code with your current knowledge. Howecer for info here's some comments.

The whole code is based around the while loop which continues executing the specified code while the given condition is true. The condition is (std::cout << prm) && !(std::cin >> num)

This has two expressions combined using && which is logical and. So for the condition to be true, both expressions must be true.

The first is (std::cout << prm). std::cout returns an ostream object which is treated as 'true' if the output was done OK and false if there was a stream error. Assuming the output was OK, then this part is true.

The nect part is !(std::cin >> num). This tries to extract a number from the input stream (the keyboard) and if successful the input stream is OK and treated as true. ! is the logical not operator so true becomes false, the result of this part becomes false and true && false is false. So the while condition fails and the while loop is exited. Fine if a valid number is entered.

If say qq is entered, then this is not a valid number, the stream extraction fails and the input stream is put into a 'fail' state. The returned input stream object is treated as false, the ! negates this false to true and you have true && true which is true. So the while loop body is executed.

This outputs an appropriate message. The input stream is in a failed state and no further input can be obtained when it is in this state. So the state is reset to good using .clear(). However the invalid entered chars which caused the cin >> extraction to fail are still in the input buffer and have to be removed - otherwise the cin >> would immediately fail again - an infinite loop!

These 'bad' chars are removed by the .ignore() statement which removed from the stream all chars up to and including the specified one - \n in this case. The bad chars are now not in the input stream, the while condition is evaluated again, the prompt is displayed, the input obtained etc etc etc until good input is got.

However, good input is only up to the point that it can be extracted. If 2..4 is entered, the 2. is extracted as good but after the while loop terminates the .4 is still in the input buffer and any next input would use this - which is probably not what is wanted. Hence the final .ignore() which removed any 'excess' chars from a valid input ready for the next input.

And this is the 'simple' way of doing it!!

Enjoy your C++ studies :) :)

PS Which book are you using?
Pretty good effort. Suggestions below might be useful:

1. use std:: prefix instead of using namespace std;
2. see while structure and how input check can be done
3. OK to have new variable for result but it's not mandatory
4. Restrict program/output line widths to the conventional console 80 characters
5. '\n' better than std::endl, can incorporate in strings as shown
6. system calls of any kind are not the best, better to avoid. And they are mostly useless for any GUI app.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>

int main()
{
    double nr1 = 0, nr2 = 0; //skapar variabler, alltså tal 1 och tal 2//
    while (std::cout << "write two numbers\n" && !(std::cin >> nr1 >> nr2) )
    {
        std::cout << "Wrong! Do it again\n";
        
        std::cin.clear();
        std::cin.ignore(1000,'\n');
    }
    
    //Själva uträkningarna//
    std::cout
    << "Addition\n"
    << nr1 << " + " << nr2 << " = " << nr1 + nr2 << '\n';
    
    std::cout
    << "Subtraktion\n"
    << nr1 << " - " << nr2 << " = " << nr1 - nr2 << '\n';
    
    std::cout
    << "Multiplikation"<< '\n'
    << nr1 << " * " << nr2 << " = " << nr1 * nr2 << '\n';
    
    if ( nr2 == 0)
    {// Om siffra 2 är noll går det ju inte att dividera//
        std::cout
        << "Division\n"
        << "går inte att dividera med noll, starta om och\n"
        << "skriv in en annan siffra\n";
        // så därför får användaren starta om igen//
        
        //Om det går att dividera så skrivs denna rad ut//
    }
    else
        std::cout
        << "Division\n"
        << nr1 << " / " << nr2 << " = " << nr1/nr2 << '\n';

    return 0;
}



write two numbers
a 3
Wrong! Do it again
write two numbers
3 bbb
Wrong! Do it again
write two numbers
2 3
Addition
2 + 3 = 5
Subtraktion
2 - 3 = -1
Multiplikation
2 * 3 = 6
Division
2 / 3 = 0.666667
Program ended with exit code: 0
2. see while structure and how input check can be done


Personally I'm not a fan of entering multiple values together for interactive input. IMO it's better to display a prompt, obtain valid input, display prompt, obtain valid input etc.

5. '\n' better than std::endl, can incorporate in strings as shown


For console output mixed with input it really doesn't matter much. The difference is that endl outputs a newline and flushes the output buffer whereas just outputting '\n' only outputs a newline and doesn't flush the buffer. When outputting to files or for a lot of console output, using endl with the flush will slow performance because of the extra buffer flushes. But when doing interactive console I/O, the slight extra time taken to perform the flush with endl isn't noticeable and ensures that all output is actually output. If you have a sequence of outputs to the console then I would suggest using \n for all except the last and endl for the last. Having several endl within console output sequence is not required and for file output is not recommended at all. Closing a file flushes all buffers. Also using a cin flushes the cout output buffer.


6. system calls of any kind are not the best, better to avoid. And they are mostly useless for any GUI app.


yeah. Now you know about system(), IMO you should forget about it! For anything you might want to use it for, there's better ways.

Last edited on
Hello Hary swe,


PLEASE ALWAYS USE CODE TAGS (the <> formatting button), to the right of this box, when posting code.

Along with the proper indenting it makes it easier to read your code and also easier to respond to your post.

http://www.cplusplus.com/articles/jEywvCM9/
http://www.cplusplus.com/articles/z13hAqkS/

Hint: You can edit your post, highlight your code and press the <> formatting button. This will not automatically indent your code. That part is up to you.

You can use the preview button at the bottom to see how it looks.

I found the second link to be the most help.



Your code that I changed because line numbers are different:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <limits>  // <--- Added.

using namespace std;  // <--- Changed. Moved here.

int main()  // <--- Changed. "main" returns an "int".
{
    double nr1, nr2; //skapar variabler, alltså tal 1 och tal 2//

    cout << "write two numbers\n\n";
    //Här får användaren skriva in sina siffror//
    
    while (std::cout << "Enter first number: " && !(std::cin >> nr1))
    {
        std::cout << "\n     Invalid Input! Must be a number.\n\n";

        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.
    }

    std::cout << "Enter second number: ";
    cin >> nr2;

    //Själva uträkningarna//
    double summa = nr1 + nr2;
    cout << "\nAddition\n" << nr1 << " + " << nr2 << " = " << summa << "\n\n";  // <--- Changed.

    double diff = nr1 - nr2;
    cout << "Subtraktion" << endl << nr1 << "- " << nr2 << " =" << diff << "\n\n";

    double produkt = nr1 * nr2;
    cout << "Multiplikation" << endl << nr1 << "* " << nr2 << " =" << produkt << "\n\n";

    double kvot = nr1 / nr2;

    if (nr2 == 0) // Om siffra 2 är noll går det ju inte att dividera//
        cout << "Division" << endl << "går inte att dividera med noll, starta om och skriv in en annan siffra";
    // så därför får användaren starta om igen//

    //Om det går att dividera så skrivs denna rad ut//
    else
        cout << "Division" << endl << nr1 << "/ " << nr2 << " =" << kvot << "\n\n";

    //cout << endl << "press Enter to exit";  // <--- Kind of a duplicata as "system("pause")" has  its own message.
    std::cout << "\n\n";
    system("pause");  // <--- Changed.
}

Putting line 4 asa the first line may work, but it is not needed to cover the header files,. Just the code that follows.

As mentioned "main" returns an "int". You can return some different, but it will be converted to an "int".

These days a "double" is the preferred floating point type because it has more precision than a "float.

Starting at line 13 this is one option you could use. If you look at the while condition and loop you will come to understand it. If not let me know.

You will need to do the same for "nr2".

On line 26 I added a couple of spaces, which you will need to do for the others.

Starting in either the 2011 or 2014 standards the "\n", (new line character), has replaced the "endl". Also a "cout" followed by "cin" will flush the output buffer before the "cin" takes any input. This can be used to your advantage.

For line 36 you could change this to a while loop and allow the user to enter something greater than (0.0) before the division.

Also when you write if (nr2 == 0) my IDE considers the (0) to be an "int" Although it will work it is a type mismatch comparing a "double" to an "int".

Line 44 the comment should be enough explanation.

It is best to avoid using system anything in your program. This could make the program vulnerable to attack.

I have found this to be a good replacement for system("pause");.
1
2
3
4
5
// A fair C++ replacement for "system("pause")". Or a way to pause the program.
// The next line may not be needed. If you have to press enter to see the prompt it is not needed.
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.
std::cout << "\n\n Press Enter to continue: ";
std::cin.get();


Andy
Hello Hary swe,

Sorry I pressed "submit" to early.


write two numbers

Enter first number: a

     Invalid Input! Must be a number.

Enter first number: 2
Enter second number: 3

Addition
2 + 3 = 5

Subtraktion
2- 3 =-1

Multiplikation
2* 3 =6

Division
2/ 3 =0.666667



Press any key to continue . . .


The error message you can change to what you like.

Andy
@Handy Andy

Starting at line 13 this is one option you could use. If you look at the while condition and loop you will come to understand it. If not let me know.

You will need to do the same for "nr2".


This has been covered in my previous posts using a function to obtain the number from the keyboard which has been explained.

Starting in either the 2011 or 2014 standards the "\n", (new line character), has replaced the "endl".

I'm not weighing in on the '\n' vs. std::endl controversy. I don't care whether you flush every line or not.

I am just curious about the above statement. The '\n' character has been around since C days. The std::endl stream manipulator has been around since long before c++98.

What changed in 2011 or 2014?
What changed in 2011 or 2014?


Nothing AFAIK. cppreference doesn't mention any changes since first introduced.

See https://en.cppreference.com/w/cpp/io/manip/endl

Last edited on
Looking at the cppreference link a comment mentions "on some platforms, stdout flushes on '\n'." The example program desyncs std::cout with stdout.

Another instance where there are possible differences between implementations.

Apparently with the C11 standard '\n' will flush a buffered stream.
https://code-examples.net/en/q/34393

Personally I prefer to use '\n' instead of std::endl. A matter of choice*. So far output to the console screen has not presented a "real time" display issue that I've noticed.

YMMV.

*less typing and fewer operator<< function calls:
1
2
std::cout << "Hello World\n";
std::cout << "Hello World" << std::endl;
Pages: 12