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