Definirea unei funcții în programare. Funcția software și aspectul software

Operatorul de buclă este cel mai important operator și se găsește în majoritatea limbajelor de programare moderne, iar ideea de buclă a apărut în secolul al XIX-lea. Un ciclu vă permite să efectuați în mod repetat o anumită secvență de acțiuni, care este specificată de operatorii care alcătuiesc corpul ciclului.

Să începem cu operatorul buclă cu precondiție. Acest operator are forma:

în timp ce<условие>do<оператор>.

Când această instrucțiune este executată, valoarea unei expresii booleene este mai întâi evaluată. Dacă această valoare este adevărată, instrucțiunea este executată. Apoi valoarea expresiei este verificată din nou și totul se repetă până când expresia devine falsă. Fiecare execuție a unei bucle este uneori numită o iterație a buclei. Dacă expresia este falsă în timpul primei verificări, atunci instrucțiunea nu este executată deloc.

Într-o buclă cu o precondiție, o pre-verificare determină dacă se execută sau nu corpul buclei înainte de prima iterație. Dacă aceasta corespunde logicii algoritmului, atunci poate fi utilizată o buclă cu o postcondiție.

Bucla cu postcondiție are forma:

Repeta...<выражние_1>până...<выражение_2>

Aici, instrucțiunea instrucțiunii este executată mai întâi și abia apoi se calculează valoarea expresiei logice. De aceea, o astfel de buclă se numește buclă cu o postcondiție. Procesul se repetă atâta timp cât expresia devine falsă. De îndată ce valoarea sa devine adevărată, bucla se oprește. Operatorul poate fi orice, inclusiv un operator compus:

Operator_1;

Operator_2;

…………….

Operator_N;

Până<условие>

Într-o repetiție...până la buclă, verificarea este efectuată ultima, iar corpul buclei este executat cel puțin o dată în orice caz.

Instrucțiuni de buclă cu un contor: pentru...to...do și for...downto...do.

A treia opțiune pentru operatorul de buclă este buclă cu parametru. Putem considera că există două varietăți foarte asemănătoare ale buclei de contor. Primul dintre acești operatori are forma:

Parametrul pentru buclă:= valoarea de început până la valoarea finală do<оператор>;

Declarația care reprezintă corpul buclei poate fi simplă sau compusă. Parametrul buclei, precum și intervalul său de modificare, pot fi doar de tip întreg sau enumerat. Parametrul este descris împreună cu alte variabile.

După ce bucla for este executată, valoarea variabilei de control devine nedefinită.

Versiunea for...downto...do... a buclei for este similară buclei for..to...do, cu excepția faptului că în ea variabila de control la fiecare pas de execuție nu este mărită, ci redusă cu unul:

pentru j:-<выражение_1>jos la<выражение_2>do<оператор>.

Pentru a rezuma, pot fi formulate următoarele recomandări pentru utilizarea ciclurilor:

Utilizați o buclă for când știți exact de câte ori ar trebui să fie executat corpul buclei. În caz contrar, utilizați buclele repeat sau while.

· Folosiți while dacă doriți ca testul să fie făcut înainte ca corpul buclei să fie executat.

· Uneori este convenabil să verificați o posibilă ieșire dintr-o buclă undeva în mijlocul acesteia, mai degrabă decât la început sau la sfârșit.

Această ieșire a buclei este asigurată de procedura Break, care întrerupe execuția celei mai interioare bucle imbricate, fie pentru, while sau repetare. Modulul specificat se conectează automat la program dacă este necesar.

În timp ce adevăratul începe

<Выражение_1>

Dacă<оператор>apoi Break

<Выражение_2>; Sfârşit

De asemenea, merită menționată procedura Continue, care întrerupe corpul celui mai interior pentru, while, sau repetă bucla și transferă controlul în capul său, astfel încât să înceapă următoarea iterație a buclei.

Pasul buclei for este întotdeauna constant și egal cu intervalul dintre cele mai apropiate două valori ale tipului de parametru buclă.

Var (descrierea parametrilor ciclului)

i: întreg (tip întreg);

c: caracter (tip de caracter);

1. Începeți (tipărirea numerelor întregi de la 1 la 10)

Pentru i:=1 la 10 scrieți n (i); (pasul buclei este 1)

2. (tipărește numere de la 10 la -10)

Pentru 10 până la -10 (pasul buclei este -1)

3. (tipărirea caracterelor latine de la A la R)

(parametrul buclei se schimbă de la A la R în ordine alfabetică)

Pentru c:=‘A’ la ‘R’ scriețiln (c);

