Descrierea și utilizarea funcțiilor personalizate c. Definirea și apelarea funcțiilor. Care sunt funcțiile folosite în C?

Până acum, am scris programe într-un singur cod, indivizibil din punct de vedere funcțional. Algoritmul programului era conținut în funcția principală și nu existau alte funcții în program. Am scris programe mici, așa că nu a fost nevoie să ne declarăm funcțiile. Pentru scris programe mari, experiența arată că este mai bine să folosiți funcții. Programul va consta din fragmente de cod separate un fragment de cod separat este o funcție. Separat, deoarece munca unei funcții separate nu depinde de munca nici unei alte. Adică, algoritmul din fiecare funcție este suficient funcțional și independent de alți algoritmi din program. Odată ce ați scris o funcție, aceasta poate fi transferată cu ușurință în alte programe. O funcție (în programare) este o bucată de cod sau un algoritm implementat într-un limbaj de programare cu scopul de a efectua o anumită secvență de operații. Deci, funcțiile vă permit să faceți un program modular, adică să împărțiți programul în mai multe subrutine mici (funcții), care îndeplinesc împreună sarcina. Un alt avantaj uriaș al funcțiilor este că pot fi reutilizate. Această ocazie vă permite să reutilizați codul scris o dată, ceea ce, la rândul său, reduce foarte mult cantitatea de cod de program!

Pe lângă faptul că C++ prevede declararea funcțiilor sale, puteți utiliza și funcții definite în fișierele de antet standard ale limbajului de programare C++. Pentru a utiliza funcția definită în fișierul antet, trebuie să o includeți. De exemplu, pentru a utiliza o funcție care ridică un anumit număr la o putere, trebuie să includeți un fișier antet și rulați funcția pow() în corpul programului. Să dezvoltăm un program în care vom rula funcția pow().

// inc_func.cpp: Definește punctul de intrare pentru aplicația consolă. #include "stdafx.h" //acțiunea 1 - includeți fișierul antet

// cod Cod::Blocuri

// Cod Dev-C++

// inc_func.cpp: Definește punctul de intrare pentru aplicația consolă. //acțiunea 1 - includeți fișierul antet care conţine prototipuri ale funcţiilor matematice de bază #include int main(int argc, char* argv) ( float power = pow(3.14,2); //acțiunea 2 - rulează funcția de ridicare a unui număr la puterea returnată 0; )

Includerea fișierelor antet se face așa cum se arată în linia 5, adică este declarată directiva preprocesor #include, după care în interiorul caracterelor<>se scrie numele fișierului antet. Când fișierul antet este inclus, puteți utiliza funcția, care este ceea ce se face în linia 9.Funcția pow() ridică un număr 3.14 pătrat și atribuie rezultatul rezultat variabilei de putere, unde
pow — numele funcției;
numerele 3.14 și 2 sunt argumente ale funcției;

Numele funcției este întotdeauna urmat de paranteze, în interiorul cărora argumentele sunt trecute funcției, iar dacă există mai multe argumente, acestea sunt separate între ele prin virgule. Argumentele sunt necesare pentru ca funcțiile să transmită informații. De exemplu, pentru a pătra numărul 3,14 folosind funcția pow(), trebuie să spuneți cumva acestei funcție ce număr este și la ce putere să-l ridicați. Tocmai de aceea au fost inventate argumentele funcției, dar există funcții în care argumentele nu sunt transmise astfel de funcții sunt numite cu paranteze goale. Deci, pentru a utiliza o funcție din fișierul antet standard C++, trebuie să efectuați doi pași:

  1. Includeți fișierul antet necesar;
  2. Lansați funcția dorită.

Pe lângă apelarea funcțiilor din fișierele antet standard, limbajul de programare C++ oferă posibilitatea de a vă crea propriile funcții. Există două tipuri de funcții în limbajul de programare C++:

  1. Funcții care nu returnează valori
  2. Funcții care returnează o valoare

Funcțiile care nu returnează o valoare nu oferă niciun răspuns programului după finalizarea activității lor. Să ne uităm la structura declarării unor astfel de funcții.

// structura declarației funcțiilor care nu returnează valori void /*numele funcției*/(/*parametrii funcției*/) // antetul funcției ( // corpul funcției)

Randul 2începe cu cuvântul rezervat void este un tip de date care nu poate stoca date. Tipul de date void înseamnă că această funcție nu returnează nicio valoare. void nu are altă utilizare și este necesar doar pentru ca compilatorul să poată determina tipul funcției. După cuvântul rezervat void se scrie numele funcției. Imediat după numele funcției sunt două paranteze, una de deschidere și una de închidere. Dacă o funcție trebuie să transfere unele date, atunci parametrii funcției sunt declarați în paranteze, sunt separați unul de celălalt prin virgule. Linia 2 se numește antetul funcției. După antetul funcției, sunt scrise două acolade, în interiorul cărora există un algoritm numit corpul funcției. Să dezvoltăm un program în care declarăm o funcție pentru găsirea factorialului, iar funcția nu ar trebui să returneze o valoare.

<= numb; i++) // цикл вычисления значения n! rezult *= i; // накапливаем произведение в переменной rezult cout << numb << "! = " << rezult << endl; // печать значения n! } int main(int argc, char* argv) { int digit; // переменная для хранения значения n! cout << "Enter number: "; cin >> cifra; faktorial(cifra);//porniți funcția de găsire a sistemului factorial(„pauză”); întoarce 0; )

// cod Cod::Blocuri

// Cod Dev-C++

folosind namespace std; // declararea unei funcții pentru găsirea n! void faktorial(int numb) // antetul funcției ( int rezult = 1; // inițializați variabila rezult cu valoarea 1 pentru (int i = 1; i<= numb; i++) // цикл вычисления значения n! rezult *= i; // накапливаем произведение в переменной rezult cout << numb << "! = " << rezult << endl; // печать значения n! } int main(int argc, char* argv) { int digit; // переменная для хранения значения n! cout << "Enter number: "; cin >> cifra; faktorial(cifra);//rularea funcției de găsire a randamentului factorial 0; )

După ce au fost incluse toate fișierele de antet necesare, puteți declara o funcție pentru găsirea factorialului Prin declararea unei funcții înțelegem alegerea numelui funcției, definirea parametrilor funcției și scrierea algoritmului care este corpul funcției. . După parcurgerea acestor pași, funcția poate fi utilizată în program. Deoarece funcția nu ar trebui să returneze o valoare, tipul returnat trebuie să fie void . Numele functiei este faktorial, in paranteze este declarata variabila numb de tip int. Această variabilă este un parametru al funcției faktorial(). Astfel, toate reclamele în linia 8împreună alcătuiesc antetul funcției. Liniile 9 - 14 alcătuiesc corpul funcției faktorial(). În interiorul corpului, linia 10 declară variabila rezult , care va stoca rezultatul găsirii n! După care, în rândurile 11-12 Un operator de buclă for a fost declarat pentru a găsi factorialul. ÎN linia 13 Se declară operatorul cout, cu ajutorul căruia se va imprima pe ecran valoarea factorialului. Acum că funcția este declarată, o puteți utiliza. ÎN linia 21 Este lansată funcția faktorial(digit), argumentul este trecut în parantezele funcției, adică valoarea conținută în variabila cifre. Rezultatul programului (vezi Figura 1).

