HiveBrain v1.2.0
Get Started
← Back to all entries
debugcppMajor

Prompting for two integers and dividing, using exceptions to handle divide-by-zero errors

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
exceptionsdividehandlepromptingtwofordividingusinganderrors

Problem

I'm trying to learn exception handling in C++.

I wanted to read two integers and divide them and print them.

The code should throw an exception when the second integer is zero, ask the user to re-enter the second integer, and then complete the divide operation.

I coded something like this:

#include 
#include 

using std::cin;
using std::cout;
using std::endl;

int main() {
    int i1, i2;
    cout > i1;
    try {
        first:
        cin >> i2;
        if (i2 == 0)
            throw 0;
        else
            cout << i1 / i2 << endl;
    }
    catch (...) {
        cout << "Second integer cannot be zero , please enter a valid integer" << endl;
        goto first;
    }
    system("pause");
    return 0;
}


However, I was advised not to use goto at all costs.

Can anyone give me some alternative way?

Solution

Exceptions are for exceptional cases


I'm trying to learn exception handling in C++.

This is a very bad example to learn exceptions. They are meant for situations where you cannot know that there is something wrong. For example if you want to use std::vector but you're out of memory:

std::vector vec(4000000000LL); // will likely throw std::bad_alloc


I'll add an exercise for you at the end of this review. But let's have a look at your code.

A review of your code

You're not using using namespace std, which is a great plus.

However, you include `, which isn't necessary here. You don't use any of the standard exception, instead, you throw 0. However, system is in . You should include that one instead.

Next, naming.

int i1, i2;


Those names don't have any meaning. What is
i1? What is i2? Naming is hard, but it's important. You're going to use them as numerator and denominator, or as dividend and divisor, so call them appropriately:

int numerator, denominator;


Getting rid of
goto

Now to your
try block. Don't. Use. goto. You want to repeat the block until you didn't get 0. We can do that with a simple while:

int main (){
    int numerator, denominator;

    cout > numerator; 

    // continue forever                               (1)
    while(true) {
        try {
            cin >> denominator;
            if (denominator == 0)
                throw 0; // this will "go to" catch   (2)

            cout << numerator / denominator << endl;
            break; // we didn't throw, we can stop    (3)
        }
        catch (...) {
            cout << "Second integer cannot be zero , please enter a valid integer" << endl;
        }
    }

    system("pause");
    return 0;
}


A "clean" version without exceptions

However, that's not how I would write the program, since exceptions are meant for exceptional cases. I would write

#include 
#include 

int main() {
    int numerator, denominator;

    std::cout > numerator >> denominator;

    while(denominator == 0) {
        std::cout > denominator;
    }

    std::cout << (numerator / denominator) << std::endl;

    system("pause");
    return 0;
}


As you can see, exceptions aren't really necessary to keep the user from entering a zero. Furthermore, the control flow is a lot easier to read.

Note that
system("pause"); won't work on Linux, since there is no application called pause. If possible, try to use your IDEs features to keep your console window alive even after your program finished, or have the output logged somewhere, or use it in the CMD/PowerShell.

Exception exercise

We need a better exercise for your exceptions. How about this?

int divide(int numerator, int denominator) {
    if(denominator == 0)
        throw "divide: division by zero";
    return numerator / denominator;
}


This is a valid place for an exception. A function has only a single return value, so it can only tell you that something is wrong with an exception*.

Exercise: Try to use that function in your code and handle the exception. Also show the exception to the user, they're probably interested in what went wrong.

You should use the code similar to

std::cout << divide(numerator, denominator) << std::endl;


that is you don't check the
denominator. Note that this is still a contrived example.

* Technically, that's not true. You can use references, pointers, or wrap the return value in some
struct`/variant, but let's keep things simple

Code Snippets

std::vector<int> vec(4000000000LL); // will likely throw std::bad_alloc
int i1, i2;
int numerator, denominator;
int main (){
    int numerator, denominator;

    cout << "Give two integers" << endl;
    cin >> numerator; 

    // continue forever                               (1)
    while(true) {
        try {
            cin >> denominator;
            if (denominator == 0)
                throw 0; // this will "go to" catch   (2)

            cout << numerator / denominator << endl;
            break; // we didn't throw, we can stop    (3)
        }
        catch (...) {
            cout << "Second integer cannot be zero , please enter a valid integer" << endl;
        }
    }

    system("pause");
    return 0;
}
#include <iostream>
#include <cstdlib>

int main() {
    int numerator, denominator;

    std::cout << "Please enter two integers." << std::endl;
    std::cin >> numerator >> denominator;

    while(denominator == 0) {
        std::cout << "Second integer cannot be zero. Try again." << std::endl;
        std::cin >> denominator;
    }

    std::cout << (numerator / denominator) << std::endl;

    system("pause");
    return 0;
}

Context

StackExchange Code Review Q#155164, answer score: 26

Revisions (0)

No revisions yet.