Execuția ciclului începe prin atribuirea unei valori de pornire parametrului. Aceasta este urmată de o verificare pentru a vedea dacă parametrul depășește valoarea finală. Dacă rezultatul verificării este afirmativ, atunci bucla este considerată finalizată și controlul este transferat operatorului urmând corpul buclei. În caz contrar, corpul buclei este executat și parametrul își schimbă valoarea la următorul în funcție de antetul buclei. Apoi, valoarea parametrului buclei este verificată din nou, iar algoritmul este repetat.

Exemplu: Calculați suma de la 1 la n.

var s,n,i: întreg;

writeln('Introduceți n');

pentru i:=1 la n face s:=s+i;

| | |
Funcţieîn programare, o bucată de cod de program (subrutină) care poate fi accesată din alt loc din program. În cele mai multe cazuri, un identificator este asociat cu o funcție, dar multe limbi permit și funcții fără nume. Numele funcției este indisolubil legat de adresa primei instrucțiuni (operator) inclusă în funcție, căreia îi este transferat controlul la apelarea funcției. După ce funcția este executată, controlul revine la adresa de retur - punctul din program în care a fost apelată funcția.

Funcția poate prelua parametri și trebuie să returneze o valoare, eventual goală. Funcțiile care revin goale sunt adesea numite proceduri. În unele limbaje de programare, declarațiile de funcții și proceduri au sintaxă diferită, în special, pot fi utilizate diferite cuvinte cheie.

Funcția trebuie să fie declarată și definită în consecință. O declarație de funcție, pe lângă nume, conține o listă de nume și tipuri de parametri (sau argumente) trecuți, precum și tipul de valoare returnat de funcție. O definiție a funcției conține codul executabil pentru funcție. În unele limbaje de programare, declararea unei funcții precede imediat definirea funcției, în timp ce într-un număr de alte limbaje este necesar să se declare mai întâi funcția și abia apoi să se furnizeze definiția acesteia.

În programarea orientată pe obiecte, funcțiile ale căror declarații sunt parte integrantă a definiției clasei se numesc metode.

Pentru a utiliza o funcție definită anterior, este necesar să indicați numele funcției în locul necesar din codul programului și să enumerați parametrii trecuți funcției. Parametrii care sunt transferați unei funcții pot fi transferați fie prin valoare, fie prin referință: pentru o variabilă transmisă după valoare, este creată o copie locală și orice modificări care apar în corpul funcției cu variabila transmisă se întâmplă de fapt cu copia locală. și nu afectează în nici un fel variabila în sine, în timp ce modificările care apar în corpul unei funcții cu o variabilă transmisă prin referință apar la variabila transmisă în sine.

O funcție își definește propriul domeniu de aplicare (local), care include parametrii de intrare, precum și acele variabile care sunt declarate direct în corpul funcției în sine.

Este posibil să apelați o funcție în cadrul funcției în sine: un astfel de apel de funcție se numește recursiv, iar procesul de apeluri succesive de funcții imbricate se numește recursie. Deoarece este necesar să ne amintim (pe stivă) adresa de retur a funcției (și, de asemenea, să alocați memorie pe aceeași stivă pentru parametrii și variabilele locale care nu sunt dinamice), recursiunea nelimitată duce la depășirea stivei, prin urmare limbaje de programare setați un anumit nivel limitativ de imbricare apeluri recursive.

  • 1 Exemple de funcții
    • 1.1 JavaScript
    • 1.2 ActionScript
    • 1.3 C++
    • 1.4 C#
    • 1,5 Pascal
    • 1,6 PHP
    • 1.7 Stadard ML
    • 1.8 Visual Basic
    • 1.9 PureBasic
  • 2 Vezi de asemenea
  • 3 Legături

Exemple de funcții

JavaScript

numele funcției (text, element) ( document.getElementById(element).innerHTML = text; )

ActionScript

numele funcției publice (text: șir) (var textfield: TextField = new TextField(); textfield.text = text; )

C++

void nume(std::string text) (std::cout<< text; }

C#

public void nume (text șir) ( System.Console.WriteLine (text); )

Pascal

procedura nume(var text: șir) începe scrierea(text);

Sfârşit;

PHP

numele funcției($text) ( echo $text; )

Stadard ML

nume distractiv t = print t

sau, care este același (vezi curry):

Fun name = print

Visual Basic

Sub Name(text) Console.WriteLine(text) End Sub

PureBasic

Procedure.l Nume(text.s) PrintN(text) EndProcedure

  • Vezi de asemenea
  • Funcție anonimă

Funcție (matematică)

Legături

Funcție (programare) Informații despre

