Mis vahe on rekursiivse funktsiooni ja funktsiooni kutsumise vahel C / C ++ abil?


Vastus 1:

Mõlemad funktsioonid on rekursiivsed. Peamine erinevus seisneb selles, et teise funktsiooni argument on pigem viide väärtusele kui otse edastatud väärtusele, mis tähendab, et iga kord, kui funktsiooni kutsutakse, otsest väärtust ei kopeerita. (Selline atribuut on int-väärtuste jaoks vähem kasulik ja oleks kasulikum struktuuride või klasside puhul, et vältida funktsiooni korduvate tervete andmeplokkide kopeerimist.)

Ainus erinevus on see, et teine ​​funktsioon ei tagasta mingit väärtust ja esimene annab.


Vastus 2:

Need on mõlemad rekursiivsed funktsioonikõned. Üks tagastab rekursiivse kõne tulemuse ja teine ​​mitte. Mõlemad on rekursiooni kasutamisel kehtivad (ja kasulikud).

Ilmselt sisaldavad mõlemad näited viga, kuna te ei lõpeta kunagi rekursiooni (ja põhjustab lõpuks virna ületäitumist), kuid ma eeldan, et postitate küsimuse raamimiseks lihtsalt väljamõeldud koodi.


Vastus 3:

Ma peksan surnud hobust sellega, et ütlen teile peaaegu sama, mis teistele vastustele, kuid tühine meetod oleks sama ülesande täitmine ikka ja jälle, kus tagasitulemismeetodi abil kogutakse iga rekursiivse kõne tulemused.

Kui te ei teadnud, et need pole head rekursiivsed funktsioonid, kuna alust ei ole olemas, võib teil tekkida virna ületäitumine (või puhvri ületäitumine sõltuvalt sellest, kellega räägite), millel on C-s töötades palju mäluprobleeme, nii et peate olema ettevaatlik. Põhja märkimiseks on vaja rekursiivse funktsiooni põhikorpust.


Vastus 4:

Peale selle, millel on tagastatav väärtus, on see enamasti eelistus / loetavus.

Kuigi ma leiaksin, et see on hädavajaliku programmeerimise enamasti halb tava. Asjade jaoks, kus rekursioon on ülioluline, on teil tõenäoliselt tegemist keerukamate matemaatiliste algoritmide rakendamisega ja seetõttu on funktsionaalne programmeerimine palju paremini rakendatav omaduste ja käitusaja analüüsimisel. Tegelikule kasutamisele üleminekul on hädavajalikes programmeerimiskeeltes paremaid kontseptsioone kui rekursioon.


Vastus 5:

Nagu kõik teised ütlesid, on mõlemad teie funktsioonid lihtsalt rekursiivsed.

Ja te ei nimeta midagi viitega, vaid teil on muutuja, mis esimesel juhul antakse lihtsalt (ja ei kasutata) ja teisel juhul anti sellele muutujale viide (osuti).

Muide, teie (int & x) ei töötaks C-keeles. Seda teeb ainult C ++ ja see tähendab ka seda, et te ei näe helistajast, et helistaja suudab seda muutujat muuta.

int x = 42;
func (x);
funcref (& x);

int func (int i) {
i = 1;
tagasi i + 2; // tagastab 3, x ei ole muudetud (ma lihtsalt kohalik)
}
int funcref (int * i) {
* i = 1;
tagasi * i + 2; // naaseb 3, x on seatud 1-le
}

Siin on näited väärtuse järgi helistamise ja viite abil helistamise kohta. Esimese kõne ajal ei saa X-i otse muuta. Funktsioon muudab helistaja X-i väärtust, kuna see ei saa mitte ainult selle muutuja väärtust, vaid ka selle muutuja aadressi ise.

Nüüd funktsiooni kutsumiseks viitega:

# kaasata 
int func1 (int x) {
tagasi x + 1;
}
int func2 (int x) {
tagasi x + 2;
}

int main () {
int (* kõne) (int x);

call = & func1;
printf (“% d \ n”, kõne (41));

call = & func2;
printf (“% d \ n”, kõne (41));
}

