Returning something to main() so it can end the program

Pages: 12
Hi, so I am building a calculator with extra features such as checking if a number is prime and finding a gcd of 2 numbers. So anyway, I decided to write a function for each of these, this is an example of a function to find gcd:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
long double gcd(double x, double y)
{
    if ((cin.fail() == true) || (x < 1) || ((x - floor(x)) != 0) || (y < 1) || ((y - floor(y)) != 0))
    {
        return 1.5;
    }
    x3 = x2 = x;
    y3 = y2 = y;
    while (x2 != 0 && y2 != 0)
    {
        if (x2 > y2)
        {
            x2 %= y2;
        }
        else
        {
            y2 %= x2;
        }
    }
    return y2+x2;
}


By the way, x3 and y3 are the outputs in the main function, since I can't use y2 and x2. Also can't use x and y, because if a number I entered is a large integer like 626541657 it returns it as 6.265417e8, loosing precision and looking stupid.

As you can see, the answer can only be an integer, so I used a double to return 1.5 to the main function, and if it gets such a value, it ends the program:

1
2
3
4
if (gcd(x, y) == 1.5)
{
    return 0;
}


Where I ran into a problem is when I wanted to do the same for addition, since I made it so you can add double numbers too, let's say 2.4+3.2=5.6, I can't return a double value to the main function so it knows there's an error and quits. Is there a way I can I stop the program while executing a function I called from main function without returning a value to the main function?

If I return the value 1.5 to the main and tell it to stop if it gets that and I add 1 and 0.5, the program quits. Same goes for any double number/integer.

Tl;dr Is there a way to do the same as return 0; in the main function, just while executing a function I called from the main function?

Thanks!
Last edited on
You should probably use std::int64_t or long long if you want large integer types, rather than doing it with floating point math.

As for your 1.5 hack, you should use exception handling instead - this is a great example of where exceptions are useful.
Ok, so my gcd function looks like this now:
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
long double gcd(double x, double y)
{
    try
    {
        if ((cin.fail() == true) || (x < 1) || ((x - floor(x)) != 0) || (y < 1) || ((y - floor(y)) != 0))
        {
            throw 5;
        }
    }
    catch(int p)
    {
        cout << "Error code: " << p << endl;
    }
    x3 = x2 = x;
    y3 = y2 = y;
    while (x2 != 0 && y2 != 0)
    {
        if (x2 > y2)
        {
            x2 %= y2;
        }
        else
        {
            y2 %= x2;
        }
    }
    return y2+x2;
}


If I enter a letter, the console output is
1
2
3
4
5
6
7
8
9
10
Error code: 5
Error code: 5

GCD(0, 0) = 0

Addition: 1; GCD: 6

Error! You have to enter a number from 0 to 7!

Process returned 0.


I skipped a few options, I have them from 0 to 7. Why does it carry over to the part where I choose what I want to do, 0 to 7? I have it checking for cin.fail() in the main function too, so the letter must carry over to a few cins? Shouldn't it just return a 0 and end the program after the first "Error code: 5"?
1. Throw an actual exception, not a number. http://en.cppreference.com/w/cpp/header/stdexcept
2. Don't catch the exception in the same function you throw it in - that completely negates the point of exceptions.

You only throw exceptions where you don't know how to recover from an error.
You only catch exceptions where you do     know how to recover from an error.
Last edited on
What do you mean by saying "actual exception"? Also, it doesn't let me compile the code if there isn't a catch() right after try ends. I know I sound stupid, but I literally have no idea how to do this.

Here's sample code, could you please show me what you meant?

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
#include <iostream>
using namespace std;
int addition(int, int), x, y;
int main()
{
    cout << "x+y" << endl << "Enter x and y:" << endl;
    cin >> x >> y;
    cout << x << " + " << y << " = " << addition(x, y);
    return 0;
}