Dacă sunteți un dezvoltator ca mine, probabil că ați studiat mai întâi paradigma OOP. Primul tău limbaj a fost Java sau C++ - sau, dacă ai noroc, Ruby, Python sau C# - așa că probabil știi ce sunt clase, obiecte, instanțe etc. Ceea ce cu siguranță nu înțelegeți prea multe sunt elementele de bază ale acelei paradigme ciudate numite programare funcțională, care diferă semnificativ nu numai de OOP, ci și de programare procedurală, orientată pe prototip și alte tipuri de programare.

Programarea funcțională are multe avantaje, dar capacitatea de a maximiza resursele CPU prin comportamentul concurent este principalul său avantaj. Mai jos ne vom uita la principiile de bază ale programării funcționale.

Introducere: Toate aceste principii sunt opționale (multe limbi nu le respectă pe deplin). Toate sunt teoretice și sunt necesare pentru definirea cât mai exactă a paradigmei funcționale.

1. Toate funcțiile sunt pure

Această regulă este cu siguranță fundamentală în programarea funcțională. Toate funcțiile sunt pure dacă îndeplinesc două condiții:

  1. O funcție apelată cu aceleași argumente returnează întotdeauna aceeași valoare.
  2. Nu apar efecte secundare în timpul execuției funcției.

Prima regulă este clară - dacă apelez la funcția sum(2, 3), mă aștept ca rezultatul să fie întotdeauna 5. De îndată ce apelați funcția rand() sau accesați o variabilă nedefinită în funcție, puritatea a funcției este încălcat, iar acest lucru nu este permis în programarea funcțională.

A doua regulă - fără efecte secundare - este de natură mai largă. Un efect secundar este o modificare a altceva decât funcția care se execută în prezent. Schimbarea unei variabile în afara unei funcții, imprimarea pe consolă, aruncarea unei excepții, citirea datelor dintr-un fișier - toate acestea sunt exemple de efecte secundare care privează funcția de puritatea sa. Aceasta poate părea o limitare majoră, dar gândiți-vă din nou. Dacă sunteți sigur că apelarea unei funcții nu va schimba nimic „din exterior”, atunci puteți utiliza această funcție în orice scenariu. Acest lucru deschide ușa către programarea concomitentă și aplicațiile multi-threaded.

2. Toate funcțiile sunt de primă clasă și de ordin superior

Acest concept nu este o caracteristică a FP (este folosit în Javascript, PHP și alte limbi) - dar este o cerință obligatorie. De fapt, Wikipedia are un articol întreg dedicat funcțiilor de primă clasă. Pentru ca o funcție să fie de primă clasă, trebuie să poată fi declarată ca variabilă. Acest lucru permite ca funcția să fie tratată ca un tip de date normal și să fie în continuare executată.

3. Variabilele sunt imuabile

Totul este simplu aici. În programarea funcțională, nu puteți modifica o variabilă după ce a fost inițializată. Puteți crea altele noi, dar nu le puteți modifica pe cele existente - și datorită acestui lucru, puteți fi sigur că nicio variabilă nu se va schimba.

4. Transparența relativă a funcțiilor

Este dificil de dat o definiție corectă a transparenței relative. Cred că cel mai precis este acesta: dacă puteți înlocui un apel de funcție cu o valoare returnată, iar starea nu se schimbă, atunci funcția este relativ transparentă. Acest lucru poate fi evident, dar voi da un exemplu.

Să presupunem că avem o funcție Java care adaugă 3 și 5:

Public int addNumbers() ( returnează 3 + 5; ) addNumbers() // 8 8 // 8

Evident, orice apel la această funcție poate fi înlocuit cu 8 - ceea ce înseamnă că funcția este relativ transparentă. Iată un exemplu de funcție opace:

Public void printText())( System.out.println("Hello World"); ) printText() // Nu returnează nimic, dar afișează "Hello World"

Această funcție nu returnează nimic, dar tipărește text, iar dacă înlocuiți apelul funcției cu nimic, starea consolei va fi diferită - ceea ce înseamnă că funcția nu este relativ transparentă.

5. Programarea funcțională se bazează pe calculul lambda

Programarea funcțională se bazează în mare măsură pe un sistem matematic numit calcul lambda. Nu sunt matematician, așa că nu voi intra în detalii - dar vreau să atrag atenția asupra două principii cheie ale calculului lambda care formează însuși conceptul de programare funcțională:

  1. În calculul lambda, toate funcțiile pot fi anonime, deoarece singura parte semnificativă a antetului funcției este lista de argumente.
  2. Când sunt apelate, toate funcțiile trec printr-un proces de curry. Este în felul următor: dacă este apelată o funcție cu mai multe argumente, atunci la început va fi executată doar cu primul argument și va returna o nouă funcție care conține 1 argument mai puțin, care va fi apelată imediat. Acest proces este recursiv și continuă până când toate argumentele au fost aplicate, returnând rezultatul final. Deoarece funcțiile sunt pure, aceasta funcționează.

