0

This is a problem in a test. I expect the result is 1:1 but run it and get the answer 1:5, although I've debug it in Visual C++ 2013 and see the value of the adress which 'a' point to is 1 (the last '1' in 1:1)

#include <iostream>
using namespace std;
int fact(int *a)
{
    if (*a <= 1)
    {
        return a[0];
    }
    else
    {
        return a[0] * fact(&(--*a));
    }
}
int main()
{
    int *a = new int;
    *a = 5;
    cout << fact(a) << ":" << *a;
    return 0;
}
  • 3
    I do not understand how you get result equal to 1:5 Take into account that the function has undefined behaviour because the order of evaluation of operands of the multiplication operator is unspecified.. – Vlad from Moscow Jul 22 '15 at 10:11

3 Answers3

3

Why do you need to change the value given to function when you can simply use local value?

int fact(int a)
{
    if (a < 2)
    {
        return a;
    }
    else
    {
        return a * fact(a-1);
    }
}
maxpovver
  • 1,580
  • 14
  • 25
2

Your program has undefined behaviour. So it could do anything.

Your "full expressions"

a[0] * fact(&(--*a));
cout << fact(a) << ":" << *a;

do not each have a defined sequence of evaluation for an access of an object (a[0] & *a) and a side effect (--*a & fact(a)). This runs afoul of §1.9/15 of the standard:

Except where noted,

[operators ?:, &&, || and ,]

evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.

and

If a side effect on a scalar object is unsequenced relative to either
(a) another side effect on the same scalar object
or
(b) a value computation using the value of the same scalar object,
the behavior is undefined.

See this answer and its question. (Where I got this quote from the standard.)

One could guess that the compiler, which can detect this violation, makes fact just return 1 without affecting *a, so that fact(*a) returns 1 and *a returns 5. But that's just a guess, and the code could do anything. (You could look at the assembler code to get some idea of what's going on.)

Programs that have the behaviour that you want involve more temporaries, simpler statements, simpler function specs and simpler program structure. It is not hard to write correct code if you know what not to write and check that you haven't written it. To help you:

  • set your compiler options to report more warnings and errors and read its output (much of undefined behaviour can be and is statically detectable by the compiler)
  • as you read & write explicitly identify the input & output specification of every function and (sub) expression/statement
  • keep explicitly educating yourself about good design
  • keep explicitly educating yourself about the language
Community
  • 1
  • 1
philipxy
  • 14,867
  • 6
  • 39
  • 83
  • This doesn't tell the OP how to avoid the problem, it just describes what went wrong. It would be more helpful it it gave the OP information on how to avoid the problem. – Yakk - Adam Nevraumont Jul 22 '15 at 15:44
  • @Yakk My thought was that one just avoided breaking the rule. But I agree that that involves knowledge, effort, and help. I've updated my answer. – philipxy Jul 22 '15 at 23:25
0

This depends on the compiler. how they handle the temp. values and preecedence of operators. Eg: on solaris CC the out put is 24:1. on some compilers it will be 120:5 .

The correct answer must be 120:1. Here is how

fact called for :5 else part. a[0] : 5 return value = 5 * fact(4) = 120

fact called for :4 else part. a[0] : 4 return value = 4*fact(3) = 4* 6 = 24

fact called for :3 else part. a[0] : 3 return value = 3 * fact(2) = 3*2 = 6

fact called for :2 else part. a[0] : 2 return value = 2*fact(1) = 2*1 = 2

fact called for :1
if part . a[0] = 1 return value = 1