Figura 1 - Funcții în C++

Deci, după rularea programului, a fost introdus numărul 5, iar programul a calculat că valoarea 120 este 5!.

Funcțiile de returnare a valorii returnează un rezultat specific la finalizarea activității lor. Astfel de funcții pot returna o valoare de orice tip de date. Structura funcțiilor care returnează o valoare va fi ușor diferită de structura funcțiilor discutate mai devreme.

// structura declarației de funcții care returnează valori ​​/*tipul de date returnate*/ /*numele funcției*/(/*parametrii funcției*/) // antetul funcției ( // corpul funcției returnează /*valoarea de returnare*/; )

Structura declarațiilor de funcții rămâne aproape neschimbată, cu excepția a două linii. În antetul funcției, trebuie mai întâi să definiți tipul de date returnate, acesta poate fi un tip de date int dacă doriți să returnați un număr întreg sau un tip de date flotant pentru numerele în virgulă mobilă. În general, orice alt tip de date, totul depinde de ce ar trebui să returneze funcția. Deoarece funcția trebuie să returneze o valoare, trebuie prevăzut un mecanism special pentru aceasta, ca în linia 5. Folosind cuvântul rezervat return, puteți returna o valoare când funcția se finalizează. Tot ce este necesar este să specificați o variabilă care conține valoarea dorită, sau o anumită valoare, după instrucțiunea return. Valoare returnată tip de date în linia 5 trebuie să se potrivească cu tipul de date în randul 2. Să reluăm programul pentru găsirea factorialului, astfel încât funcția faktorial() să returneze valoarea factorială.

// struct_func.cpp: Definește punctul de intrare pentru aplicația consolă. #include „stdafx.h” #include <= numb; i++) // цикл вычисления значения n! rezult *= i; // накапливаем произведение в переменной rezult return rezult; // передаём значение факториала в главную функцию } int main(int argc, char* argv) { int digit; // переменная для хранения значения n! cout << "Enter number: "; cin >> cifra; cout<< digit << "! = " << faktorial(digit) << endl;// запуск функции нахождения факториала system("pause"); return 0; }

// cod Cod::Blocuri

// Cod Dev-C++

// struct_func.cpp: Definește punctul de intrare pentru aplicația consolă. #include folosind namespace std; // declararea unei funcții pentru găsirea n! int faktorial(int numb) // antetul funcției ( int rezult = 1; // inițializați variabila rezult cu valoarea 1 pentru (int i = 1; i<= numb; i++) // цикл вычисления значения n! rezult *= i; // накапливаем произведение в переменной rezult return rezult; // передаём значение факториала в главную функцию } int main(int argc, char* argv) { int digit; // переменная для хранения значения n! cout << "Enter number: "; cin >> cifra; cout<< digit << "! = " << faktorial(digit) << endl;// запуск функции нахождения факториала return 0; }

Funcția faktorial() are acum un tip de date returnate de int deoarece n! este un număr întreg.B linia 13 se declară o instrucțiune return care returnează valoarea conținută în variabila rezult. ÎN linia 21 Rulem funcția faktorial(), a cărei valoare returnată este trimisă fluxului de ieșire folosind operatorul cout. S-ar putea scrie astfel: int fakt = faktorial(cifra); - variabila de tip int atribuim valoarea returnata functiei faktorial(), dupa care variabila fakt va stoca valoarea n! . Rezultatul programului nu s-a schimbat (vezi Figura 2).

Introduceți numărul: 5 5! = 120 Pentru a continua, apăsați orice tastă. . .

Figura 2 - Funcții în C++

Am analizat două tipuri de funcții, iar declararea funcțiilor a fost efectuată în zona programului, după includerea fișierelor de antet, dar înainte de începerea funcției main(). Există mai multe moduri de a declara funcții (vezi Figura 3).

Figura 3 - Funcții în C++

Pe Figura 3 arată 4 moduri de a declara funcții în limbajul de programare C++. Să ne uităm la structura declarațiilor de funcții într-un singur fișier, cu funcția principală. Funcțiile pot fi declarate în două zone, înaintea funcției main() și după funcția main(). Până acum am declarat funcții într-un singur fișier, înaintea funcției main() - acesta este cel mai simplu mod.

// struct_func.cpp: Definește punctul de intrare pentru aplicația consolă. #include "stdafx.h" /*area 1 - declararea funcțiilor înainte de începerea lui main(), un loc pentru declararea funcțiilor declarate în această zonă nu au nevoie de prototipuri */ int main(int argc, char* argv) ( returnează 0; )

Dacă funcțiile sunt declarate în regiunea 1, înainte de funcția principală, atunci nu sunt necesare prototipuri pentru aceste funcții. Este un stil de programare bun pentru a declara funcții după main() . Să ne uităm la structura unei astfel de declarații de funcție.

// struct_func.cpp: Definește punctul de intrare pentru aplicația consolă. #include "stdafx.h" // loc pentru declararea prototipurilor de funcții int main(int argc, char* argv) ( return 0; ) /*area 2 - declararea funcțiilor după main() loc pentru declararea funcțiilor */

// cod Cod::Blocuri

// Cod Dev-C++

// struct_func.cpp: Definește punctul de intrare pentru aplicația consolă. // loc pentru declararea prototipurilor de funcții int main(int argc, char* argv) ( return 0; ) /*zona 2 - declararea funcțiilor după main() loc pentru declararea funcțiilor */

Zona de declarare a funcției s-a mutat până la sfârșitul programului, după main() . În ceea ce privește metoda de declarare a funcțiilor în sine, aceasta nu s-a schimbat. Dar din moment ce funcțiile sunt declarate după main() , nu va fi posibilă utilizarea lor, deoarece ordinea declarațiilor s-a schimbat și funcția main() pur și simplu nu va vedea funcțiile declarate după. Deci, pentru ca aceste funcții să fie vizibile în main(), există conceptul de prototip. Un prototip de funcție este un antet de funcție care este declarat înaintea funcției main(). Și dacă declarați un prototip de funcție, atunci funcția poate fi văzută în main() .

// sintaxă declarație prototip /*funcție returnează tipul de date*/ /*numele funcției*/(/*parametrii funcției*/);

Structura unei declarații prototip este foarte asemănătoare cu structura unei declarații de funcție. Să dezvoltăm un program care determină dacă numărul de cinci cifre introdus este un palindrom. Un palindrom este un număr sau un text care citește la fel atât în ​​stânga, cât și în dreapta: 93939; 49094; 11311.

// palindrom_func.cpp: Definește punctul de intrare pentru aplicația consolă. #include „stdafx.h” #include << "Enter 5zn-e chislo: "; // введите пятизначное число int in_number, out_number; // переменные для хранения введённого пятизначного числа cin >> << "Number " << out_number << " - palendrom" << endl; else cout<<"This is not palendrom"<

