Permalänk
Medlem

Problem med rekursion i C.

Håller på göra en funktion som ska multiplicera ihop alla talen i en array genom att använda rekursion (alltså att funktionen anropar sig själv). Jag har fått till det med en for-loop men det strular på rekursionsbiten.

Jag tror att koden är hyffsat korrekt men jag får felmeddelandet från kompilatorn "operation on "nr" may be undefined".

Funktionen ser ut såhär. Det händer när jag använder ++ eller --

int mulArray2(int arr[], int nr){

if(nr>=1 && nr!= '\0')
{
return arr[nr] * mulArray2(arr, nr--);

}
else return 1;
}

Visa signatur

I9 12900K|Asus Prime Z690-P WIFI D4|Noctua NH-D14|Samsung 850 1000gb|Asus RTX 3080 TUF|HyperX Fury 3600mhz CL17 32GB|EVGA Supernova 850w|Corsair 650D|Acer XB270HU

Permalänk
Datavetare

@Oggaaaa: det kompilatorn klagar på är detta

return arr[nr] * mulArray2(arr, nr--);

Detta är ett uttryck, det är tillåtet att evaluera saker i vilken ordning som helst inom ett och samma uttryck.

Det betyder att det inte finns någon garanti att

arr[nr]

beräknas innan

mulArray2(arr, nr--)

Ser du problemet? nr kan alltså vara eller inte vara ökat med ett när arr[nr] evalueras.

Du ska nog även fundera lite över din jämförelse för när rekursionen ska avbrytas...

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Medlem
Skrivet av Yoshman:

@Oggaaaa: det kompilatorn klagar på är detta

return arr[nr] * mulArray2(arr, nr--);

Detta är ett uttryck, det är tillåtet att evaluera saker i vilken ordning som helst inom ett och samma uttryck.

Det betyder att det inte finns någon garanti att

arr[nr]

beräknas innan

mulArray2(arr, nr--)

Ser du problemet? nr kan alltså vara eller inte vara ökat med ett när arr[nr] evalueras.

Du ska nog även fundera lite över din jämförelse för när rekursionen ska avbrytas...

Mm jämförelsen var nog lite onödig att ha med. Testade lite olika och fick till den när jag hade såhär.

int mulArray2(int arr[], int nr){ if(nr>0) { return arr[nr-1] *mulArray2(arr, nr-1); } else return 1;

Det fungerar nu men finns de en risk att den går utanför arrayen? Tänkte när den kommer ner till första elementet.

Visa signatur

I9 12900K|Asus Prime Z690-P WIFI D4|Noctua NH-D14|Samsung 850 1000gb|Asus RTX 3080 TUF|HyperX Fury 3600mhz CL17 32GB|EVGA Supernova 850w|Corsair 650D|Acer XB270HU

Permalänk
Medlem

Ja, det finns det nog en risk att det gör. Problemet är att du inte sätter ett "basfall" där du kollar längden på arrayen. Är inte speciellt bevandrad med C så ha gärna lite översyn. Skulle skriva något i stil med detta.

int mulArray2(int arr[], int nr){

if (arr.length() = 0 || nr = 0)
return 1;
else{
return arr[nr-1] *mulArray2(arr, nr-1);
}

Edit: Såg nu att man kollar längden i C på ett helt annat sätt. Har visst suttit för mycket med Java

Permalänk
Medlem
Skrivet av Oggaaaa:

Det fungerar nu men finns de en risk att den går utanför arrayen? Tänkte när den kommer ner till första elementet.

Det första elementet har ju index 0, och din if-sats ser till att nr-1 aldrig blir mindre än just 0. Så nej, du kommer inte gå utanför arrayen (inte åt det hållet i alla fall, den som anropar funktionen kan förstås ange ett för stort index).

I din ursprungliga jämförelse if(nr>=1 && nr!= '\0') så har för övrigt karaktären '\0' värdet 0, så det är bara ett krångligt sätt att skriva if(nr >= 1 && nr != 0) (och nr != 0 är förstås helt överflödig där).

Permalänk
Datavetare

Finns lite småputsning du kan göra, antagligen inte alls nödvändigt här.

Vid rekursion skiljer man mellan svansrekursiva anrop och sådan som inte är svansrekursiva. Fördelen med svansrekursion är att kompilatorn kan göra en del optimeringar, bl.a. så att anropsstacken inte växer vilket gör det möjligt att hantera godtyckligt djup rekursion.

Vissa språk garanterar svansrekursionoptimering, detta då de kanske inte har något annat sätt att göra loopar på. C ger inte denna garanti, men i praktiken utförs den när man slår på optimeringar.

Det skulle kunna se ut så här

int mulArray2(int arr[], int nr, int accProduct) { int product = accProduct * arr[--nr]; if (nr == 0) { return product; } return mulArray2(arr, nr, product); } // Nu slipper man också dra bort ett från andra argumentet, // där skickar man in antal element initialt. // Kan inte hantera en array av längd noll som det står nu!!! int productOfAllElements = mulArray2 (arrToMultiply, numberOfElementsOfArr, 1);

"Tricket" här är att sista uttrycket inte gör något annat än returnerar resultatet från det rekursiva anropet. Multiplikationen utförs som argument, inte på returvärdet!

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer