Curs 07

Pentru funcțiile void, declarația de returnare este folosită în principal ca element de control al programului. De exemplu, în următoarea funcție, este rezultatul creșterii unui număr la o putere întregă pozitivă. Dacă exponentul se dovedește a fi negativ, instrucțiunea de returnare va oferi o ieșire din funcție înainte de a se încerca să se calculeze o astfel de expresie. În acest caz, declarația de returnare acționează ca element de control, împiedicând executarea nedorită a unei anumite părți a funcției.







void power (int bază, int exp)

dacă (exp<0) return; /* Чтобы не допустить возведения числа в отрицательную степень, здесь выполняется возврат в вызывающую функцию и игнорируется остальная часть функции. */

pentru (; exp; exp--) i = baza * i;

cout <<"Результат равен: " <

O funcție poate conține mai multe declarații de returnare. Funcția va fi terminată când cel puțin una dintre ele este executată. De exemplu, fragmentul de cod următor este perfect legitim.

Cu toate acestea, trebuie avut în vedere faptul că prea multe instrucțiuni de returnare pot degrada claritatea algoritmului și pot induce în eroare pe cei care o vor înțelege. Mai multe declarații de returnare ar trebui utilizate numai dacă contribuie la claritatea funcției.

Fiecare funcție, cu excepția voidului. returnează o anumită valoare. Această valoare este specificată explicit folosind instrucțiunea de retur. Cu alte cuvinte, orice functie non-void poate fi folosita ca un operand intr-o expresie. Prin urmare, fiecare dintre următoarele expresii este valabilă în C ++.

dacă (max (x, y))> 100) cout <<"больше";

Deși toate funcțiile non-void returnează valori, acestea nu trebuie să fie utilizate în program. Cea mai obișnuită întrebare despre valorile returnate de funcții este: "Deoarece funcția returnează o anumită valoare, nu ar trebui (ar trebui) să atribuie această valoare oricărei variabile?". Răspuns: nu, nu este necesar. Dacă valoarea returnată de funcție nu participă la atribuire, ea este pur și simplu aruncată (pierdută).

Luați în considerare următorul program, care utilizează funcția standard de bibliotecă abs ().

folosind namespace std;

i = abs (-10); // linia 1

cout <

Funcția abs () returnează valoarea absolută a argumentului întreg. Utilizează antetul . În linia 1, valoarea returnată de funcția abs (). este alocat i. În linia 2, valoarea returnată de abs (). nimic nu este atribuit, ci este utilizat de instrucțiunea cout. În cele din urmă, în rândul 3, valoarea returnată de abs (). se pierde deoarece nu este alocată nici o altă variabilă și nu este utilizată ca parte a expresiei.

Dacă o funcție al cărui tip este diferit de void. se termină prin detectarea unei bretele curbate de închidere, valoarea pe care o returnează nu este definită (adică necunoscută). Din cauza caracteristicilor sintaxei oficiale C ++, funcția void nu este necesară pentru a executa o declarație de returnare. Acest lucru se poate întâmpla dacă se ajunge la sfârșitul funcției înainte de găsirea declarației de returnare. Dar, deoarece funcția este declarată ca valoare de returnare, valoarea va fi returnată, chiar dacă este doar gunoi. În general, orice funcție non-void pe care o creați ar trebui să returneze o valoare printr-o declarație explicită de returnare.

Sa menționat mai sus că o funcție void poate avea mai multe declarații de returnare. Același lucru se aplică și funcțiilor care returnează valorile. De exemplu, funcția găsită în următorul program, find_substr () utilizează două declarații de retur. ceea ce face posibilă simplificarea algoritmului de funcționare a acestuia. Această funcție caută subdistribuția specificată în șirul specificat. Aceasta returnează indicele primei apariții a substringului specificat sau valoarea -1. dacă subcadrul specificat nu a fost găsit. De exemplu, dacă în linia "I love C ++" este necesar să găsiți substringul "dragoste". atunci funcția find_substr () va returna numărul 2 (care este indicele caracterului "l" din linia "I love C ++").

folosind namespace std

int find_substr (char * sub, char * str);

index = find_substr ("trei", "două două trei patru");

cout <<"Индекс равен " <

// Funcția returnează indexul substringului cerut sau -1 dacă nu a fost găsit.







int find_substr (char * sub, char * str)

p = str [t]; // setați indicatorii

în timp ce (* p2 * p2 == * p)

/ * Dacă se ajunge la capătul liniei p2 (adică subsirful), a fost găsită o subcadr. * /

dacă (! * p2) returnează t; // Returnați indexul subrecursului.

retur -1; // Nu a fost găsit nici un subrevers.

Rezultatele acestui program sunt următoarele.

Deoarece substringul în cauză există într-un șir dat, se execută prima declarație de returnare. Ca exercițiu, modificați programul astfel încât acesta să caute un substring care nu face parte din șirul specificat. În acest caz, find_substr () trebuie să returneze -1 (datorită celei de-a doua instrucțiuni de returnare).

Funcții care nu returnează valori (funcții void)

folosind namespace std;

void print_vertical (char * str);

int principal (int argc, char * argv [])

void print_vertical (char * str)

cout <<*str++ <<'\n';

Deoarece print_vertical () este declarată ca o funcție void, ea nu poate fi utilizată într-o expresie. De exemplu, următoarea declarație este nevalidă și, prin urmare, nu este compilată.

x = print_vertical ("Hello!"); // eroare