După cum am spus, calculul lambda nu se termină aici - dar am acoperit doar aspectele cheie legate de FP. Acum, într-o conversație despre programarea funcțională, puteți intermite cuvantul „calcul lambda” și toată lumea va crede că vă încurcați :)

Concluzie

Programarea funcțională este un teaser serios - dar este o abordare foarte puternică și cred că popularitatea sa va crește doar.

Dacă doriți să aflați mai multe despre programarea funcțională, vă sfătuim să vă familiarizați cu exemple de utilizare a principiilor FP în JavaScript (,), precum și cu unul dedicat C# funcțional.

Utilizatorii care sunt departe de a programa în principiu întâlnesc rar conceptele de funcții și proceduri și sunt asociați cu ceva matematic și birocratic-medical. În programare, multe limbaje operează cu aceste concepte, cu toate acestea, chiar și experții nu pot înțelege clar diferența dintre o funcție și o procedură. Ca și cu acel gopher: este acolo, dar nimeni nu îl vede. Să vedem dacă diferențele sunt atât de invizibile.

Ce înseamnă termenii funcție și procedură?

  • Funcţieîn programare, un subprogram apelat de la alte subrutine de numărul necesar de ori.
  • Procedură- o parte numită a programului (subrutină), apelată în mod repetat din părțile ulterioare ale programului de numărul necesar de ori.

Comparație între funcție și procedură

Principala diferență dintre o funcție și o procedură este rezultatul pe care îl returnează. De fapt, atât funcțiile, cât și procedurile sunt blocuri indivizibile din punct de vedere logic care alcătuiesc codul programului. O funcție returnează o valoare, o procedură în majoritatea limbajelor de programare nu, sau (în C, de exemplu) returnează o valoare goală. În acest din urmă caz ​​(în C), o procedură este considerată o versiune subordonată a unei funcții.

Antetul funcției conține cuvântul „funcție”, un identificator (numele propriu al funcției), opțional o listă de parametri și, neapărat, tipul rezultatului. Corpul funcției trebuie să conțină un operator care atribuie o valoare numelui funcției, pe care o va returna ca rezultat. Antetul procedurii conține cuvântul „procedură”, un identificator (numele procedurii) și opțional o listă de parametri.

Un apel de funcție este efectuat ca parte a expresiilor în care sunt utilizate aceste expresii, un apel de procedură necesită o instrucțiune separată.

O procedură este numită numai după nume, în timp ce numele unei funcții este asociat cu valoarea acesteia. În diagramele de algoritm, un apel de funcție este reprezentat într-un bloc de ieșire sau într-un bloc de proces, un apel de procedură este reprezentat într-un bloc special „proces predefinit”.

Diferența dintre o funcție și o procedură în programare este următoarea:

  • O funcție returnează o valoare, o procedură nu.
  • Antetul funcției trebuie să conțină tipul de rezultat.
  • Corpul funcției trebuie să conțină o instrucțiune care atribuie o valoare numelui funcției.
  • Apelarea unei proceduri necesită o instrucțiune separată; apelarea unei funcții este posibilă ca parte a unei expresii.
  • Numele procedurii este necesar pentru a o apela, numele funcției este necesar pentru a atribui o valoare.
  • În diagramele de algoritm, un apel de procedură este reprezentat într-un bloc separat, un apel de funcție într-un proces sau un bloc de ieșire.

Pagina 51 din 85

1.5.1. Definirea și apelarea funcțiilor

Puterea limbajului de programare C este în mare măsură determinată de ușurința și flexibilitatea în definirea și utilizarea funcțiilor în programele în limbajul de programare C Spre deosebire de alte limbaje de programare de nivel înalt, în limbajul de programare C nu există nicio diviziune în proceduri, subrutine și. funcții aici întregul program este construit numai din funcții.

O funcție este o colecție de declarații și declarații, de obicei concepute pentru a îndeplini o anumită sarcină. Fiecare funcție trebuie să aibă un nume, care este folosit pentru a o declara, defini și apela. În orice program C trebuie să existe o funcție numită main (funcție principală), tocmai din această funcție, indiferent de locul în care se află în program, începe execuția programului.

Când o funcție este apelată, unele valori (parametri actuali) îi pot fi transmise folosind argumente (parametri formali) care sunt utilizați în timpul execuției funcției. O funcție poate returna o valoare (una!). Această valoare returnată este rezultatul execuției funcției, care, atunci când programul este executat, este înlocuită în punctul apelului funcției, oriunde are loc acest apel. De asemenea, este posibil să utilizați funcții care nu au argumente și funcții care nu returnează nicio valoare. Acțiunea unor astfel de funcții poate consta, de exemplu, în modificarea valorilor unor variabile, tipărirea unor texte etc.

Există trei concepte asociate cu utilizarea funcțiilor în limbajul de programare C - definirea funcției (descrierea acțiunilor efectuate de funcție), declararea funcției (specificarea formei de apelare a funcției) și apelul funcției.

O definiție a funcției specifică tipul de returnare, numele funcției, tipurile și numărul de parametri formali, precum și declarațiile și declarațiile variabile, numite corpul funcției, care definesc acțiunea funcției. Definiția funcției poate specifica și o clasă de memorie.

Int rus (caracter nesemnat r)
( dacă (r>="A" && c<=" ") return 1; else return 0; }

În acest exemplu, este definită o funcție numită rus, care are un parametru numit r și tip unsigned char. Funcția returnează o valoare întreagă egală cu 1 dacă parametrul funcției este o literă din alfabetul rus, sau 0 în caz contrar.

Limbajul de programare C nu necesită ca o definiție a funcției să preceadă apelul acesteia. Definițiile funcțiilor utilizate pot urma definiția funcției principale, înaintea acesteia, sau pot fi într-un alt fișier.

Totuși, pentru ca compilatorul să verifice dacă tipurile parametrilor efectivi care sunt trecuți corespund tipurilor parametrilor formali, este necesar să se plaseze o declarație (prototip) a funcției înainte de a apela funcția.

O declarație de funcție are aceeași formă ca o definiție de funcție, singura diferență fiind că nu există un corp de funcție, iar numele parametrilor formali pot fi, de asemenea, omise. Pentru funcția definită în ultimul exemplu, prototipul ar putea arăta ca

int rus (unsigned char r); sau rus (cara nesemnat);

În programele în limbajul de programare C, așa-numitele funcții de bibliotecă sunt utilizate pe scară largă, adică. funcțiile sunt pre-dezvoltate și scrise în biblioteci. Prototipurile de funcții de bibliotecă sunt situate în fișiere de antet speciale furnizate cu bibliotecile ca parte a sistemelor de programare și sunt incluse în program folosind directiva #include.

Dacă nu este specificată o declarație de funcție, atunci implicit un prototip de funcție este construit pe baza analizei primei referințe de funcție, fie că este un apel de funcție sau o definiție. Cu toate acestea, un astfel de prototip nu este întotdeauna în concordanță cu definiția ulterioară sau apelul de funcție. Se recomandă să specificați întotdeauna un prototip de funcție. Acest lucru va permite compilatorului fie să emită mesaje de diagnosticare atunci când o funcție este utilizată incorect, fie să gestioneze corect nepotrivirile argumentelor setate în timpul execuției programului.

Declararea parametrilor unei funcții la definirea acesteia se poate face în așa-numitul „stil vechi”, în care doar numele parametrilor urmează numele funcției dintre paranteze, iar declarațiile tipurilor de parametri urmează paranteze. De exemplu, funcția rus din exemplul anterior ar putea fi definită după cum urmează:

Int rus(r)
nesemnat char r;
( ... /* corpul funcției */ ... )

Conform sintaxei limbajului de programare C, definiția unei funcții are următoarea formă:

[specificator-clasă-memorie] [specificator-tip] nume-funcție
([lista-parametri-formali])
(funcții ale corpului)

Specificatorul opțional de clasă de memorie specifică clasa de memorie a funcției, care poate fi statică sau externă. Clasele de memorie vor fi discutate în detaliu în secțiunea următoare.

Specificatorul de tip de funcție specifică tipul valorii returnate și poate specifica orice tip. Dacă specificatorul de tip nu este specificat, se presupune că funcția returnează o valoare int.

O funcție nu poate returna o matrice sau o funcție, dar poate returna un pointer către orice tip, inclusiv o matrice și o funcție. Tipul de returnare specificat într-o definiție a funcției trebuie să se potrivească cu tipul din declarația funcției.

Funcția returnează o valoare dacă execuția ei se termină cu o instrucțiune return care conține o expresie. Expresia specificată este evaluată, convertită dacă este necesar într-un tip de returnare și returnată la punctul de apel al funcției ca rezultat. Dacă instrucțiunea return nu conține o expresie sau funcția se termină după ce ultima sa instrucțiune a fost executată (fără a executa instrucțiunea return), atunci valoarea returnată este nedefinită. Pentru funcțiile care nu folosesc o valoare returnată, trebuie utilizat tipul void pentru a indica faptul că nu există o valoare returnată. Dacă o funcție este definită ca o funcție care returnează o valoare și nu există nicio expresie în instrucțiunea return când iese, atunci comportamentul funcției care apelează după ce i se transmite controlul poate fi imprevizibil.

lista-parametrul-formal este o secvență de declarații de parametri formali, separate prin virgulă. Parametrii formali sunt variabile utilizate în corpul unei funcții și cărora li se acordă o valoare atunci când funcția este apelată prin copierea valorilor parametrilor actuali corespunzători în ei. Lista-parametri-formali se poate termina cu o virgulă (,) sau o virgulă cu o elipsă (,...), ceea ce înseamnă că numărul de argumente ale funcției este variabil. Cu toate acestea, se presupune că funcția are cel puțin la fel de multe argumente necesare cât numărul de parametri formali specificat înainte de ultima virgulă din lista de parametri. Această funcție poate primi mai multe argumente, dar argumentele suplimentare nu sunt verificate de tip.

Dacă o funcție nu folosește parametri, atunci prezența parantezelor este obligatorie și este recomandat să specificați cuvântul void în locul unei liste de parametri.

Ordinea și tipurile de parametri formali trebuie să fie aceleași în definiția funcției și în toate declarațiile acesteia. Tipurile parametrilor efectivi la apelarea unei funcții trebuie să fie compatibile cu tipurile parametrilor formali corespunzători. Tipul unui parametru formal poate fi orice tip de bază, structură, unire, enumerare, pointer sau matrice. Dacă nu este specificat tipul unui parametru formal, atunci acestui parametru i se atribuie tipul int.

Pentru un parametru formal, puteți specifica registrul clasei de memorie, în timp ce pentru valorile de tip int specificatorul de tip poate fi omis.

Identificatorii formali de parametri sunt utilizați în corpul funcției ca referințe la valorile transmise. Acești identificatori nu pot fi suprascriși în blocul care formează corpul funcției, dar pot fi suprascriși într-un bloc interior din corpul funcției.

La trecerea parametrilor unei funcții, conversiile aritmetice obișnuite sunt efectuate pentru fiecare parametru formal și fiecare parametru real în mod independent, dacă este necesar. După conversie, parametrul formal nu poate fi mai scurt decât int, adică. declararea unui parametru formal cu tipul char este echivalentă cu declararea lui cu tipul int. Iar parametrii care sunt numere reale sunt de tip double.

Tipul convertit al fiecărui parametru formal determină modul în care sunt interpretate argumentele introduse în stivă la apelarea funcției. O nepotrivire între tipurile de argumente efective și parametrii formali poate provoca o interpretare greșită.

Corpul unei funcții este o instrucțiune compusă care conține instrucțiuni care definesc acțiunea funcției.

Toate variabilele declarate în corpul unei funcții fără a specifica o clasă de memorie au clasa de memorie auto, adică. sunt locale. Când o funcție este apelată, variabilelor locale li se alocă memorie pe stivă și sunt inițializate. Controlul este transferat la prima instrucțiune a corpului funcției și începe execuția funcției, care continuă până când este întâlnită instrucțiunea return sau ultima instrucțiune a corpului funcției. În acest caz, controlul revine la punctul care urmează punctului de apel, iar variabilele locale devin inaccesibile. Când o funcție este apelată din nou, memoria pentru variabilele locale este alocată din nou și, prin urmare, vechile valori ale variabilelor locale se pierd.

Parametrii funcției sunt transferați după valoare și pot fi considerați ca variabile locale, pentru care memoria este alocată atunci când funcția este apelată și inițializată cu valorile parametrilor actuali. Când funcția iese, valorile acestor variabile se pierd. Deoarece parametrii sunt transferați după valoare, corpul funcției nu poate modifica valorile variabilelor din funcția de apelare care sunt parametri reali. Cu toate acestea, dacă treceți un pointer către o variabilă ca parametru, atunci folosind operația de redirecționare puteți modifica valoarea acestei variabile.

/* Utilizarea incorectă a parametrilor */
modificare nulă (int x, int y)
( int k=x;
x=y;
y=k;
}

