2.5. Pułapek ciąg dalszy 39
nie będzie mógł sprawdzić: jak rzeczywisty kompilator wykona tę funkcję! Mimo, że większość kompilatorów działa podobnie, to zdarzają się pomiędzy nimi drobne różnice, które powodują, że identyczne programy będą dawać różne wyniki Nasz kolejny przykład będzie dotyczył właśnie takiego przypadku.
Proszę spojrzeć na następującą funkcję:
int N(int n,int p)
{
if (n==0) return 1; else
return N (n-1, N (n-p, p) )
ł
Można przeprowadzić dowód matematyczny!, że powyższa definicja jest poprawna w tym sensie, iż dla dowolnych wartości n>0 i p>0 jej wynik jest określony i wynosi 1. Dowód ten opiera się na założeniu, że wartość argumentu wywołania funkcji jest obliczana tylko wtedy, gdy jest naprawdę niezbędna (co wydaje się dość logiczne). Jak się to zaś ma do typowego kompilatora C++?
Otóż regułą w jego przypadku jest to, iż wszystkie parametry funkcji rckuren-cyjnej są ewaluowane jako pierwsze, a następnie dokonywane jest wywołanie samej funkcji. (Taki sposób pracy jest zwany wywołaniem przez wartość.
Problem może zaistnieć wówczas, gdy w wywołaniu funkcji spróbujemy umieścić ją samą; zobaczmy, jak to się odbędzie w przypadku naszej funkcji, np. dla N(l.O) (patrz rysunek 2 - 5).
Rys. 2-5.
^ W‘»(70
i
Nieskończony ciąg Wywołań rekuren-cyjnych.
■O.
Z
*
1 Patrz [Kro89j.
«0‘^