// cod Cod::Blocuri

// Cod Dev-C++

// palindrom_func.cpp: Definește punctul de intrare pentru aplicația consolă. #include folosind namespace std; bool palindrom5(int); // prototipul funcției pentru găsirea unui palindrom de numere din cinci cifre int main(int argc, char* argv) ( cout<< "Enter 5zn-e chislo: "; // введите пятизначное число int in_number, out_number; // переменные для хранения введённого пятизначного числа cin >>in_numar; out_number = in_number; // stochează numărul introdus în variabila out_number if (palindrom5(in_number)) // dacă funcția returnează adevărat, atunci condiția este adevărată, în caz contrar funcția va returna false - false cout<< "Number " << out_number << " - palendrom" << endl; else cout<<"This is not palendrom"<

ÎN linia 7 a fost anunțată o funcție prototip pentru găsirea unui palindrom de numere din cinci cifre. Vă rugăm să rețineți că prototipul trebuie să se potrivească complet cu antetul funcției, dar există încă unele diferențe. De exemplu, prototipul nu trebuie să listeze numele parametrilor, este suficient să le declare tipurile de date. Ar trebui să puneți întotdeauna un punct și virgulă la sfârșitul unei declarații de prototip. În caz contrar, declarația prototipului este aceeași cu declarația antetului unei singure funcții. Prototipul trebuie declarat pentru fiecare funcție separat. Variabila out_number este folosită pentru a stoca temporar numărul introdus. ÎN linia 16 condiția instrucțiunii de selecție if rulează funcția palindrom5(). Argumentul pentru aceasta este variabila in_number. funcția va returna o valoare de tip bool, iar dacă funcția returnează true, atunci condiția va fi adevărată, în caz contrar va fi falsă. Ar fi posibil să atribuiți mai întâi valoarea returnată de funcție unei variabile și apoi să înlocuiți această variabilă în condiția instrucțiunii de selecție if, dar acest lucru ar crește codul programului cu o linie. ÎN liniile 23 - 40 Este declarată funcția palindrom5(), cu un parametru prin care un număr de cinci cifre este transmis funcției. Variabilele sold1, sold2, sold4, sold5 sunt declarate în linia 25, și sunt necesare pentru stocarea cifrelor unui număr de cinci cifre: primul, al doilea, al patrulea, al cincilea (numerotare - de la dreapta la stânga). În rândurile 26, 29, 32, 35 se efectuează aceeași operațiune - restul diviziunii. Operația de împărțire a restului taie un bit de la dreapta la stânga și le stochează în variabilele sold1, balance2, balance4, balance5, respectiv. Mai mult, operațiunea restului de divizare alternează cu operațiunea de divizare obișnuită. Operația de împărțire se efectuează în rândurile 27, 30 , 33 , și micșorează numărul introdus de cinci cifre în pași cu o cifră. ÎN linia 30 Operația de împărțire reduce numărul introdus cu două cifre deodată, deoarece numărul este de cinci cifre, iar cifra din mijloc nu ne interesează, poate fi orice. ÎN rândurile 36 - 39 se declară un operator de selecție if , care compară cifrele unui număr de cinci cifre, iar dacă acestea sunt egale în mod corespunzător, atunci funcția va returna true , în caz contrar false . Rezultatul programului (vezi Figura 4).

Introduceți numărul 5zn-e: 12321 Numărul 12321 - palendrom Pentru a continua, apăsați orice tastă. . .

Figura 4 - Funcții în C++

Până acum am declarat funcții în același fișier ca și programul principal, adică unde se află funcția main(). În C++, este posibil să plasați declarații de funcție într-un fișier separat, apoi va trebui să includeți fișierul cu funcțiile, așa cum este cazul includerii fișierelor de antet standard. Există două moduri:

  1. crearea unui fișier *.cpp în care sunt declarate funcții;
  2. crearea de fișiere *.cpp și *.h.

A doua metodă este un stil de programare bun. Astfel, dacă declarați funcții într-un alt fișier, atunci faceți-o conform metodei a doua. Să reluăm programul de găsire a palindromului, astfel încât declarația funcției palindrom5() să fie într-un fișier *.cpp separat. Fișierul *.h este necesar pentru a ascunde implementarea funcțiilor, adică fișierul *.h va conține prototipuri de funcție. Folosind MVS Solution Explorer, creați un fișier *.h și numiți-l palendrom.

// cod de fișier palendrom.h #ifndef palendrom #define palendrom bool palindrom5(int); // prototip al funcției de găsire a unui palindrom de numere din cinci cifre #endif

Directive în liniile 2,3,5 trebuie să fie întotdeauna declarate în fișierele prototip de funcție, iar prototipurile de funcție sunt întotdeauna declarate în fișiere *.h. După directivele scrise în liniile 2,3, dar prototipurile de funcții sunt declarate înainte de directiva #endif. Linia 4 declară prototipul funcției palindrom5(). Declarația acestei funcții se află în fișierul palendrom.cpp, care a fost creat anterior folosind MVS Solution Explorer.

// conținutul fișierului palendrom.cpp #include "stdafx.h" #include "palendrom.h" bool palindrom5(int number) // funcție pentru găsirea palindromului numerelor din cinci cifre ( int balance1, balance2, balance4, balance5 ; // variabile care stochează rezultate intermediare sold1 = număr % 10 // variabilei sold1 este alocat primul număr = număr / 10 // scade numărul introdus cu o cifră = numărul % 10; al doilea număr rămas = număr / 100 număr cu două cifre sold4 = număr % 10 // al patrulea număr rămas = număr / 10 = număr % 10; variabilei sold5 i se atribuie al cincilea rest dacă ((balance1 == balance5) && (balance2 == balance4)) returnează adevărată // funcția returnează valoarea adevărată // funcția returnează o valoare falsă;

// cod Cod::Blocuri

// Cod Dev-C++

// conținutul fișierului palendrom.cpp #include "palendrom.h" bool palindrom5(int number) // funcție pentru găsirea palindromului numerelor din cinci cifre ( int balance1, balance2, balance4, balance5; // variabile care stochează rezultate intermediare sold1 = număr % 10 // soldul variabil1 i s-a atribuit primul număr rămas = număr / 10 // scade numărul introdus cu o cifră sold2 = numărul % 10 // soldul variabil2 i s-a atribuit al doilea număr / 100; ; // scade numărul introdus cu două cifre sold4 = număr % 10 // soldul variabil4 este alocat al patrulea număr rămas / 10 // scade numărul introdus cu o cifră = număr % 10; este alocat al cincilea rest if ((balance1 == sold5) && (balance2 == balance4)) returnează adevărat // funcția returnează valoarea adevărată // funcția returnează valoarea falsă;