Important: În primele versiuni ale C, nu a fost furnizat tipul vid. Astfel, în programele vechi C, funcțiile care nu returnează valori au fost int implicit. Dacă trebuie să vă ocupați de astfel de funcții atunci când traduceți programe vechi C pe șinele C ++, pur și simplu declarați-le folosind cuvântul cheie void, făcându-le funcții void.

Funcții care returnează indicii

Funcțiile pot reda indicii. Indicatorii se întorc ca valorile altor tipuri de date și nu prezintă probleme particulare. Dar, deoarece pointerul este unul dintre instrumentele cele mai complexe (sau nesigure) ale limbajului C ++, este logic să se dedice o secțiune separată.

Pentru a returna un pointer, funcția trebuie să declare tipul său ca tip de valoare de retur. Acesta este modul în care, de exemplu, este declarat tipul valorii returnate pentru funcția f (). care ar trebui să returneze un pointer la un număr întreg.

Dacă funcția returnează un pointer, atunci valoarea folosită în instrucțiunea de retur. ar trebui să fie, de asemenea, un indicator. (Ca în cazul tuturor funcțiilor, valoarea returnată trebuie să fie compatibilă cu tipul valorii returnate.)

Următorul program demonstrează modul de utilizare a indicatorului ca tip de valoare de retur. Aceasta este noua versiune a funcției de mai sus find_substr (). Numai acum nu returnează indicele substringului găsit, ci un indicator pentru el. Dacă nu se găsește o subcrasă dată, este returnat un pointer nul.

// Noua versiune a funcției find_substr ().

// care returnează un pointer la un substring.

folosind namespace std;

char * find_substr (char * sub, char * str);

substr = find_substr ("trei", "două două trei patru");

cout <<"Найденная подстрока: " <

pentru (t = 1;<=n; t++) answer = answer* (t);

Versiune nerecursive a faptului funcției () este destul de simplu și nu necesită explicații extinse. Acesta folosește un ciclu în care a organizat de multiplicare numere consecutive începând cu 1 și terminând cu numărul specificat ca parametru: la fiecare iterație valoarea curentă a ciclului variabil manipulate înmulțit cu valoarea curentă a produsului obținut ca rezultat al ciclului de repetare precedent.

Funcția recursivă a factr () este oarecum mai complicată. În cazul în care este numit cu un argument de 1, apoi revine imediat valoarea 1. În caz contrar, se returnează factr produsului (n-1) * n. Pentru a evalua această expresie, numim metoda factr () cu argumentul n-1. Acest proces se repetă până când argumentul este egal cu 1. după care metodele numite anterior vor reveni la valori. De exemplu, atunci când se calculează factorialul 2 primul apel la factr metoda () va conduce la un al doilea tratament cu aceeași metodă, dar cu un argument de 1 secundă factr apel () returneaza valoarea 1, care va fi înmulțit cu 2 (valoarea inițială a parametrului n ). Poate că veți fi interesat să inserați o instrucțiune cout în funcția factr (). Pentru a afișa nivelul fiecărui apel și rezultatele intermediare.

Atunci când o funcție se solicită, memoria pentru variabilele și parametrii locali noi este alocată în stack-ul sistemului, iar codul funcțional este executat de la început cu aceste variabile noi. Un apel recursiv nu creează o nouă copie a funcției. Numai argumentele sunt noi. Când fiecare apel recursiv este returnat, variabilele și parametrii locali vechi sunt extrași din stiva și funcția este reluată din punctul "intern" al apelului. Cu privire la funcțiile recursive putem spune că sunt "nominalizați" și "împinși".

Prea multe apeluri recursive la o funcție pot provoca o depășire a stivei. Deoarece variabilele și parametrii locali sunt stocați în stivă de sistem și fiecare apel nou creează o nouă copie a acestor variabile, poate să apară timpul când memoria stivei este epuizată. În acest caz, alte date ("nevinovate") pot fi distruse. Dar dacă recursiunea este construită corect, cu greu trebuie să vă faceți griji.

Principalul avantaj al recursivității este că unele tipuri de algoritmi sunt implementate recursiv mai simplu decât echivalentele lor iterative. De exemplu, algoritmul de sortare Quicksort este destul de greu de implementat într-un mod iterativ. În plus, anumite sarcini (în special cele legate de inteligența artificială) sunt create pur și simplu pentru soluții recursive. În sfârșit, pentru unii programatori, procesul de gândire este organizat în așa fel încât este mai ușor pentru ei să gândească recursiv decât iterativ.

Atunci când scrieți o funcție recursivă, este necesar să includeți în ea o instrucțiune de testare a condiției (de exemplu, o instrucțiune if) care ar oferi o ieșire din funcție fără a efectua un apel recursiv. Dacă nu faceți acest lucru, atunci când apelați această funcție, nu vă puteți întoarce de la ea. Când lucrați cu recurs, acesta este cel mai frecvent tip de eroare. Prin urmare, atunci când dezvoltați programe cu funcții recursive, nu schimbați declarația cout. Pentru a fi conștient de ceea ce se întâmplă într-o anumită funcție și pentru a putea întrerupe funcționarea acesteia în caz de eroare.

Să luăm în considerare încă un exemplu de funcție recursivă. Funcția inversă () folosește recursion pentru a afișa argumentul string în ordine inversă.

// Afișați șirul în ordine inversă utilizând recursul.

folosind namespace std;

void invers (char * s);

char str [] = "Acesta este un test";







Articole similare

Trimiteți-le prietenilor: