Noi te platim pentru timpul acordat , o postare , like , vizualizare subiect , sau creare subiect , insemna castig.
Suntem comunitatea unica din Romania care plateste pentru efortul depus . Ideile ,opiniile tale conteaza si sunt platite doar la noi.

Funcţiile şi structura unui program

Funcţiile şi structura unui program

Solus

Membru
Staff member
Fondator BitArena
Moderator
Utilizator
Joined
Jul 6, 2018
Messages
523
Reaction score
94
Points
26
Location
Bucuresti
Website
www.bitarena.eu

Reputation:

Funcţiile sînt elementele de bază ale unui program scris în C; orice program, de orice dimensiune, constă din una sau mai multe funcţii, care specifică operaţiile care trebuie efectuate.
O funcţie oferă un mod convenabil de încapsulare a anumitor calcule într-o cutie neagră care poate fi utilizată apoi fără a avea grija conţinutului ei. Funcţiile sînt într-adevăr singurul mod de a face faţă complexităţii programelor mari. Funcţiile permit desfacerea programelor mari în unele mici şi dau utilizatorului posibilitatea de a dezvolta programe, folosind ceea ce alţii au făcut deja în loc să o ia de la început.
Limbajul C a fost conceput să permită definirea de funcţii eficiente şi uşor de mînuit. În general e bine să concepem programe constituite din mai multe funcţii mici decît din puţine funcţii de dimensiuni mari. Un program poate fi împărţit în mai multe fişiere sursă în mod convenabil, iar fişierele sursă pot fi compilate separat.
Mai precis, un program C constă dintr-o secvenţă de definiţii externe. Acestea sînt definiţii de funcţii şi de date. Sintaxa definiţiilor externe este aceeaşi ca şi a tuturor declaraţiilor.

Definiţia funcţiilor

Sintaxa definiţiei unei funcţii este următoarea:
Definiţia-funcţiei:
tip-funcţie<opt> nume-funcţie(lista-parametri) corp-funcţie
Lista-parametri:
declaraţie-parametru
declaraţie-parametru, lista-parametri
Corpul-funcţiei:
instrucţiune-compusă