Într-o funcție dată, valorile variabilelor x și y, care sunt parametri formali, sunt schimbate, dar deoarece aceste variabile există numai în cadrul funcției de modificare, valorile parametrilor efectivi utilizați la apelarea funcției vor rămâne neschimbat. Pentru a schimba valorile argumentelor reale, puteți utiliza funcția dată în exemplul următor.

/* Utilizarea corectă a parametrilor */
modificare nulă (int *x, int *y)
( int k=*x;
*x=*y;
*y=k;
}

Când apelați o astfel de funcție, nu valorile variabilelor, ci adresele acestora ar trebui să fie utilizate ca parametri reali

Dacă trebuie să apelați o funcție înainte ca aceasta să fie definită în fișierul în cauză, sau definiția funcției este într-un fișier sursă diferit, atunci apelul funcției ar trebui să fie precedat de o declarație a funcției respective. Declarația funcției (prototip) are următorul format:

[specificator-clasă-memorie] [specificator-tip] nume-funcție ([lista-parametri-formal]) [,lista-nume-funcție];

Spre deosebire de definiția unei funcții, într-un prototip, antetul este urmat imediat de un punct și virgulă și nu există un corp de funcție. Dacă mai multe funcții diferite returnează valori de același tip și au aceleași liste de parametri formali, atunci aceste funcții pot fi declarate în același prototip, specificând numele uneia dintre funcții ca nume-funcție și plasând toate altele într-o listă de nume-funcție și fiecare funcție trebuie să fie însoțită de o listă de parametri formali. Regulile de utilizare a altor elemente de format sunt aceleași ca atunci când definiți o funcție. Când se declară o funcție, nu este necesar să se specifice numele parametrilor formali, iar dacă sunt specificati, domeniul lor se extinde doar până la sfârșitul declarației.

Un prototip este o declarație explicită a funcției care precede definiția funcției. Tipul de returnare al unei declarații de funcție trebuie să se potrivească cu tipul de returnare al definiției funcției.

Dacă nu este specificat un prototip de funcție, dar este întâlnit un apel de funcție, atunci un prototip implicit este construit dintr-o analiză a formei apelului de funcție. Tipul de returnare al prototipului creat este int, iar lista de tipuri și numărul de parametri ai funcției se formează pe baza tipurilor și numărului de parametri efectivi utilizați în acest apel.

Astfel, un prototip de funcție trebuie specificat în următoarele cazuri:

1. Funcția returnează o valoare de alt tip decât int.

2. Este necesar să inițializați un pointer către o funcție înainte ca această funcție să fie definită.

Având o listă completă de tipuri de argumente ale parametrilor în prototip, vă permite să verificați dacă tipurile de parametri reali atunci când apelați o funcție corespund tipurilor de parametri formali și, dacă este necesar, să efectuați conversiile corespunzătoare.

Într-un prototip, puteți specifica că numărul de parametri ai funcției este variabil sau că funcția nu are parametri.

Dacă prototipul este specificat cu o clasă de memorie statică, atunci definiția funcției trebuie să aibă și o clasă de memorie statică. Dacă specificatorul clasei de memorie nu este specificat, atunci se presupune clasa de memorie extern.

Apelul funcției are următorul format:

expresie-adresă ([lista-expresii])

Deoarece din punct de vedere sintactic numele unei funcții este adresa de la începutul corpului funcției, se poate folosi o expresie de adresă (inclusiv numele funcției sau neadresarea unui pointer către o funcție) având valoarea adresei funcției. ca un apel la funcție.

O listă de expresii este o listă de parametri reali trecuți unei funcții. Această listă poate fi goală, dar este necesară prezența parantezelor.

Parametrul real poate fi o valoare de orice tip de bază, o structură, o uniune, o enumerare sau un pointer către un obiect de orice tip. Matricea și funcția nu pot fi utilizate ca parametri reali, dar pot fi utilizați pointeri către aceste obiecte.

Apelul funcției se execută după cum urmează:

1. Expresiile din lista de expresii sunt evaluate și supuse transformărilor aritmetice uzuale. Apoi, dacă prototipul funcției este cunoscut, tipul argumentului real rezultat este comparat cu tipul parametrului formal corespunzător. Dacă nu se potrivesc, atunci fie se efectuează o conversie de tip, fie se generează un mesaj de eroare. Numărul de expresii din lista de expresii trebuie să se potrivească cu numărul de parametri formali, cu excepția cazului în care funcția are un număr variabil de parametri. În acest din urmă caz, doar parametrii obligatorii sunt supuși verificării. Dacă prototipul funcției specifică că nu necesită parametri, dar aceștia sunt specificați la apelare, este generat un mesaj de eroare.