int addition(int x, int y)
{
    try
    {
        if (cin.fail() == true)
        {
            throw;
        }
    }
    catch(...)
    {
        cout << "An error occured!" << endl;
    }
    return x+y;
}
Don't use try unless you plan to deal with the exceptions that get thrown. In this case you only want to try and catch exceptions in the main function.

For example: https://ideone.com/dB7wcB
This is what I came up with by looking at your example:

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
#include <iostream>
#include <stdexcept>
using namespace std;
int addition(int, int), x, y;
int main()
{
    cout << "x+y" << endl << "Enter x and y:" << endl;
    cin >> x >> y;
    try
    {
        cout << x << " + " << y << " = " << addition(x, y);
    }
    catch(exception &e)
    {
        cerr << "Error: " << e.what() << endl;
    }
    return 0;
}

int addition(int x, int y)
{
    if(cin.fail() == true)
    {
        throw runtime_error{"You entered a letter!"};
    }
    return x+y;
}


IT WORKS! Thank you so much for your patience, I think I kind of get it now. Oh and also, I can't understand what the "&e" in the line 13 and "e.what()" in the line 15 do, could you please explain? Thank you again!!!
std::exception &e means that e has the type std::exception &, known in English as "reference to std::exception. You should research C++ references to understand it. References are extremely important and useful in C++ and should be one of the first things you learn.

As for e.what(), all exception classes provide a mechanism for attaching a message to the exception (as on line 24 "You entered a letter!"). The way you access that message is with the what() member function.

Also, there are other ways to make std::cin unusable besides entering letters, and fail() doesn't detect all those cases. Prefer to convert the stream to a boolean instead: if(!cin)

You may also be interested in reading:
http://www.LB-Stuff.com/user-input

Also, as JLBorges states below, don't make user input and gcd computation into the same function. I should have noticed this earlier - my apologies.
Last edited on
Keep separate concerns separate. For instance, do not tightly couple computing the gcd of two numbers with the processing of user input to read the two numbers.

Avoid using exceptions for control flow. If we know that the error condition would normally be handled by the caller of the function, strongly favour using a return value to flag the error. For an example of indicating an error from an input function, see: http://en.cppreference.com/w/cpp/string/basic_string/getline

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>

long long gcd( long long a, long long b )
{
    if( b == 0 ) return a<0 ? -a : a ;

    else return gcd( b, a%b ) ;
}

std::istream& get_numbers( std::istream& stm, long long& a, long long& b )
{ return stm >> a >> b ; }

int main()
{
    long long a, b ;
    while( get_numbers( std::cin, a, b ) )
        std::cout << "gcd of " << a << " and " << b << " is " << gcd(a,b) << '\n' ;
}

http://coliru.stacked-crooked.com/a/bdab5b9535f84805
Last edited on
Thank you LB, will give that a look and implement if(!cin) into my code instead of if(cin.fail()==true).

JLBorges, thank you for the effort, but I have no idea what you are saying... I'm just a begginer.
Last edited on
JLBorges pointed out something I completely overlooked: you have a function which is trying to do two different things: user input, and calculation. A function should do one thing only, and it should do it well, rather than trying to do multiple things poorly. If you split your function into two different functions as he suggests, the need for exceptions goes away completely.
Last edited on
I imagine the separation would look 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
#include <iostream>
#include <stdexcept>
using namespace std;
int addition(int, int), x, y, getnumbers();
int main()
{
    getnumbers();
    try
    {
        cout << x << " + " << y << " = " << addition(x, y);
    }
    catch(exception &e)
    {
        cout << "Error: " << e.what() << endl;
        return 0;
    }
    return 1;
}

int getnumbers()
{
    cout << "x+y" << endl << "Enter x and y:" << endl;
    if(!(cin >> x >> y))
    {
        throw runtime_error{"You entered a letter!"};
    }
    return x, y;
}
int addition(int x, int y)
{
    return x+y;
}


Although this returns some strange stuff when I enter a letter:

