Funkcja rekurencyjna silnia - zagadkowe zachowanie

0

Mam taki mały problem (pewnie mega banalny). Miałem za zadanie (z książki) aby napisać funkcję rekurencyjną w C++ która oblicza silnię.

Znalazłem już funkcję z necie, wygląda ona tak :

double silnia (int n)
{
    if (n<2)
        return 1;
    return n*silnia2(n-1);
}

No okej. Wcześniej jednak próbowałem napisać coś samemu. Metodą prób i błędów wyszedł taki twór :

int main()
{
    int b=1;
    cout << endl <<silnia(7, &b); //dodałem tutaj endl z przodu, aby cout z funkcji się nie zlewaly

}

double long silnia (int n, int* b)
{
    if (n>0)
    {

        cout << *b;
        *b *= n;
        silnia (n-1, b);
    }
    if (n==0)
        return *b;
} 

No i tak. Funkcja ta jak ją pisałem zawsze zwracała mi zero. Dodałem więc tam "cout << b" aby zobaczyć dokładnie przebieg wartości b. I co dziwne - wtedy funkcja ożyła i rzeczywiście, na cout << silnia (7; &b) zwraca prawidłowy wynik (pomijając wyświetlanie wcześniejszych cout'ów z funkcji silnia.
Pytanie jest następujące. Dlaczego gdy usunę ten *cout << b;** z funkcji silnia funkcja ta zwraca 0, a gdy jednak to zostawię to zwraca prawidłowy wynik?

Tutaj obrazek pokazujący o co mi chodzi :
user image

3

Przy wejściu do if brak return kompilator protestuje ale prądem nie bije więc kontynuujesz, dostajesz to co ostatnio zaległo się na stosie, ponieważ cout << *b; używa stosu to zmienia to wynik.

3

Na przyszłość kompiluj używając -Wall i wtedy by kompilator powiedział co źle robisz.

Mianowicie nie wszystkie gałęzie Twojego kodu zwracają wartość. Poprawny (i lekko przeformatowany kod) wygląda tak:

unsigned long silnia(unsigned long n, unsigned long b) {
    if (n == 0) return b;

    return silnia(n - 1, b * n);
}

Jednak pamiętaj, że nawet ten kod wyłoży się dla n większego od 12.

3

silnia (n-1, b); brakuje ci tu return

0
_13th_Dragon napisał(a):

Przy wejściu do if brak return kompilator protestuje ale prądem nie bije więc kontynuujesz, dostajesz to co ostatnio zaległo się na stosie, ponieważ cout << *b; używa stosu to zmienia to wynik.

Ahh, rzeczywiście było coś wspominane w książce że cout używa stosu. Dzięki, już rozumiem.

winerfresh napisał(a):

unsigned long silnia(unsigned long n, unsigned long b) {
if (n == 0) return b;
return silnia(n - 1, b * n);

}


> 
> Jednak pamiętaj, że nawet ten kod wyłoży się dla `n` większego od `12`.

<del>Jak zamiast long dam double to się nie wyłoży, tylko poda wtedy wynik w notacji wykładniczej.</del> <del>Chociaż nie, wyłoży się XD</del> Chociaż nie, nie wyłoży się jak zmienię wcześniejszego **int**a **b** na **double b;**
A co do tego b ze wskaźnikiem to to był taki parapomysł aby jakoś zapisywać wynik do zmiennej i aby zaczęło mnożyć od jedynki a nie od jakiejś zapisanej wartości w pamięci wczesniej, tylko że tej zmiennej nie mogłem zadeklarować w tej funkcji bo by się powtarzała deklaracja int b=1 ciągle w funkcji i nie zmieniałoby to wyniku.
Wiem, logika pokrętna, ale dopiero się uczę XD

 > ##### [Shalom napisał(a)](http://4programmers.net/Forum/1214601):
> `silnia (n-1, b);` brakuje ci tu return

Dzięki, działa :)
Trochę ogólnie nie zrozumiałem return w funkcji rekurencyjnej, ale już wszystko jasne.
Dzięki za pomoc, temat można zamknąć

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0