Fișierul palendrom.cpp conține o declarație a funcției palindrom5(). Deoarece fișierul palendrom.cpp este un fișier executabil (*.cpp sunt fișiere executabile), este necesar să includeți containerul „stdafx.h” în el, ca în randul 2. Pentru a lega fișierul în care este declarată funcția palindrom5() și fișierul cu prototipul său, să includem fișierul antet (fișierul cu prototipul), acest lucru se face în linia 3. Vă rugăm să rețineți că atunci când conectați fișierul creat de noi, sunt folosite ghilimele duble și nu mai mari sau mai mici decât semne. Tot ce rămâne este să rulați funcția palindrom5() în fișierul executabil principal func_palendrom.cpp .

// func_palendrom.cpp: Definește punctul de intrare pentru aplicația consolă. #include „stdafx.h” #include << "Enter 5zn-e chislo: "; // введите пятизначное число int in_number, out_number; // переменные для хранения введённого пятизначного числа cin >>in_numar; out_number = in_number; // stochează numărul introdus în variabila out_number if (palindrom5(in_number)) // dacă funcția returnează adevărat, atunci condiția este adevărată, în caz contrar funcția va returna false - false cout<< "Number " << out_number << " - palendrom" << endl; else cout<<"This is not palendrom"<

// cod Cod::Blocuri

// Cod Dev-C++

// func_palendrom.cpp: Definește punctul de intrare pentru aplicația consolă. #include // include fișierul antet, cu funcția prototip palindrom5() #include "palendrom.h" folosind namespace std; int main(int argc, char* argv) ( cout<< "Enter 5zn-e chislo: "; // введите пятизначное число int in_number, out_number; // переменные для хранения введённого пятизначного числа cin >>in_numar; out_number = in_number; // stochează numărul introdus în variabila out_number if (palindrom5(in_number)) // dacă funcția returnează adevărat, atunci condiția este adevărată, în caz contrar funcția va returna false - false cout<< "Number " << out_number << " - palendrom" << endl; else cout<<"This is not palendrom"<

ÎN linia 6 am inclus un fișier cu un prototip al funcției palindrom5(), după care putem folosi această funcție. Deci, am împărțit programul în trei fișiere:

  • fișier proiect: func_palendrom.cpp
  • fișier antet palendrom.h
  • fișier executabil palendrom.cpp

Asociem fișierul proiect cu fișierul antet și asociem fișierul antet cu fișierul executabil, caz în care fișierul proiect va vedea funcția palindrom5() și o va putea rula.

O mare parte din puterea limbajului SI provine din ușurința și flexibilitatea în definirea și utilizarea funcțiilor în programele SI. Spre deosebire de alte limbaje de programare de nivel înalt, limbajul SI nu se împarte în proceduri, subrutine și funcții aici întregul program este construit doar 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 SI 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ă folosiț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 SI - 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

Î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.

Nu există nicio cerință în SI ca definiția unei funcții să preceadă neapărat apelul ei. 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 (car nesemnat);