1
2
3
4
5
6
7
8
9
10
11
x+y
Enter x and y:
a
terminate called after throwing an instance of 'std::runtime_error'
  what():  You entered a letter!

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

Process returned 3 (0x3)   execution time : 2.991 s
Press any key to continue. 


Why is this the case? Also, I don't see how this would not need exception handling. You can still enter a letter instead of a number, you surely need an exception for that?
Last edited on
You have the wrong code inside your try block, since addition no longer throws exceptions. However, as JLBorges points out, you don't need exception handling anymore.

Don't use global variables! On line 4 you declare x and y as global variables and later use them in both main and getnumbers.

getnumbers by convention should take and return a std::istream by reference - look more closely at JLBorges' example.
This is the corrected version with no global variables and no exceptions (still can't understand why we got rid of it, what if a letter gets typed?), it takes in x and y numbers and does addition with them, but not with the values it got from getnumbers(), instead it does it with random garbage values. How do I pass a value from cin in one function to main without global variables? Also, I have no idea what istream is supposed to do or mean in JLBorges' example or at all.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;
int addition(int, int), getnumbers(int, int);
int main()
{
    int x, y;
    getnumbers(x, y);
    cout << x << " + " << y << " = " << addition(x, y);
    return 1;
}

int getnumbers(int x, int y)
{
    cout << "x+y" << endl << "Enter x and y:" << endl;
    cin >> x >> y;
    return x, y;
}
int addition(int x, int y)
{
    return x+y;
}
It would probably help a lot if you stopped for a moment and learned about references.
http://www.cplusplus.com/doc/tutorial/functions/#reference

Your getnumbers function should take its parameters by reference so that it can modify them. Right now, you just have them passed by value, which copies them and doesn't affect the values in main at all.

As for the std::istream stuff, consider that std::cin is not the only place you may want to read numbers from - you might also want to read numbers from a file or some other type of stream. In C++, std::istream is the parent of all input streams such as std::cin, std::ifstream, std::istringstream, etc. - it is just good practice to make your code work in the general case.
Last edited on
I got it as close as I can to working:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
using namespace std;
int addition(int, int);
void getnumbers(int, int);
int main()
{
    int x, y;
    getnumbers(x, y);
    cout << x << " + " << y << " = " << addition(x, y);
    return 1;
}

void getnumbers(int &x, int &y)
{
    cout << "x+y" << endl << "Enter x and y:" << endl;
    cin >> x >> y;
    *&x=x;
    *&y=y;
}
int addition(int &x, int &y)
{
    return x+y;
}


Now it just has two errors:

1
2
undefined reference to `getnumbers(int, int)'
undefined reference to `addition(int, int)'


What does this mean?
Also, still don't know how to use the "istream", if I replace "cin" with "istream" it doesn't work.
Last edited on
The errors are because your declarations on lines 3 and 4 do not match your definitions on lines 13 and 20. Just change lines 3 and 4 to match.

On lines 17 and 18, you don't need to do that *& nonsense - in fact, these lines do nothing at all and you don't need them.

Your addition function doesn't need to use references at all - just pass by value as normal.
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;
int addition(int, int);
void getnumbers(int&, int&);
int main()
{
    int x, y;
    getnumbers(x, y);
    cout << x << " + " << y << " = " << addition(x, y);
    return 1;
}
void getnumbers(int &x, int &y)
{
    cout << "x+y" << endl << "Enter x and y:" << endl;
    cin >> x >> y;
}
int addition(int x, int y)
{
    return x+y;
}


This works perfectly, thank you! But I still can't understand why this eliminates the need for exceptions. If I enter a letter, it runs over all the cins and gives a nonsensical answer.
JLBorges' solution eliminates the needs for exceptions because of how he passes around the std::istream reference. Without that, you have no way of knowing that something went wrong inside your getnumbers function. Look at his code again.
Can't wrap my head around his code, I'll continue using exceptions I guess. Thank you for your help and time, I learned a lot from you.
Pages: 12