1

So a friend of mine is taking one of his first CS classes and mentions that he's using recursion in his very first program. He sends me the code below. Right off the bat I noticed that he isn’t catching the return value of his recursive call and I assumed it wouldn’t work. But he insists that it does work so I try his program out, and to my surprise it functions exactly as expected. Ignoring the fact that this is a dumb way to get from point A to point B, why does this even work?

I was playing around with what he sent me and added a cout after the if statement. Besides that, the first chunk of code and the second chunk are identical.

If I input the following for the first program, here's what I get...

Enter a Number: 10

You entered: 10 Is this correct? (Y/N): N

Enter a Number: 12

You entered: 12 Is this correct? (Y/N): Y

main() = 12

And then if I do the same thing with the second program, here's what I get...

Enter a Number: 10

You entered: 10 Is this correct? (Y/N): N

Enter a Number: 12

You entered: 12 Is this correct? (Y/N): Y

main() = 6300096

What's going on!?

#include <iostream>
#include <cstring>
#include <cctype>

using namespace std;

int getNum() 
{
    cout << "Enter a Number: ";
    int x;
    cin >> x;
    cin.ignore(100, '\n');

    while(x < 0) {
        cout << "Please enter amount greater than 0: ";
        cin >> x;
        cin.ignore(100, '\n');
    }

    cout << "You entered: " << x << " Is this correct? (Y/N): ";
    char response;
    cin >> response;
    cin.ignore(100, '\n');

    if (response != 'Y') {
        getNum();
    } else {
        return x;
    }
}

int main() {

    cout << "\nmain() = " << getNum() << endl;

    return 0;
}

The only difference between the top and the bottom is a cout statement after the if statement.

#include <iostream>
#include <cstring>
#include <cctype>

using namespace std;

int getNum() 
{
    cout << "Enter a Number: ";
    int x;
    cin >> x;
    cin.ignore(100, '\n');

    while(x < 0) {
        cout << "Please enter amount greater than 0: ";
        cin >> x;
        cin.ignore(100, '\n');
    }

    cout << "You entered: " << x << " Is this correct? (Y/N): ";
    char response;
    cin >> response;
    cin.ignore(100, '\n');

    if (response != 'Y') {
        getNum();
    } else {
        return x;
    }
    cout << "returning... " << x;
}

int main() {

    cout << "\nmain() = " << getNum() << endl;

    return 0;
}
Community
  • 1
  • 1
DanubePM
  • 1,526
  • 1
  • 10
  • 24
  • 3
    In `if (response != 'Y')`, shouldn't you `return getNum();` ? When you write it like this, if `response != 'Y'`, you never return anything, so the fact that your first program works is mainly luck. – tforgione Apr 12 '16 at 07:28
  • 1
    Yes, you're right, but I'm asking about the luck part. – DanubePM Apr 12 '16 at 07:33
  • My bad, didn't understand your question. – tforgione Apr 12 '16 at 07:35
  • I reopened the question to provide [the answer shown below](http://stackoverflow.com/a/36566764/464581). I believe this (why it "works") isn't covered by the originally identified possible duplicate. – Cheers and hth. - Alf Apr 12 '16 at 07:46

2 Answers2

6

At the machine code level, a small enough function result is usually returned in a particular processor register.

Formally the code has Undefined Behavior by not executing a return statement in some calls of getNum, but what happens is probably this:

  1. getNum() is called, user answers N.

  2. getNum() calls itself recursively, user answer Y.

  3. getNum() executes return x;. With a typical C++ implementation this places the return value in a register, let's call it R.

  4. Execution returns up to getNum() (original call), which now returns by execution passing through the end of the function, no return.

  5. The calling code finds the value in register R, as expected.

So, it can “work”.

But it's formally Undefined Behavior, and with some other compiler and/or options, it might not work.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
2

In C++, compilers don't thoroughly check that function ends its flow without return statement because it's not easy task to check all control paths. Behavior of this code is undefined, what will actually occur depends on calling convention.

I think they merely forgot return before getNum(). It will work and will not pollute stack because if tail recursion optimization.

This code is weird for first CS classes though.

George Sovetov
  • 4,942
  • 5
  • 36
  • 57