Clasa a VI-a lecția 31 - 31 mai 2016
Lecție
Funcții în limbajul C
Funcțiile permit programelor complicate să fie parcelate în blocuri mici, fiecare din ele fiind mai ușor de scris, citit și modificat (întreținut). Am întîlnit deja funcția main() și am folosit funcții de intrare ieșire, precum și funcții matematice din bibliotecile standard. Vom vedea în continuare cum putem să scriem propriile noastre funcții.
De ce funcții
- Pentru a nu repeta cod.
- Pentru organizare, citibilitate, ușurinta înțelegerii codului și întreținerea codului.
- Recursivitate, precum vom vedea anul următor.
Cate tipuri de funcții exista in C
- Clasificare dupa valoarea pe care o returneaza
- functii procedurale - de tip void
- functii cu valoare de return
Definitia functiilor si apelul lor
Pentru a utiliza functii definite de noi, trebuie sa definim functia si apoi sa o apelam.
Definitia Sintaxa (simplificare)
<tip returnat> <nume funcție>(<tip1> <var1>, <tip2> <var2>, ..., <tipn> <varn>) { ... declarații variabile ... ... cod funcție ... return <valoare return>; // dacă tipul returnat nu este 'void' }
Obs:
- Tipul returnat trebuie sa coincida cu valoare ruturn'
- Daca o functie este de tip void, nu vom avea deci o valoare de return, deci nici instructiunea return in corpul functiei.
Apelul Sintaxa (simplificare)
<nume funcție>( <param1>, <param2>, ..., <paramn>);
Unde <Param1>...<paramn> pot fi variabile, constante, expresii si trebuie sa coincida ca tip cu <var1>...<varn>
Exemple
#include <stdio.h>
#include <stdlib.h>
//definitia unei functii procedurale ( void )
void inc1( int a ) {
a++;
}
//functie cu valoare de return
int inc2( int a ) {
a++;
return a;
}
int main() {
int x = 0;
inc1( x ); // apelul functiei procedurale
printf( "%d\n", x );
printf( "%d", inc2( x ) ); // apelul functiei cu valoare de return
return 0;
}
Parametri și valoarea returnată
- Parametri, valoare returnată
- Transmisia parametrilor se face numai prin copiere, pe stiva sistem
- Ce afișează următorul program:
void inc( int a ) {
a++;
}
int main() {
int x = 0;
inc( x );
printf( "%d", x );
return 0;
}
- Valoarea returnată, prin copiere pe stiva sistem
- Cum modificam parametrii, operatorii & si &; ar fi bine să evitați, deocamdată. Exemplu: functia swap.
- Transmisie vectori ca parametri; vom transmite și lungimea; vectorul și lungimea lui sînt componente inseparabile ale tipului de date abstract.
- Ce se întîmplă dacă modificăm elementele vectorului în funcție?
- Ce se întîmplă dacă modificăm lungimea vectorului în funcție?
- Declarații de variabile și vizibilitatea acestora. Așezarea lor pe stivă.
- Conversia de tip cînd chemăm funcția cu alte tipuri decît cele declarate.
Apelul
O funcție este apelată astfel: numeFunctie( valoare1, valoare2, ..., valoaren );
Exemple
Scrieți funcții care să rezolve:
- minim, maxim a două numere
- inversare vector
- inserare element în vector
- sortare cu funcție de comparație (scrieți funcția de comparare separat)
- citire întreg fără semn din fișier folosind doar fgetc()
Funcțiile și programarea structurată
Instrucțiunea return este echivalentul unui salt la finalul funcției. Programare evident nestructurată. De aceea, deși limbajul C ne permite, nu o vom folosi decît la finalul funcției, ca ultima instrucțiune. C este un limbaj vechi. Limbaje gen Pascal au rezolvat problema nestructurării eliminînd instrucțiunea return.
Cînd scriem funcții?
Bun, am învățat funcții. Dar cum iau decizia să scriu o funcție sau nu?
- Atunci cînd nu putem evita repetiția de cod prin alte mijloace (factorizare, bucle, etc)
- Atunci cînd programul devine prea lung pentru a fi citit ușor, de obicei undeva la 80-100 de linii. Ca regulă generală o funcție ar fi bine să aibă pînă în 100 de linii, dar desigur regula nu este bătută în cuie.
- Atunci cînd simțim că o bucată semnificativă de cod are o coeziune, reprezintă un tot unitar, o putem transforma în funcție.
- Atunci cînd scriem o bucată de cod care execută un calcul general, gen sortare, sau citirea unui întreg, atunci o putem scrie ca funcție pentru a o refolosi în viitor. Vom vedea că aceasta este baza de pornire a bibliotecilor de funcții.
- Nu este bine să "rupem" artificial programul de dragul funcțiilor. Dacă tot programul ar avea 40 de linii, introducerea unor funcții i-ar scădea lizibilitatea.
- Pe cazul general, la olimpiade și pentru programele mici care rezolvă probleme de concurs încercați să evitați funcțiile inutile, doar de dragul artei. Cînd tot programul, scris elegant, ar avea 80 de linii este destul de greu să justifici introducerea unor funcții.
Cum denumim funcțiile?
O funcție trebuie denumită cît mai sugestiv. Funcții denumite citire() sau solve() cu am văzut la colegii voștri mai mari fac codul mai necitibil decît dacă ele nu existau. Ele sînt echivalentul variabilelor denumite contor sau stegulet. Așa cum stegulețul ar fi bine să se numească terminat sau fara_zero, la fel și funcțiile trebuie denumite sugestiv. Pentru cele două funcții de mai sus nume bune ar fi citesteVectorInaltimi() și calculSumePartiale(). Observați că primul cuvînt din denumire începe cu literă mică, celelalte cu literă mare. Aceasta este o convenție de codare.
Considerente de viteză
Atunci cînd funcția poate fi chemată de un număr mare de ori calculatorul pierde un timp semnificativ în apelul de funcție. Un exemplu tipic ar fi cînd funcția este chemată într-o buclă care se execută de un milion de ori. Ce putem face?
- Evitați astfel de funcții, dacă nu dăunează eleganței și citibilității programului: introduceți codul funcției în loc de apel.
- Dacă totuși trebuie să folosiți o funcție aveți opțiunea să o declarați inline. Aceasta înseamnă că compilatorul nu va genera cod care să cheme funcția ci va înlocui apelul cu chiar corpul funcției, peste tot unde apare el. Este ca și cum funcția nu ar exista, păstrînd însă citibilitatea programului (nu și scurtimea executabilului generat, din păcate).
Temă
Încercați să folosiți funcții în rezolvarea problemelor de la temă. Mai exact, la problema ținta încercați să scrieți o funcție care să primească ca parametrii numărul n, linia și coloana și să returneze elementul aflat în matrice la acea linie și coloană. În felul acesta nu veți avea nevoie să stocați matricea. Încercați să nu repetați cod, folosind funcții.
Rezolvări aici [1]
Începeți să lucrați la jocul de concurs, Pah-Tum.