Kompileerimine ja väljund:

> cc-O3 -o fcall fcall.c
> .kõne
42
43

Funktsiooni kutsumine viite abil on palju jõudu. Kokkupanekutasandil on sarnane kõne lihtsalt ühe opoodkoodi kõne, nii et tavaliselt ei vaja registris oleva aadressi üle hüppamiseks rohkem aega, kui otse aadressile, mis tuleb mälust laadida. See võib olla isegi kiirem, sest sellise hüppe jaoks ei vaja me juurdepääsu mälule.

Praktikas hüppame tavaliselt hüppelaudadest üle. Nagu siin näites:

# kaasata 
int fadd (int a, int b) {tagasta a + b; }
int fsub (int a, int b) {tagasta a-b; }
int fmul (int a, int b) {tagasta a * b; }
int fdiv (int a, int b) {tagasta a / b; }

int main () {
// hüppetabeli “kõne” algatamine
int (* kõne []) (int x, int y) = {& fadd, & fsub, & fmul, & fdiv};

jaoks (int i = 0; i 

Kompileerimine ja väljund:

> cc-O3 -o fcall fcall.c
> .kõne
15
9
36
4

Nagu näete, on massiivides sellised funktsioonid tööriistana üsna võimsad. Ja sellega saate lahendada palju probleeme. Tegelikult saab seda kasutada nagu lüliti / ümbrise struktuuri, lihtsalt keerukam ja palju kompaktsem. Kompaktne on hea, see hoiab teie koodi vahemälus. Nii et kui teil on näiteks mõni probleemide lahendamise probleem, võib see olla üks tõhusamaid viise selle lahendamiseks.

Minu näites oleks nüüd vaja väga vähe, et sellest väike kalkulaator teha. Selliseid asju saate kasutada simulatsioonide ja isegi olekumasinate jaoks, samas kui loomuliku oleku masin kasutab mingit hüppemehhanismi, jah, ma räägin siin GOTO-st. Kuid see on teise küsimuse jaoks.

Kuid kui teil on rekursiivse tagasihelistamise struktuuriga olekumasinad, mis võivad tekkida paljude AI probleemide korral, on teil selle lahendamiseks tööriist.

Lisaks on see lahendus ka siis, kui soovite C-funktsioonis teha puhast funktsionaalset programmeerimist: töötate funktsioonitabelitega.

Funktsionaalne programmeerimine ei kuulu ühe keele valdkonda. Midagi sellist nagu skeem või Lisp võivad seda väga toetada, kuid funktsioonikõne muutuja nimetu muutuja korral, see on Lambda, kellele need inimesed nii palju räägivad. Võrrelge lihtsalt Lispi efektiivsust sellega.

Võib-olla oleks mugavam kirjutada selliseid asju väga heas kirjas, kuid selle mugavuse hind on nii kõrge, et väljaspool prototüüpimist ei tasu tavaliselt seda väikest vaeva vältida; vaeva näitasin teile juba, kuidas lahendada.


Vastus 6:

Nagu kõik teised ütlesid, on mõlemad teie funktsioonid lihtsalt rekursiivsed.

Ja te ei nimeta midagi viitega, vaid teil on muutuja, mis esimesel juhul antakse lihtsalt (ja ei kasutata) ja teisel juhul anti sellele muutujale viide (osuti).

Muide, teie (int & x) ei töötaks C-keeles. Seda teeb ainult C ++ ja see tähendab ka seda, et te ei näe helistajast, et helistaja suudab seda muutujat muuta.

int x = 42;
func (x);
funcref (& x);

int func (int i) {
i = 1;
tagasi i + 2; // tagastab 3, x ei ole muudetud (ma lihtsalt kohalik)
}
int funcref (int * i) {
* i = 1;
tagasi * i + 2; // naaseb 3, x on seatud 1-le
}

Siin on näited väärtuse järgi helistamise ja viite abil helistamise kohta. Esimese kõne ajal ei saa X-i otse muuta. Funktsioon muudab helistaja X-i väärtust, kuna see ei saa mitte ainult selle muutuja väärtust, vaid ka selle muutuja aadressi ise.

Nüüd funktsiooni kutsumiseks viitega:

# kaasata 
int func1 (int x) {
tagasi x + 1;
}
int func2 (int x) {
tagasi x + 2;
}

int main () {
int (* kõne) (int x);

call = & func1;
printf (“% d \ n”, kõne (41));

call = & func2;
printf (“% d \ n”, kõne (41));
}

Kompileerimine ja väljund:

> cc-O3 -o fcall fcall.c
> .kõne
42
43

Funktsiooni kutsumine viite abil on palju jõudu. Kokkupanekutasandil on sarnane kõne lihtsalt ühe opoodkoodi kõne, nii et tavaliselt ei vaja registris oleva aadressi üle hüppamiseks rohkem aega, kui otse aadressile, mis tuleb mälust laadida. See võib olla isegi kiirem, sest sellise hüppe jaoks ei vaja me juurdepääsu mälule.

Praktikas hüppame tavaliselt hüppelaudadest üle. Nagu siin näites:

# kaasata 
int fadd (int a, int b) {tagasta a + b; }
int fsub (int a, int b) {tagasta a-b; }
int fmul (int a, int b) {tagasta a * b; }
int fdiv (int a, int b) {tagasta a / b; }

int main () {
// hüppetabeli “kõne” algatamine
int (* kõne []) (int x, int y) = {& fadd, & fsub, & fmul, & fdiv};

jaoks (int i = 0; i 

Kompileerimine ja väljund:

> cc-O3 -o fcall fcall.c
> .kõne
15
9
36
4

Nagu näete, on massiivides sellised funktsioonid tööriistana üsna võimsad. Ja sellega saate lahendada palju probleeme. Tegelikult saab seda kasutada nagu lüliti / ümbrise struktuuri, lihtsalt keerukam ja palju kompaktsem. Kompaktne on hea, see hoiab teie koodi vahemälus. Nii et kui teil on näiteks mõni probleemide lahendamise probleem, võib see olla üks tõhusamaid viise selle lahendamiseks.

Minu näites oleks nüüd vaja väga vähe, et sellest väike kalkulaator teha. Selliseid asju saate kasutada simulatsioonide ja isegi olekumasinate jaoks, samas kui loomuliku oleku masin kasutab mingit hüppemehhanismi, jah, ma räägin siin GOTO-st. Kuid see on teise küsimuse jaoks.

Kuid kui teil on rekursiivse tagasihelistamise struktuuriga olekumasinad, mis võivad tekkida paljude AI probleemide korral, on teil selle lahendamiseks tööriist.

Lisaks on see lahendus ka siis, kui soovite C-funktsioonis teha puhast funktsionaalset programmeerimist: töötate funktsioonitabelitega.

Funktsionaalne programmeerimine ei kuulu ühe keele valdkonda. Midagi sellist nagu skeem või Lisp võivad seda väga toetada, kuid funktsioonikõne muutuja nimetu muutuja korral, see on Lambda, kellele need inimesed nii palju räägivad. Võrrelge lihtsalt Lispi efektiivsust sellega.

Võib-olla oleks mugavam kirjutada selliseid asju väga heas kirjas, kuid selle mugavuse hind on nii kõrge, et väljaspool prototüüpimist ei tasu tavaliselt seda väikest vaeva vältida; vaeva näitasin teile juba, kuidas lahendada.


Vastus 7:

Nagu kõik teised ütlesid, on mõlemad teie funktsioonid lihtsalt rekursiivsed.

Ja te ei nimeta midagi viitega, vaid teil on muutuja, mis esimesel juhul antakse lihtsalt (ja ei kasutata) ja teisel juhul anti sellele muutujale viide (osuti).

Muide, teie (int & x) ei töötaks C-keeles. Seda teeb ainult C ++ ja see tähendab ka seda, et te ei näe helistajast, et helistaja suudab seda muutujat muuta.

int x = 42;
func (x);
funcref (& x);

int func (int i) {
i = 1;
tagasi i + 2; // tagastab 3, x ei ole muudetud (ma lihtsalt kohalik)
}
int funcref (int * i) {
* i = 1;
tagasi * i + 2; // naaseb 3, x on seatud 1-le
}

Siin on näited väärtuse järgi helistamise ja viite abil helistamise kohta. Esimese kõne ajal ei saa X-i otse muuta. Funktsioon muudab helistaja X-i väärtust, kuna see ei saa mitte ainult selle muutuja väärtust, vaid ka selle muutuja aadressi ise.

Nüüd funktsiooni kutsumiseks viitega:

# kaasata 
int func1 (int x) {
tagasi x + 1;
}
int func2 (int x) {
tagasi x + 2;
}

int main () {
int (* kõne) (int x);

call = & func1;
printf (“% d \ n”, kõne (41));

call = & func2;
printf (“% d \ n”, kõne (41));
}

Kompileerimine ja väljund:

> cc-O3 -o fcall fcall.c
> .kõne
42
43

Funktsiooni kutsumine viite abil on palju jõudu. Kokkupanekutasandil on sarnane kõne lihtsalt ühe opoodkoodi kõne, nii et tavaliselt ei vaja registris oleva aadressi üle hüppamiseks rohkem aega, kui otse aadressile, mis tuleb mälust laadida. See võib olla isegi kiirem, sest sellise hüppe jaoks ei vaja me juurdepääsu mälule.

Praktikas hüppame tavaliselt hüppelaudadest üle. Nagu siin näites:

# kaasata 
int fadd (int a, int b) {tagasta a + b; }
int fsub (int a, int b) {tagasta a-b; }
int fmul (int a, int b) {tagasta a * b; }
int fdiv (int a, int b) {tagasta a / b; }

int main () {
// hüppetabeli “kõne” algatamine
int (* kõne []) (int x, int y) = {& fadd, & fsub, & fmul, & fdiv};

jaoks (int i = 0; i 

Kompileerimine ja väljund:

> cc-O3 -o fcall fcall.c
> .kõne
15
9
36
4

Nagu näete, on massiivides sellised funktsioonid tööriistana üsna võimsad. Ja sellega saate lahendada palju probleeme. Tegelikult saab seda kasutada nagu lüliti / ümbrise struktuuri, lihtsalt keerukam ja palju kompaktsem. Kompaktne on hea, see hoiab teie koodi vahemälus. Nii et kui teil on näiteks mõni probleemide lahendamise probleem, võib see olla üks tõhusamaid viise selle lahendamiseks.

Minu näites oleks nüüd vaja väga vähe, et sellest väike kalkulaator teha. Selliseid asju saate kasutada simulatsioonide ja isegi olekumasinate jaoks, samas kui loomuliku oleku masin kasutab mingit hüppemehhanismi, jah, ma räägin siin GOTO-st. Kuid see on teise küsimuse jaoks.

Kuid kui teil on rekursiivse tagasihelistamise struktuuriga olekumasinad, mis võivad tekkida paljude AI probleemide korral, on teil selle lahendamiseks tööriist.

Lisaks on see lahendus ka siis, kui soovite C-funktsioonis teha puhast funktsionaalset programmeerimist: töötate funktsioonitabelitega.

Funktsionaalne programmeerimine ei kuulu ühe keele valdkonda. Midagi sellist nagu skeem või Lisp võivad seda väga toetada, kuid funktsioonikõne muutuja nimetu muutuja korral, see on Lambda, kellele need inimesed nii palju räägivad. Võrrelge lihtsalt Lispi efektiivsust sellega.

Võib-olla oleks mugavam kirjutada selliseid asju väga heas kirjas, kuid selle mugavuse hind on nii kõrge, et väljaspool prototüüpimist ei tasu tavaliselt seda väikest vaeva vältida; vaeva näitasin teile juba, kuidas lahendada.