În programele SI, 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, indiferent dacă 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 SI, definiția unei funcții are următoarea formă:

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

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 la orice tip, inclusiv o matrice și o funcție. Tipul returnat 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ă, tipul void trebuie utilizat 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ță separată de virgulă de declarații de parametri formali. 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 nu se efectuează verificarea de tip asupra argumentelor suplimentare.

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 subiacent, 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 */ void change (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 */ void change (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 de funcție și plasând toate celelalte într-o listă de nume-funcție, fiecare funcție trebuind 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ă nu este specificat specificatorul clasei de memorie, atunci se presupune clasa de memorie extern.

Apelul funcției are următorul format:

expresie-adresă ([lista-expresie])

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 si supuse transformarilor aritmetice obisnuite. 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 instrucțiunii return în corpul funcției 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() ( dublu x; /* punct de calcul derivat */ double dx; /* increment */ double z; /* valoare derivată */ scanf("%f,%f",&x,&dx); /* intrare valorile lui x și dx */ z=proiz(x,dx,fun); 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 ) double fun(double z) ( /* functie din care se calculeaza derivata (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 SI 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 când n=0; n*(n-1)! pentru n>1.

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

Long fakt(int n) ( return ((n==1) ? 1: n*fakt(n-1)); )

Deși compilatorul SI 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.

1.5.2. Apelarea unei funcții cu un număr variabil de parametri

Când apelați o funcție cu un număr variabil de parametri, orice număr necesar de argumente este specificat în apelul la această funcție. În declararea și definirea unei astfel de funcții, un număr variabil de argumente este specificat printr-o elipsă la sfârșitul listei de parametri formali sau a listei de tipuri de argumente.

Toate argumentele date într-un apel de funcție sunt introduse în stivă. Numărul de parametri formali declarați pentru o funcție este determinat de numărul de argumente care sunt preluate din stivă și atribuite parametrilor formali. Programatorul este responsabil pentru selectarea corectă a argumentelor suplimentare din stivă și determinarea numărului de argumente care se află pe stivă.

Exemple de funcții cu un număr variabil de parametri sunt funcțiile din biblioteca de funcții limba SI care efectuează operații de intrare/ieșire a informațiilor (printf, scanf etc.). Aceste funcții sunt discutate în detaliu în partea a treia a cărții.

Programatorul își poate dezvolta funcțiile cu un număr variabil de parametri. Pentru a oferi o modalitate convenabilă de a accesa argumentele unei funcții cu un număr variabil de parametri, există trei definiții de macro (macro) va_start, va_arg, va_end, aflate în fișierul antet stdarg.h. Aceste macrocomenzi indică faptul că o funcție dezvoltată de utilizator are un număr de argumente necesare urmate de un număr variabil de argumente opționale. Argumentele necesare sunt accesibile prin numele lor, la fel ca atunci când apelați o funcție obișnuită. Pentru a prelua argumente opționale, utilizați macrocomenzile va_start, va_arg, va_end în următoarea ordine.

Macrocomanda va_start este concepută pentru a seta argumentul arg_ptr la începutul listei de parametri opționali și arată ca o funcție cu doi parametri:

void va_start(arg_ptr,prav_param);

Parametrul prav_param trebuie să fie ultimul parametru necesar al funcției apelate, iar pointerul arg_prt trebuie declarat cu o predefinire în lista de variabile de tip va_list sub forma:

va_list arg_ptr;

Macrocomanda va_start trebuie utilizată înainte de prima utilizare a macrocomenzii va_arg.

Macro-ul va_arg oferă acces la parametrul curent al funcției apelate și arată, de asemenea, ca o funcție cu doi parametri

type_arg va_arg(arg_ptr,type);

Această macrocomandă preia valoarea tipului la adresa specificată de pointerul arg_ptr, incrementează valoarea pointerului arg_ptr cu lungimea parametrului utilizat (lungimea tipului) și astfel parametrul arg_ptr va indica următorul parametru al funcției apelate . Macro-ul va_arg este folosit de câte ori este necesar pentru a prelua toți parametrii funcției apelate.

Macro-ul va_end este utilizat după ce toți parametrii funcției au fost procesați și setează indicatorul opțional pentru lista de parametri la NULL.

Să luăm în considerare utilizarea acestor macrocomenzi pentru a procesa parametrii unei funcții care calculează valoarea medie a unei secvențe arbitrare de numere întregi. Deoarece funcția are un număr variabil de parametri, vom considera că sfârșitul listei este o valoare egală cu -1. Deoarece lista trebuie să aibă cel puțin un element, funcția va avea un parametru necesar.

#include int main() ( int n; int sred_znach(int,...); n=sred_znach(2,3,4,-1); /* apel cu patru parametri */ printf("n=%d" ,n); n=sred_znach(5,6,7,8,9,-1); ,...); ( int i=0, j=0, sum=0; va_list uk_arg; va_start(uk_arg,x); /* setarea indicatorului uk_arg la */ /* primul parametru opțional */ dacă (x!=-1) sum= x ; /* verifica lista goala */ else return (0 while ((i=va_arg(uk_arg,int))!=-1) /* selectand urmatoarea */ ( /* parametrul si verificand */ sum+); = i; /* la sfârșitul listei */ j++ ) va_end(uk_arg) */ return (sum/j);

1.5.3. Transmiterea parametrilor la funcția principală

Funcția principală, de la care începe execuția programului SI, poate fi definită cu parametri care sunt trecuți din mediul extern, de exemplu, din linia de comandă. Mediul extern are propriile reguli de reprezentare a datelor sau, mai degrabă, toate datele sunt prezentate sub formă de șiruri de caractere. Pentru a trece aceste șiruri de caractere la funcția principală, se folosesc doi parametri, primul parametru este folosit pentru a transmite numărul de șiruri care urmează să fie transmise, al doilea este folosit pentru a transmite șirurile în sine. Numele comune (dar nu obligatorii) pentru acești parametri sunt argc și argv. Parametrul argc este de tip int, valoarea lui este formată din analiza liniei de comandă și este egală cu numărul de cuvinte de pe linia de comandă, inclusiv numele programului apelat (un cuvânt este orice text care nu conține spațiu caracter). Parametrul argv este o matrice de pointeri către șiruri de caractere, fiecare conținând un cuvânt din linia de comandă. Dacă un cuvânt trebuie să conțină un caracter spațiu, acesta trebuie să fie cuprins între ghilimele atunci când îl scrieți în linia de comandă.

Funcția principală poate avea și un al treilea parametru, care se numește de obicei argp, și care servește la transferul parametrilor sistemului de operare (mediu) în care se execută programul SI către funcția principală.

Antetul funcției principale arată astfel:

int main (int argc, char *argv, char *argp)

Dacă, de exemplu, linia de comandă a programului SI arată astfel:

A:\>cprog lucrând „Programul C” 1

atunci argumentele argc, argv, argp sunt reprezentate în memorie așa cum se arată în diagrama din Fig. 1.

Argc [ 4 ] argv --> --> --> --> --> argp --> --> --> --> --> Fig.1. Dispunerea parametrilor liniei de comandă

Sistemul de operare acceptă transmiterea de valori pentru parametrii argc, argv, argp și este responsabilitatea utilizatorului să transmită și să utilizeze argumentele reale către funcția principală.

Următorul exemplu este un program care imprimă argumentele reale transmise funcției principale din sistemul de operare și parametrii sistemului de operare.

Exemplu: int main (int argc, char *argv, char *argp) ( int i=0; printf ("\n Nume program %s", argv); for (i=1; i>=argc; i++) printf ("\n argumentul %d este %s", argv[i]); ; ) întoarcere (0);

Parametrii sistemului de operare pot fi accesați și folosind funcția de bibliotecă geteuv prototipul său arată astfel:

char *geteuv (const char *varname);

Argumentul acestei funcții specifică numele parametrului de mediu, un pointer către a cărui valoare va fi returnat de funcția geteuv. Dacă parametrul specificat nu este definit în prezent în mediu, valoarea returnată este NULL.

Folosind indicatorul obținut de funcția geteuv, puteți citi doar valoarea parametrului sistemului de operare, dar nu o puteți modifica. Funcția puteuv este utilizată pentru a modifica valoarea unui parametru de sistem.

Compilatorul limbajului SI construiește un program SI în așa fel încât o anumită inițializare să fie efectuată la începutul programului, incluzând, printre altele, procesarea argumentelor transmise funcției principale și transmiterea acesteia a valorilor parametrilor de mediu. Aceste acțiuni sunt efectuate de funcțiile de bibliotecă _setargv și _seteuv, care sunt întotdeauna plasate înaintea funcției principale de către compilator.

Dacă programul SI nu utilizează transmiterea de argumente și valori ale parametrilor sistemului de operare, atunci este recomandabil să interziceți utilizarea funcțiilor bibliotecii _setargv și _seteuv prin plasarea în programul SI înaintea funcțiilor principale cu aceleași nume. , dar care nu efectuează nicio acțiune (stubs). Începutul programului în acest caz va arăta astfel:

Setargv() ( return ; /* funcție goală */ ) -seteuv() ( return ; /* funcție goală */ ) int main() ( /* funcție principală fără argumente */ ... ... renurn (0) )

În programul de mai sus, la apelarea funcțiilor de bibliotecă _setargv și _seteuv, vor fi folosite funcțiile plasate în program de către utilizator și nu vor efectua nicio acțiune. Acest lucru va reduce semnificativ dimensiunea fișierului exe rezultat.

[

Vă rugăm să suspendați AdBlock pe acest site.

Deci, de ce avem nevoie de funcții personalizate? Sunt necesare funcții definite de utilizator pentru a facilita scrierea programelor de către programatori.

Amintiți-vă, am vorbit despre paradigmele de programare, mai precis despre programarea structurată. Ideea principală a fost că orice program poate fi scris folosind doar trei constructe de bază: follow, condition și loop. Acum vom adăuga încă una la aceste structuri - „subrutine” - și vom obține o nouă paradigmă programare procedurală".

Singura diferență este că vom scrie bucăți individuale ale programului nostru principal (în special, cele repetate) sub formă de funcții separate (subrutine, proceduri) și le vom apela după cum este necesar. În esență, programul va descrie acum interacțiunea diferitelor funcții.

Deci, în acest tutorial vom discuta în detaliu modul în care funcțiile sunt construite intern. De asemenea, vom învăța cum să ne creăm propriile funcții personalizate.

Cum funcționează funcțiile

Să ne amintim informațiile din prima lecție. Toate funcțiile, inclusiv cele scrise de utilizator, sunt aranjate într-un mod similar. Acestea au două părți principale: antetul funcției și corpul funcției.

Listarea 1.

Int main(void)( // antetul funcției // corpul funcției este scris între acolade)

Totul este clar cu corpul funcției: descrie algoritmul funcției. Să ne uităm la titlu. Este format din trei părți obligatorii:

  • tip de returnare;
  • numele funcției;
  • argumente ale funcției.

Mai întâi, tipul returnat este scris, de exemplu, int, ca în funcția principală. Dacă o funcție nu ar trebui să returneze nicio valoare programului, atunci cuvântul cheie void este scris în acest loc. S-ar părea că, deoarece funcția nu returnează nimic, atunci nu este nevoie să scrieți nimic. Anterior, apropo, acest lucru se făcea în limbajul C, dar apoi l-au adăugat pentru uniformitate. În zilele noastre, compilatoarele moderne vor emite avertismente/erori dacă nu specificați un tip de returnare.
În unele limbaje de programare, funcțiile care nu returnează nicio valoare sunt numite proceduri (de exemplu, Pascal). Mai mult, există sintaxe diferite pentru crearea de funcții și proceduri. Nu există o astfel de discriminare în limbajul C.

Numele funcției este scris după tipul returnat. Ei bine, după nume sunt indicate tipurile și numărul de argumente care sunt transmise funcției.

Să ne uităm la titlurile funcțiilor cu care suntem deja familiarizați.

Lista 2.

// o funcție numită srand care ia un întreg nu returnează nimic void srand(int) // o funcție numită sqrt care ia un float real returnează un float float sqrt(float) // o funcție numită rand care nu primește argumente, returnează un număr întreg int rand(void) //o funcție numită pow care ia două argumente de tip double, returnează un număr real de tip double double pow(double, double)

Cum să-ți creezi propria funcție

Pentru a vă crea propria funcție, trebuie să o descrieți complet. Aici se aplică regula generală: înainte de a o utiliza, declarați și descrieți cum ar trebui să funcționeze. Pentru a face acest lucru, să revenim la diagrama structurii programului C pe care am avut-o chiar în prima lecție. Să marchem pe el locurile în care pot fi descrise funcțiile.

Fig.1 Clarificarea structurii programului. Declaratie de functii.

După cum puteți vedea, există două locuri unde se poate face acest lucru.

Să ne uităm la un exemplu care ilustrează crearea unei funcții personalizate pentru a calcula maximum două numere.

Lista 3.

#include // declară o funcție personalizată numită max_num // intrare: doi parametri întregi denumiți a și b // ieșire: maximul dintre cele două argumente int max_num(int a, int b)( int max = b; if (a > b) max = a; return max; x ,y); printf("max(%d,%d) = %d\n",x,y,m);

Permiteți-mi să descriu în detaliu cum va funcționa acest program. Corpul funcției principale este executat. Sunt create variabilele întregi x, y și m. Variabilele x și y sunt citite de la tastatură. Să presupunem că am introdus 3 5, apoi x = 3, y = 5. Toate acestea ar trebui să vă fie clare. Acum linia următoare

Lista 4.

M = max_num(x,y);

Variabila m trebuie atribuită la ceea ce se află în dreapta semnului =. Acolo avem numele funcției pe care am creat-o noi înșine. Calculatorul caută declarația și descrierea acestei funcții. Este situat deasupra. Conform acestei declarații, această funcție trebuie să accepte două valori întregi. În cazul nostru, acestea sunt valorile scrise în variabilele x și y. Acestea. numerele 3 și 5. Vă rugăm să rețineți că nu variabilele x și y în sine sunt transmise funcției, ci doar valorile (două numere) care sunt stocate în ele. Ceea ce este de fapt transmis unei funcții atunci când este apelată într-un program se numește parametrii actuali ai funcției.

Acum funcția max_num începe să se execute. Primul pas este de a crea o variabilă temporară separată pentru fiecare parametru descris în antetul funcției. În cazul nostru, sunt create două variabile întregi numite a și b. Aceste variabile li se atribuie valorile parametrilor actuali. Parametrii înșiși, descriși în antetul funcției, sunt numiți parametri formali. Deci, parametrilor formali a și b li se atribuie valorile parametrilor actuali 3 și, respectiv, 5. Acum a = 3, b = 5. Mai departe în interiorul funcției putem lucra cu aceste variabile ca și cum ar fi variabile obișnuite.

O variabilă întreagă numită max este creată și i se atribuie valoarea b. În continuare, se verifică condiția a > b. Dacă este adevărat, atunci valoarea din variabila max ar trebui înlocuită cu un .

Urmează instrucțiunea return, care returnează programului apelant (funcția principală) valoarea scrisă în variabila max, adică. 5 . După care variabilele a, b și max sunt eliminate din memorie. Și ne întoarcem la linie

Lista 5.

M = max_num(x,y);

Funcția max_num a returnat valoarea 5, ceea ce înseamnă că acum există 5 scris în dreapta semnului =. Această valoare este scrisă în variabila m. Apoi linia este afișată pe ecran și programul se termină.

Citiți din nou cu atenție ultimele 4 paragrafe pentru a înțelege pe deplin cum funcționează programul.

Între timp, vă voi spune de ce este necesar blocul inferior de descrieri de funcții. Imaginează-ți că ai scris 20 de funcții mici în programul tău. Și toate sunt descrise înainte de funcția principală. Nu este foarte convenabil să ajungi la programul principal atât de mult timp. Pentru a rezolva această problemă, funcțiile pot fi descrise într-un bloc inferior.

Dar nu va fi posibil să transferați pur și simplu întregul cod de funcție acolo, deoarece atunci regula va fi încălcată: înainte de a folosi ceva, trebuie să-l declari. Pentru a evita această problemă, trebuie să utilizați un prototip de funcție.

Prototipul funcției repetă complet antetul funcției, urmat de ; . După ce am specificat prototipul în blocul superior, în cel de jos putem deja descrie complet funcția. Pentru exemplul de mai sus ar putea arăta astfel:

Lista 6.

#include int max_num(int, int); int main(void) ( int x =0, y = 0; int m = 0; scanf("%d %d", &x, &y); m = max_num(x,y); printf("max(%d); ,%d) = %d\n",x,y,m); return 0; ) int max_num(int a, int b)( int max = b; if (a > b) max = a; return max; )

Totul este foarte simplu. Vă rugăm să rețineți că prototipul funcției nu trebuie să specifice numele parametrilor formali, este suficient să indicați pur și simplu tipurile acestora. În exemplul de mai sus, exact asta am făcut.

Este timpul să aflați despre caracteristici. Aveți deja o idee despre cum să utilizați funcția principală - acesta este un alt exemplu de funcție. În general, funcțiile sunt blocuri de cod separate, independente, care execută o serie de comenzi predefinite. În limbajul de programare C, puteți utiliza atât funcțiile încorporate ale diferitelor biblioteci, cât și funcțiile pe care le-ați creat singur, adică propriile funcții.

Funcțiile pe care le vom crea singuri necesită de obicei o declarație prototip. Un prototip oferă informații de bază despre structura unei funcții: îi spune compilatorului ce valoare returnează funcția, cum va fi apelată funcția și ce argumente pot fi transmise funcției. Când spun că o funcție returnează o valoare, vreau să spun că la sfârșitul funcționării sale funcția va returna o valoare care poate fi plasată într-o variabilă. De exemplu, o variabilă poate fi inițializată cu valoarea pe care o va returna funcția:

#include // conectarea antetului cu funcția rand rand() int randomNumber = rand(); // funcția standard de generare a numerelor aleatorii

Greșeala este că mulți programatori începători cred că valoarea din variabila randomNumber se va schimba aleatoriu de fiecare dată, nu este așa. Acesta va fi inițializat cu o valoare aleatorie o dată, când funcția este apelată, dar nu de fiecare dată când programul este lansat.

Să ne uităm la formatul general pentru un prototip de funcție:

ReturnedDataType functionName(dataType par1, ..., dataType parN);

unde returnedDataType este tipul de date returnat de funcție;
functionName — numele funcției
dataType - tipul de date al parametrului funcției, acesta este același tip de date ca atunci când se declară variabila
par1 ... parN — parametrii funcției.

O funcție poate avea mai mult de un parametru sau deloc, caz în care parantezele sunt goale. Funcțiile care nu returnează o valoare au un tip de date pentru valoarea returnată de void. Să ne uităm la prototipul funcției:

Int mult(int x, int y);

Acest prototip îi spune compilatorului că funcția ia două argumente ca numere întregi și că funcția va returna o valoare întreagă când se finalizează. Asigurați-vă că adăugați un punct și virgulă la sfârșitul prototipului. Fără acest simbol, compilatorul va crede probabil că încercați să scrieți definiții reale ale funcției.

Când programatorul definește de fapt o funcție, va începe cu un prototip, dar nu este nevoie să adăugați un punct și virgulă. Imediat după prototip există un bloc cu acolade și codul pe care funcția îl va executa. De exemplu, cum ați scrie în mod normal cod în interiorul funcției principale. Oricare dintre argumentele transmise funcției poate fi folosit ca și cum ar fi fost declarate ca variabile obișnuite. În cele din urmă, definiția funcției se termină cu o acoladă de închidere, fără punct și virgulă.

Să ne uităm la un exemplu de declarare și utilizare a unei funcții în limbajul de programare C:

#include int multiplicare(int num1, int num2); //prototipul funcției int main() ( int num1; int num2; printf("Introduceți două numere de înmulțit: "); scanf("%d", &num1); scanf("%d", &num2); printf(" Rezultatul înmulțirii %d\n", multiplicare(num1, num2)); // apelul funcției getchar(); return 0; ) int multiplication(int num1, int num2) // definiția funcției ( return num1 * num2; )

Acest program începe prin includerea unui singur fișier antet, pe linia 1. Următoarea linie este un prototip pentru funcția de multiplicare. Rețineți că există un punct și virgulă la sfârșitul declarației prototipului! Funcția principală returnează un număr întreg, pe linia 16. Pentru a se conforma standardului, funcția principală trebuie să returneze întotdeauna o valoare. Nu ar trebui să aveți nicio problemă în a înțelege intrarea și ieșirea valorilor în funcții dacă ați studiat cu atenție lecțiile anterioare.

Observați cum funcția multiplication() ia de fapt o valoare. Ce se întâmplă cu adevărat? Dar în realitate funcționează așa: funcția de înmulțire ia două valori întregi, le înmulțește și returnează produsul. Rezultatul acestui program va fi exact același ca și cum am face asta:

Printf("Rezultatul înmulțirii %d\n", num1 * num2);

Funcția multiplication() este de fapt definită sub funcția principală. Și deoarece prototipul acestei funcții este declarat deasupra funcției principale, compilatorul nu va arunca o eroare atunci când apelează funcția multiplication() în main(). Atâta timp cât prototipul este prezent, funcția poate fi utilizată chiar dacă nu există o definiție reală. Cu toate acestea, o funcție nu poate fi apelată înainte ca funcția să fi fost definită.

Definirea prototipurilor de funcții este necesară numai dacă definiția reală a funcției în sine va fi localizată după funcția principală. Dacă funcția este definită înaintea funcției principale, atunci nu este necesar un prototip.

Cuvântul cheie return este folosit pentru a forța o funcție să returneze o valoare. Rețineți că este foarte posibil să declarați funcții care nu returnează nicio valoare. Dacă o funcție returnează o valoare de tip void , atunci funcția nu are de fapt o valoare returnată. Cu alte cuvinte, pentru o funcție care returnează o valoare de tip void , instrucțiunea return; este legal, dar de obicei este redundant. (Deși poate fi folosit pentru a părăsi o funcție în caz de urgență.)

Cel mai important lucru este să înțelegem de ce avem nevoie de o funcție? Funcțiile au multe utilizări. De exemplu, un program are un bloc de cod care trebuie executat în diferite locuri din program de aproximativ patruzeci de ori. Adică declari o funcție o dată și o apelezi acolo unde este necesar, fără a duplica codul, ceea ce va economisi mult spațiu, ceea ce la rândul său va face programul mai lizibil. În plus, având o singură copie a codului, este mai ușor să faceți modificări.

Un alt motiv pentru a utiliza funcțiile este separarea întregului cod în părți logice separate. În acest fel, sarcinile complexe sunt împărțite în altele mai simple, acest lucru este foarte util la menținerea codului, structura unui astfel de program va fi mult mai ușor de înțeles.

P.S.: dacă aveți nevoie de un server bun, atunci puteți folosi închirierea de server la Moscova. De asemenea, puteți utiliza și alte servicii furnizate pe site-ul it-express.ru: implementare de servere tolerante la erori, sisteme de stocare a datelor etc.

În limbajul C, toate programele sunt tratate ca funcții. De obicei, programele în acest limbaj constau dintr-un număr mare de funcții mici. Pentru fiecare dintre funcțiile utilizate este furnizată o descriere și definiție a funcției (Descrierea funcției oferă informații despre tipul funcției și ordinea parametrilor. La definirea unei funcții, instrucțiunile specifice care trebuie executate sunt indicate). Funcțiile trebuie să fie de același tip cu valorile pe care le returnează ca rezultate. În mod implicit, se presupune că funcțiile sunt de tip int. Dacă o funcție are un alt tip, aceasta trebuie specificată atât în ​​programul apelant, cât și în definiția funcției în sine.

Luați în considerare descrierea funcțiilor: puteți utiliza două stiluri diferite de descriere a funcțiilor (stil clasic și modern). În primul caz, formatul descrierii funcției este următorul:

tip function_name();

Această specificație descrie numele funcției și tipul de returnare.

Stilul modern este folosit în construcțiile ANSI C extinse. Când descriem funcții în această versiune de C, sunt folosite instrumente speciale de limbaj, cunoscute sub numele de „prototip de funcție”. Descrierea unei funcții folosind prototipul acesteia conține informații suplimentare despre parametrii acesteia:

tastați nume_funcție (par_inf1, par_inf2, ...);

unde parametrul par_infi este informații despre numele și tipul parametrilor formali.

Definiția unei funcții. La fel ca în descrierea funcției, atunci când definiți funcții puteți utiliza două stiluri - clasic și modern. Formatul clasic pentru definirea funcțiilor este următorul:

tastați nume_funcție (numele parametrilor)

determinarea parametrilor;

descrieri locale;

operatori;

Formatul de descriere a stilului modern implică definirea parametrilor funcției în paranteze după numele funcției:

tastați nume_funcție (par_inf, par_inf, ...)

unde definiția parametrului par_inf conține informații despre parametrul transmis: tip și identificator.

Trebuie remarcat faptul că o serie de descrieri (constante, tipuri de date, variabile) conținute într-o funcție (cu excepția funcției principale main0) sunt definite numai în cadrul acestei funcții. Prin urmare, limbajul C nu acceptă imbricarea funcțiilor, adică o funcție nu poate fi declarată în interiorul unei alte funcții.

Funcțiile pot fi plasate într-o ordine diferită într-un program și sunt considerate globale pentru întregul program, inclusiv funcțiile încorporate descrise înainte de utilizare.

O funcție este apelată de numele funcției, cu argumentele reale în paranteze.

Rezultatul funcției este returnat folosind instrucțiunea return. Forma generala:

Return(expresie);

Instrucțiunea încheie execuția funcției și transmite controlul următoarei instrucțiuni din funcția de apelare. Acest lucru se întâmplă chiar dacă instrucțiunea return nu este ultima instrucțiune din corpul funcției.

Puteți utiliza declarația de returnare în formularul:

Utilizarea lui duce la faptul că funcția în care este conținută își finalizează execuția și controlul (este transferat) este returnat funcției de apelare. Deoarece acest operator nu are o expresie între paranteze, nicio valoare nu este transmisă funcției.

(floaty,x,mult(); /* descriere în programul apelant */

floatmult(v,k) /* descriere în definiția funcției */

pentru (res=0,0; k>0; k--)

return(res); ) /* returnează o valoare flotantă*/

Cu instrucțiunea return, puteți transmite o singură valoare programului apelant. Dacă trebuie să treceți două valori, trebuie să utilizați pointeri.

O definiție a funcției specifică numele, parametrii formali și corpul funcției. De asemenea, poate specifica tipul de returnare a funcției și clasa de stocare. Sintaxa pentru definirea unei funcții este:

[<спецификация КП>][<спецификация типа>]<описатель>([<список параметров>]) [<объявление параметров>] <тело функции>

Specificația clasei de memorie<спец. КП>specifică clasa de memorie a funcției.

<спец. типа>împreună cu descriptorul, determină tipul de returnare și numele funcției.<Список параметров>este o listă (posibil goală) de nume de parametri formali ale căror valori sunt transmise funcției atunci când sunt apelate.<Объявления параметров>definiți identificatori și tipuri de parametri formali.<Тело функции>-o instrucțiune compusă care conține declarații de variabile locale și operatori.

Design modern:

[<спецификация КП>][<спецификация типа>]<описатель>([<список объявлений параметров>])<тело функции>

Declarație de funcție: formă clasică:

[<спецификация КП>][<спецификация типа>]<описатель>([<список типов аргументов>]);

O declarație de funcție specifică numele funcției, tipul ei returnat și, eventual, tipurile și numărul argumentelor sale.

Stilul modern de descriere (declararea prototipurilor). În lista de tipuri de argumente, prototipul poate conține și identificatorii acestor argumente.

float f1 (float a, float b)

c=(2*pow(a,3)+sin a)/pow(a+b,4);

( float x,y,s=0;

printf("\nIntroduceți x, y");

scanf ("%f %f", &x, &y);

s=f1(5,6, y)+f1(2*x-1, x*y);

printf(“\n s=%6.2f ”,s);

Operațiuni de adresare. C suportă două operații speciale de adresă: operatorul de adresă (&) și operatorul de adresă (*). Operația & returnează adresa unei variabile date. Dacă sum este o variabilă de tip int, atunci &sum este adresa acelei variabile.

Indicatori. Un pointer este o variabilă care deține adresa unor date. În general, un pointer este o reprezentare simbolică a unei adrese. &sum în acest caz înseamnă „indicator către suma variabilă”. Adresa reală este un număr, iar reprezentarea simbolică a adresei &sum este o constantă pointer. T.arr. Adresa celulei de memorie alocată variabilei suma nu se modifică în timpul execuției programului.

Limbajul C are, de asemenea, variabile de tip pointer. Valoarea unei variabile pointer este adresa unei anumite valori. Lăsați indicatorul să fie desemnat de identificatorul ptr, apoi următoarea instrucțiune atribuie suma adresei variabilei ptr:ptr=&sum. În acest caz, se spune că ptr „indică spre” sumă. Deci, ptr este o variabilă, &sum este o constantă. Variabila ptr poate indica un alt obiect:

Valoarea lui ptr este adresa variabilei max. Să luăm în considerare operația de adresare prin adresă (*) sau operațiunea de adresare indirectă. Să presupunem că variabila ptr conține o referință la variabila max. Apoi, pentru a accesa valoarea acestei variabile, puteți folosi operația cu adresa (*). Pentru a determina valoarea indicată de ptr, scriem următoarea afirmație:

Res=*ptr; (Ultimele două afirmații luate împreună sunt echivalente cu următoarele: Res=max;)

Utilizarea operației de obținere a unei adrese și a adresei indirecte se dovedește a fi departe de a fi o cale directă către rezultat, de unde și apariția cuvântului „indirect” în numele operației.).

Operația (*) - când acest semn este urmat de un pointer către o variabilă, rezultatul operației este valoarea plasată în celula cu adresa specificată.

Descrierea indicatorilor. Când descrieți variabile de tip „pointer”, este necesar să indicați la ce tip de variabilă se referă acest indicator. Deoarece Variabile de diferite tipuri ocupă un număr diferit de locații, în timp ce unele operațiuni legate de pointer necesită cunoașterea cantității de memorie alocată. Exemple de descrieri corecte de indicator:

Folosind pointeri pentru a comunica între funcții. Să ne uităm la un exemplu de utilizare a indicatorilor pentru a stabili conexiuni între funcții. În acest exemplu, pointerii sunt utilizați pentru a schimba valori variabile.

( int x=5, y=10;

printf (“x=%d y=%d\n”, x, y);

schimbare(&x, &y); /*trimite adrese de funcții*/

printf (“x=%d y=%d\n”, x, y); )

int*u, *v; /*u și v sunt indicatori*/

temp=*u; /*temp i se atribuie valoarea indicată de u*/

Această funcție modifică valorile variabilelor x și y. Transmițând adresele variabilelor x și y funcției, i-am dat posibilitatea de a le accesa. Folosind pointerii și operația (*), funcția a putut să recupereze valorile plasate în locațiile de memorie corespunzătoare și să le schimbe.

Principaldacăteratură: 1 baza, 2 baze

AdiţionalliteraturăA: 10 suplimentar

Întrebări de control:

1. Numele parametrilor formali și actuali ai subrutinelor pot fi aceleași?

2. Care este diferența dintre descrierea unei proceduri și a unei funcții?

3. Ce parametri se numesc formali si care se numesc actuali?

4. Ce stiluri de descriere și definire a funcțiilor există?

5. Care este operatorul pentru returnarea rezultatului unei funcții?