Dintre specificatorii de clasă de memorie numai extern şi static sînt admişi. Un declarator de funcţie este similar cu un declarator pentru „funcţie care returnează ...” cu excepţia că el listează parametrii formali ai funcţiei care se defineşte.
După cum se observă, diferitele părţi pot să lipsească; o funcţie minimă este:
dummy() {}
funcţia care nu face nimic. Această funcţie poate fi utilă în programe, ţinînd locul unei alte funcţii în dezvoltarea ulterioară a programului.
Numele funcţiei poate fi precedat de un tip, dacă funcţia returnează altceva decît o valoare întreagă (vezi secţiunea 7.2).
Numele funcţiei poate fi de asemenea precedat de clasa de memorie extern sau static. Dacă nici un specificator de clasă de memorie nu este prezent, atunci funcţia este automat declarată externă, deoarece în C nu se admite ca o funcţie să fie definită în interiorul altei funcţii.
Declaraţia unei funcţii se face implicit la apariţia ei. Se interpretează ca funcţie orice identificator nedeclarat anterior şi urmat de o paranteză ’(’. Pentru a evita surprize neplăcute datorită neconcordanţei dintre tipurile de parametri această practică nu este recomandată.
Dăm mai jos un exemplu de funcţie complet definită:

int max(int a, int b, int c) {
int m;
m = (a>b) ? a : b;
return (m>c) ? m : c;
}

Această funcţie determină maximul dintre 3 numere date:
- int este un specificator de tip care indică faptul că funcţia max returnează o valoare întreagă;
- max(int a, int b, int c) este declaraţia funcţiei şi a parametrilor formali;
- { . . . } este corpul funcţiei.

Să ilustrăm mecanismul definirii unei funcţii scriind funcţia putere power(m,n) care ridică un întreg m la o putere întreagă pozitivă n. Astfel valoarea lui power(2,5) este 32. Această funcţie desigur nu este completă, deoarece calculează numai puteri pozitive de întregi mici.
Prezentăm mai jos funcţia power şi un program principal care o apelează, pentru a putea vedea şi structura unui program.

power(int x, int n) {
int i, p;
p = 1;
for (i=1; i<=n; ++i)
p = p * x;
return p;
}

main() {
int i;
for (i=0; i<10; ++i)
printf(" %d %d\n", i, power(2,i),
power(-3,i));
}

Funcţia power este apelată în programul principal de două ori. Fiecare apel transmite funcţiei două argumente.
Rezultatul este afişat de funcţia de bibliotecă printf (vezi capitolul 11).
Numele funcţiei este urmat obligatoriu de paranteze, chiar dacă lista parametrilor este vidă.
În general numele funcţiei este ales după dorinţa utilizatorului. Totuşi în fiecare program trebuie să existe o funcţie cu numele impus main; orice program îşi începe execuţia cu funcţia main. Celelalte funcţii sînt apelate din interiorul funcţiei main. Unele dintre funcţiile apelate sînt definite în acelaşi program, altele sînt conţinute într-o bibliotecă de funcţii.
Comunicarea între funcţii se face prin argumente şi valori returnate de funcţii. Comunicarea între funcţii poate fi făcută şi prin intermediul variabilelor externe.
O funcţie poate fi declarată şi static. În acest caz ea poate fi apelată numai din fişierul unde a fost definită.
Funcţiile în C pot fi folosite recursiv, deci o funcţie se poate apela pe ea însăşi fie direct, fie indirect.
În general însă recursivitatea nu face economie de memorie, deoarece trebuie menţinută o stivă cu valorile de prelucrat.

Apelul funcţiilor

În limbajul C orice funcţie este apelată prin numele ei, urmat de lista reală a argumentelor, închisă între paranteze.
Dacă într-o expresie numele funcţiei nu este urmat imediat de o paranteză ’(’, adică funcţia nu apare pe poziţia de apel de funcţie atunci nu se realizează imediat apelul funcţiei respective ci se generează un pointer la funcţie (vezi secţiunea 9.11).

Revenirea din funcţii

Revenirea dintr-o funcţie se face prin intermediul unei instrucţiuni return.
Valoarea pe care o funcţie o calculează poate fi returnată prin instrucţiunea return, care după cum am văzut are două formate:
return;
return expresie;

Ca argument poate apărea orice expresie admisă în C. Funcţia returnează valoarea acestei expresii funcţiei apelante.
O funcţie nu returnează în mod obligatoriu o valoare. O instrucţiune return, fără expresie ca parametru, cauzează numai transferul controlului funcţiei apelante nu şi o valoare utilă.
La rîndul său funcţia apelantă poate ignora valoarea returnată.
De obicei o funcţie returnează o valoare de tip întreg. Dacă se doreşte ca funcţia să returneze un alt tip, atunci numele tipului trebuie să preceadă numele funcţiei, iar programul trebuie să conţină o declaraţie a acestei funcţii atît în fişierul în care funcţia este definită cît şi în fişierul unde funcţia este apelată.
Pentru a evita orice confuzie se recomandă ca tipul valorii returnate de funcţie să fie întotdeauna precizat, iar dacă dorim în mod expres ca funcţia să nu returneze o valoare să folosim tipul void.

De exemplu, funcţia atof(s) din biblioteca asociată compilatorului converteşte şirul s de cifre în valoarea sa în dublă precizie. Vom declara funcţia sub forma:
double atof(char s[]);
sau împreună cu alte variabile de tip double:
double sum, atof(char s[]);

Funcţiile nu pot returna masive, structuri, reuniuni sau funcţii.
Dacă o funcţie returnează o valoare de tip char, nu este nevoie de nici o declaraţie de tip din cauza conversiilor implicite. Totdeauna tipul char este convertit la int în expresii.

Argumentele funcţiei şi transmiterea
parametrilor


O metodă de a comunica datele între funcţii este prin argumente. Parantezele mici care urmează după numele funcţiei închid lista argumentelor.
În limbajul C argumentele funcţiilor sînt transmise prin valoare. Aceasta înseamnă că în C funcţia apelată primeşte valorile argumentelor sale într-o copie particulară de variabile temporare (în realitate pe stivă).
Funcţia apelată nu poate altera decît variabilele sale particulare, adică copiile temporare.
Apelul prin valoare este o posibilitate, dar nu şi o obligativitate. Apelul prin valoare conduce la programe mai compacte cu mai puţine variabile externe, deoarece argumentele pot fi tratate ca variabile locale, şi care pot fi modificate convenabil în rutina apelată.
Ca exemplu, prezentăm o versiune a funcţiei putere care face uz de acest fapt:

power(int x, int n) {
int p;
for (p=1; n>0; --n)
p = p * x;
return p;
}

Argumentul n este utilizat ca o variabilă temporară şi este decrementat pînă devine zero; astfel nu este nevoie de încă o variabilă i. Orice operaţii s-ar face asupra lui n în interiorul funcţiei, ele nu au efect asupra argumentului pentru care funcţia a fost apelată.
Dacă totuşi se doreşte alterarea efectivă a unui argument al funcţiei apelante, acest lucru se realizează cu ajutorul pointerilor sau a variabilelor declarate externe.
În cazul pointerilor, funcţia apelantă trebuie să furnizeze adresa variabilei de modificat (tehnic printr-un pointer la această variabilă), iar funcţia apelată trebuie să declare argumentul corespunzător ca fiind un pointer. Referirea la variabila de modificat se face prin adresare indirectă (vezi capitolul 9).
Printre argumentele funcţiei pot apărea şi nume de masive. În acest caz valoarea transmisă funcţiei este în realitate adresa de început a masivului (elementele masivului nu sînt copiate). Prin indexarea acestei valori funcţia poate avea acces şi poate modifica orice element din masiv.

Funcţii cu număr variabil de parametri

Pentru funcţiile cu număr variabil de parametri standardul ANSI defineşte o construcţie specială ... , numită elipsă. Acesta este de exemplu cazul funcţiilor de citire şi scriere cu format (familiile ...scanf şi ...printf - a se vedea capitolul 11). În acest caz, parametrii ficşi sînt verificaţi la compilare, iar cei variabili sînt transmişi ca şi cînd nu ar exista prototip de funcţie.
Pentru simplitatea expunerii am păstrat convenţiile definite de standardele mai vechi ale limbajului, păstrate şi de standardul ANSI C. O funcţie poate fi declarată fără nici un parametru, compilatorul deducînd de aici că funcţia respectivă poate avea oricîţi parametri de orice tip. Nu se recomandă totuşi o asemenea practică deoarece este posibil să se creeze confuzii care conduc la erori în execuţia programelor, erori care se corectează foarte greu în cazul programelor mari.

Exemple de funcţii şi programe


1. Acest exemplu este un program de căutare şi imprimare a tuturor liniilor dintr-un text care conţin o anumită configuraţie de caractere, de exemplu cuvîntul englezesc "the". Structura de bază a acestui program este:

while (mai există linii sursă)
if (linia conţine configuraţia de caractere)
imprimă linia

În scopul scrierii acestui program vom scrie trei funcţii. Funcţia getline citeşte o linie din textul sursă şi returnează lungimea ei. Această funcţie are două argumente. Argumentul s indică numele masivului unde se va citi linia, iar argumentul lim reprezintă lungimea maximă a unei linii care poate fi citită.
Funcţia index caută configuraţia de caractere dorită în interiorul liniei şi furnizează poziţia sau indexul în şirul s, unde începe şirul t, sau -1 dacă linia nu conţine şirul t. Argumentele funcţiei sînt s care reprezintă adresa şirului de studiat şi t care reprezintă configuraţia căutată.

Funcţia care realizează afişarea este printf din biblioteca.

Programul care realizează structura de mai sus este:

#define MAXLINE 1000
#define EOF -1

getline(char s[], int lim) {
/* citeşte o linie în s; returnează lungimea */
int c, i;
i = 0;
while (--lim>0 && (c=getchar())!= EOF &&
c!='\n')
s[i++]=c;
if (c=='\n') s[i++]=c;
s='\0';
return i;
}


index(char s[], char t[]) {
/* returnează poziţia din şirul s unde începe şirul t, sau -1 */
int i,j,k;
for (i=0; s!='\0'; i++) {
for (j=i, k=0; t[k]!='\0' &&
s[j]==t[k]; j++, k++)
;
if (t[k]=='\0')
return i;
}
return -1;
}


main() {
/* imprimă toate liniile care conţin cuvîntul „the” */
char line [MAXLINE];
while (getline(line, MAXLINE)>0)
if (index(line,"the")>=0)
printf("%s",line);
}


2. Funcţia atof converteşte un şir de cifre din formatul ASCII într-un număr flotant în precizie dublă.


double atof(char s[]) {
/* converteşte şirul s în dublă precizie */
double val, power;
int i, sign;
for (i=0; s==' ' || s=='\n' ||
s=='\t'; i++) ; /* sare peste spaţii albe */
sign = 1;
if (s=='+' || s=='-')
sign = (s[i++]=='+') ? 1 : -1;
for (val=0; s>='0' && s<='9'; i++)
val = 10 * val + s - '0';
if (s== '.') /* punct zecimal */
i++;
for (power=1; s>='0' && s<='9'; i++)
{
val = 10 * val +s - '0':
power *= 10;
}
return sign * val / power;
}


3. Funcţia atoi converteşte un şir de cifre în echivalentul lor numeric întreg.

atoi(char s[]) { /* converteşte şirul s la un întreg */
int i,n;
n = 0;
for (i=0; s>='0' && s<='9'; i++)
n = 10 * n +s - '0';
return n;
}


4. Funcţia lower converteşte literele mari din setul de caractere ASCII în litere mici. Dacă lower primeşte un caracter care nu este o literă mare atunci îl returnează neschimbat.


lower(int c) {
if (c>='A' && c<='Z')
return c + 'a' - 'A';
else
return c;
}


5. Funcţia binary realizează căutarea valorii x într-un masiv sortat v, care are n elemente.

binary(int x, int v[], int n) {
/* caută x în v0, v1, ..., vn-1 */
int low, high, mid;
low = 0;
high = n - 1;
while (low<=high) {
mid = (low + high) / 2;
if (x < v[mid])
high = mid - 1;
else if (x > v[mid])
low = mid + 1;
else /* s-a găsit o intrare */
return(mid);
}
return -1;
}


Funcţia returnează poziţia lui x (un număr între 0 şi n-1), dacă x apare în v sau -1 altfel.
Exemplul ilustrează o decizie triplă, dacă x este mai mic, mai mare sau egal cu elementul din mijlocul şirului v[mid].
 
Top