2. Valorile parametrilor actuali sunt atribuite parametrilor formali corespunzători.

3. Controlul este transferat primului operator al funcției.

4. Executarea unei instrucțiuni return în corpul unei funcții returnează control și, eventual, valoare funcției care apelează. În absența unei instrucțiuni return, controlul revine după ce ultima instrucțiune a corpului funcției este executată, iar valoarea returnată este nedefinită.

Expresia de adresă dinaintea parantezelor specifică adresa funcției care trebuie apelată. Aceasta înseamnă că funcția poate fi apelată printr-un indicator de funcție.

int (*fun)(int x, int *y);

Aici variabila fun este declarată ca un pointer către o funcție cu doi parametri: de tip int și un pointer către int. Funcția în sine trebuie să returneze o valoare int. Parantezele care conțin numele pointerului fun și atributul pointerului * sunt obligatorii, în caz contrar intrarea

int *fun (intx,int *y);

va fi interpretat ca o declarație de funcție fun care returnează un pointer către int.

Un apel de funcție este posibil numai după inițializarea valorii indicatorului distractiv și are forma:

Această expresie folosește operatorul de redirecționare * pentru a obține adresa funcției indicată de indicatorul distractiv.

Un indicator de funcție poate fi transmis ca parametru de funcție. În acest caz, dereferențiarea are loc în timpul unui apel la funcția la care face referire indicatorul funcției. Puteți atribui o valoare unui indicator de funcție într-un operator de atribuire utilizând numele funcției fără o listă de parametri.

Dublu (*fun1)(int x, int y);
dublu fun2(int k, int l);
fun1=fun2; /* inițializarea unui indicator de funcție */
(*fun1)(2,7); /* apel la functie */

În exemplul de mai sus, funcția pointer fun1 este descrisă ca un pointer către o funcție cu doi parametri care returnează o valoare de tip double și este descrisă și funcția fun2. Altfel, i.e. Când un indicator de funcție este atribuit unei funcții descrise, alta decât un pointer, va apărea o eroare.

Să luăm în considerare un exemplu de utilizare a unui indicator de funcție ca parametru al unei funcții care calculează derivata funcției cos(x).

Proiz dublu(x dublu, dx dublu, dublu (*f)(x dublu));
distracție dublă(z dublu);
int main()
{
x dublu; /* punct de calcul derivat */
dublu dx; /* increment */
dublu z; /* valoare derivată */
scanf("%f,%f",&x,&dx); /* introduceți valorile x și dx */
z=proiz(x,dx,fun); /* apel de funcție */
printf("%f",z); /* imprimă valoarea derivată */
întoarce 0;
}
dublu proiz(dublu x,dublu dx, dublu (*f)(dublu z))
( /* functie care calculeaza derivata */
dublu xk,xk1,pr;
xk=fun(x);
xk1=fun(x+dx);
pr=(xk1/xk-1e0)*xk/dx;
return pr;
}
distracție dublă (z dublu)
( /* functie din care se calculeaza derivata */
întoarcere (cos(z));
}

Pentru a calcula derivata unei alte funcții, puteți modifica corpul funcției distractive sau puteți utiliza numele unei alte funcții atunci când apelați funcția proiz. În special, pentru a calcula derivata funcției cos(x), puteți apela funcția proiz sub forma

z=proiz(x,dx,cos);

și pentru a calcula derivata funcției sin(x) în forma

z=proiz(x,dx,sin);

Orice funcție dintr-un program în limbajul de programare C poate fi apelată recursiv, adică. se poate numi. Compilatorul permite orice număr de apeluri recursive. Cu fiecare apel, parametrilor formali și variabilele cu clasa de memorie auto și registru li se alocă o nouă zonă de memorie, astfel încât valorile lor de la apelurile anterioare să nu se piardă, ci doar valorile apelului curent să fie disponibile în orice moment.

Variabilele declarate cu clasa de memorie statică nu necesită alocarea unei noi locații de memorie de fiecare dată când se efectuează un apel recursiv de funcție, iar valorile lor sunt disponibile pe toată durata execuției programului.

Un exemplu clasic de recursivitate este definiția matematică a factorialului n! :

N! = 1 pentru n=0;
n*(n-1)! pentru n>1.

Funcția care calculează factorialul va arăta astfel:

Fapt lung (int n)
{
return ((n==1) ? 1: n*fakt(n-1));
}

Deși compilatorul limbajului de programare C nu limitează numărul de apeluri recursive de funcții, acest număr este limitat de resursele de memorie ale computerului și, dacă există prea multe apeluri recursive, poate apărea o depășire a stivei.