3

This is a function to get sum of the digits of a number:

int sumOfDigits(int n)
{
    int sum=0; //line 1
    if(n==0)
        return sum;
    else
    {
        sum=(n%10)+sumOfDigits(n/10); //line 2
        // return sum;  //line 3
    }
}

While writing this code, I realized the scope of the local variables is local to each individual recursion of the function. So am I right in saying that if n=11111, 5 sum variables are created and pushed on the stack with each recursion? If this is correct then what is the benefit of using recursion when I can do it in normal function using loops, thus overwriting only one memory location? If I use pointers, recursion will probably take similar memory as a normal function.

Now my second question, even though this function gives me the correct result each time, I don't see how the recursions (other than the last one which returns 0) return values without uncommenting line 3. (using geany with gcc)

I'm new to programming, so please pardon any mistakes

Freak
  • 6,786
  • 5
  • 36
  • 54
aste123
  • 1,223
  • 4
  • 20
  • 40
  • 5
    If you don't uncomment line 3, you invoke undefined behaviour. That may manifest as the programme pretending to work as intended until next tuesday, if it wants to. – Daniel Fischer Jun 04 '13 at 10:16

3 Answers3

4

So am I right in saying that if n=11111, 5 sum variables are created and pushed on the stack with each recursion?

Conceptually, but compilers may turn some forms of recursion into jumps/loops. E.g. a compiler that does tail call optimization may turn

void rec(int i)
{
    if (i > 0) {
        printf("Hello, level %d!\n", i);
        rec(i - 1);
    }
}

into the equivalent of

void loop(int i)
{
    for (; i > 0; i--)
        printf("Hello, level %d!\n", i);
}

because the recursive call is in tail position: when the call is made, the current invocation of rec has no more work to do except a return to its caller, so it might as well reuse its stack frame for the next recursive call.

If this is correct then what is the benefit of using recursion when I can do it in normal function using loops, thus overwriting only one memory location? If I use pointers, recursion will probably take similar memory as a normal function.

For this problem, recursion is a pretty bad fit, at least in C, because a loop is much more readable. There are problems, however, where recursion is easier to understand. Algorithms on tree structures are the prime example.

(Although every recursion can be emulated by a loop with an explicit stack, and then stack overflows can be more easily caught and handled.)

I don't understand the remark about pointers.

I don't see how the recursions (other than the last one which returns 0) return values without uncommenting line 3.

By chance. The program exhibits undefined behavior, so it may do anything, even return the correct answer.

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • Thanks for explaining the concept of tail call optimization. When I said about using pointers, I wasn't really referring to any particular problem but was implying that we could change the value at a memory location in a hypothetical problem without creating unnecessary variables but I guess compiler would most probably optimize any recursion where a variable goes unused after an instance. – aste123 Jun 04 '13 at 11:10
  • @aste123: in "true" (unoptimized) recursion, you'd still need a pointer per recursive invocation :) – Fred Foo Jun 04 '13 at 11:26
2

So am I right in saying that if n=11111, 5 sum variables are created and pushed on the stack with each recursion?

The recursion is 5 levels deep, so traditionally 5 stack frames will be eventually created (but read below!), each one of which will have space to hold a sum variable. So this is mostly correct in spirit.

If this is correct then what is the benefit of using recursion when I can do it in normal function using loops, thus overwriting only one memory location?

There are several reasons, which include:

  • it might be more natural to express an algorithm recursively; if the performance is acceptable, maintainability counts for a lot
  • simple recursive solutions typically do not keep state, which means they are trivially parallelizable, which is a major advantage in the multicore era
  • compiler optimizations frequently negate the drawbacks of recursion

I don't see how the recursions (other than the last one which returns 0) return values without uncommenting line 3.

It's undefined behavior to comment out line 3. Why would you do that?

Community
  • 1
  • 1
Jon
  • 428,835
  • 81
  • 738
  • 806
  • Actually when I wrote the code, I forgot the return statement but it gave expected results. That was what I was wondering about. Guess it's the compiler doing intelligent things and won't work always. – aste123 Jun 04 '13 at 10:31
  • @aste123: Undefined behavior is undefined. Unfortunately many times it *happens* that the result is as expected. Don't fall into the bad habit of being OK with that, things will eventually change without any warning. – Jon Jun 04 '13 at 10:33
  • Thanks for the link to the question on tail recursion. – aste123 Jun 04 '13 at 11:14
1

Yes, the parameters and local variables are local to each invokation and this is usually achieved by creating a copy of each invokation variables set on the program stack. Yes, that consumes more memory compared to an implementation with a loop, but only if the problem can be solved with a loop and constant memory usage. Consider traversing a tree - you will have to store the tree elements somewhere - be it on the stack or in some other structure. Recursion advantage is it is easier to implement (but not always easier to debug).

If you comment return sum; in the second branch the behavior is undefined - anything can happen, expected behavior included. That's not what you should do.

sharptooth
  • 167,383
  • 100
  • 513
  • 979