Sunteți pe pagina 1din 21

11/9/2016

Programarea Calculatoarelor si CUPRINS


Limbaje de Programare
CONTROLUL EXECUȚIEI PROGRAMELOR
CURS 6 •

Ciclurile while şi for
Operatorul virgulă
- suport de curs - • Ciclul do-while
• Instrucţiunile break şi continue
• Instrucţiunea goto şi etichetele
FUNCŢII
Controlul execuției programelor. • Variabile externe
Funcții. Stiva • Stiva şi notaţia poloneză inversă
• Regulile domeniului
17:53 PCLP CURS 6 2

Ciclurile while şi for


• Am lucrat deja cu ciclurile while şi for. În
while (expresie) for (; expresie;)
instrucţiune
instrucţiune
 prima dată este evaluată expresia
 dacă este nenulă se execută instrucțiunea şi apoi
expresia este re-evaluată.
CICLURILE while ŞI for
Această repetare se reia până când expresia devine
zero
 moment în care execuția continuă cu ceea ce este
după instrucţiune.
17:53 PCLP CURS 6 4

Instrucţiunea for Întrebare


for (expresie1; expresie2; expresie3) • Cât este valoarea lui i la ieşirea din ciclul for de
instrucţiune mai jos?
for ( i = 0; i < 10; i++ )
este echivalentă cu: printf(”i = %d\n”, i);
expresie1;
while (expresie2) { a) 9 b. 10
instrucţiune
b) 10 • De ce?
c) 11
expresie3;
d) niciuna din cele trei de mai sus
}
17:53 PCLP CURS 6 5 17:53 PCLP CURS 6 6

PCLP CURS 6 1
11/9/2016

• Din punct de vedere gramatical, cele trei componente ale


Răspuns ciclului for sunt expresii.
 Cel mai adesea expresie1 şi expresie3 sunt atribuiri sau
for ( i = 0; i < 10; i++ ) apeluri de funcții,
printf(”i = %d\n”,i);  iar expresie2 este o expresie relațională.
Este echivalent cu: • Oricare din cele trei părți poate fi omisă,
i = 0;  dar caracterele punct și virgulă trebuie să fie prezente.
while ( i < 10 ) {
• Din echivalarea instrucțiunii for cu instrucțiunea while
printf(”i = %d\n”,i); prezentată mai sus se vede simplu ce se întâmplă dacă
i++; expresie1 şi expresie3 sunt omise.
}
• Dacă expresia de test expresie2 este absentă
i se mai incrementează o dată la ieșirea din for  se consideră condiția adevărată totdeauna ca un while(1)
17:53 PCLP CURS 6 7 17:53 PCLP CURS 6 8

• Un for ca cel de mai jos: • Dacă condiția din test (expresie2) este adevărată
for (;;) {
 atunci se execută corpul ciclului,
...
}  după care se execută expresie3,
 este un ciclu „infinit”, care probabil este întrerupt  care constă de cele mai multe ori în modificarea
prin alte mijloace cum ar fi valorii variabilei de control al ciclului.
 un break sau
 un return. • Se revine apoi la reevaluarea condiției (expresie2)

• expresie1 constituie inițializarea ciclului și se execută • Ciclul se termină când condiția (expresie2) devine
o singură dată înaintea ciclului, falsă.
• expresie2 specifică testul care controlează ciclul, • Alegerea între utilizare lui while sau for ține de
 el se execută înaintea fiecărei iterații. preferința personală.
17:53 PCLP CURS 6 9 17:53 PCLP CURS 6 10

• De exemplu, în: • Aceasta este evident în exemplul:


while ((c = getchar()) == ' ' || c == '\n' || c = '\t')
; /* skip white space characters */
for ( i = 0; i < n; i++ )
...
 nu există nicio inițializare sau re-iniţializare
 astfel că alegerea lui while este mai naturală.  care în C este o construcție uzuală pentru
procesarea primelor n elemente ale unui tablou.
• for este preferabil când există
 o simplă inițializare și • Contorul și limita unui ciclu for în C
 o incrementare,  pot fi modificate din interiorul ciclului.
• deoarece instrucțiunile de control ale ciclului se • Adică un cod ca următorul unde
păstrează la  i : contorul ciclului și
 începutul ciclului într-un loc vizibil și  n : limita ciclului
 una lângă alta sunt modificate în interiorul ciclului, este legal.
17:53 PCLP CURS 6 11 17:53 PCLP CURS 6 12

PCLP CURS 6 2
11/9/2016

int i, n = 10; • Variabila contor își păstrează valoarea la ieșirea din


for ( i = 0; i < n; i++ ) { ciclul for.
if ( i == 5 ) Modificarea • Deoarece componentele lui for sunt expresii
i++; contorului ciclului: i arbitrare
printf("%d\n", i);  ciclul for nu este restricționat la progresii aritmetice
if ( i == 8 )
Modificarea
• Prezentăm un exemplu cu o versiune a unei funcții
n++; limitei ciclului: n prezentate anterior: atoi
}  pentru conversia unui șir de caractere la echivalentul
său numeric.
• Evident, un astfel de ciclu poate fi foarte confuz • Versiunea prezintă un grad de generalitate mai mare
 așa că este recomandat să nu faceți uz prea mult  aplicându-se și la șiruri prefixate de spații albe, sau
de această libertate. care prezintă semnul + sau -.
17:53 PCLP CURS 6 13 17:53 PCLP CURS 6 14

• În partea a 2-a a cursului vom prezenta funcția atof #include <ctype.h>


care realizează aceiași conversie /* atoi: convert s to integer; version 2 */
int atoi(char s[])
 pentru numere reale virgulă mobilă. {
int i, n, sign;
• Schema programului reflectă forma intrării:
sari peste spațiile albe, dacă există for (i = 0; isspace(s[i]); i++)
preia semnul, dacă există ; /* skip white space */
sign = (s[i] == '-') ? -1 : 1;
preia partea de număr întreg și convertește-l Biblioteca standard
if (s[i] == '+' || s[i] == '-') furnizează o funcție
• Fiecare pas își face bine sarcina sa și i++; /* skip sign */ mult mai elaborată

 lasă lucrurile într-o formă clară pentru următorul pas. for (n = 0; isdigit(s[i]); i++) strtol pentru
conversia șirurilor
n = 10 * n + (s[i] - '0'); de caractere la
• Întregul proces se termină la primul caracter care return sign * n; întregi lungi.
 nu poate să facă parte dintr-un număr. }
17:53 PCLP CURS 6 15 17:53 PCLP CURS 6 16

Operatorul virgulă
• Operatorul virgulă este adesea utilizat în for.
• Un număr de expresii separate prin virgulă sunt
evaluate de la stânga la dreapta,
 iar tipul și valoarea rezultatului sunt tipul și valoarea
operandului din dreapta.
• Astfel într-o instrucțiune for este posibil să plasăm
OPERATORUL VIRGULĂ
multiple expresii în diferite părți ale acesteia
 de exemplu pentru a procesa doi indici în paralel.
• Acest lucru este ilustrat în funcția reverse(s)
17:53 PCLP CURS 6 18

PCLP CURS 6 3
11/9/2016

Operatorul virgulă
#include <string.h>
• Să observăm că virgulele care separă
/* reverse: reverse string s in place */  argumentele funcțiilor,
void reverse(char s[])  variabilele din declarații etc.
{ nu sunt operatori virgulă și nu se garantează evaluarea de la
int c, i, j; stânga la dreapta.

for (i = 0, j = strlen(s)-1; i < j; i++, j--){ • Atunci când întâlnim un apel de forma:
c = s[i]; getline(line, MAXLINE);
s[i] = s[j];  virgula doar separă cele două argumente
Funcția reverse(s), line și
s[j] = c; MAXLINE;
inversează șirul de
} caractere s[] în el însuși.  amândouă vor fi evaluate,
}  dar nu contează în ce ordine și
 ambele vor fi transmise funcției getline.
17:53 PCLP CURS 6 19 17:53 PCLP CURS 6 20

• Dacă virgula dintr-un apel de funcții ar fi interpretată Operatorul virgulă


ca operator virgulă
 funcția ar trebui să primească un singur argument,
• O expresie virgulă poate fi de asemenea adecvată
 deoarece valoarea primului operand al operatorului
virgulă se pierde. la interschimbarea elementelor din funcția
reverse
• Operatorii virgulă trebuie utilizați cumpătat.
 unde interschimbarea poate fi realizată printr-o
• Cea mai adecvată utilizare este pentru construcțiile singură operație, ca mai jos:
puternic înrudite unele cu altele,
for (i = 0, j = strlen(s) - 1; i < j; i++, j--)
 cum este și în ciclul for din funcția reverse(),
 precum și în macrouri unde un calcul în mai mulți pași c = s[i], s[i] = s[j], s[j] = c;
trebuie să fie concentrat într-o singură expresie.
17:53 PCLP CURS 6 21 17:53 PCLP CURS 6 22

Ciclul do-while
• Ciclurile while şi for testează condiţia de terminare
la început.
• În schimb, do-while, testează condiția la final,
 după ce a efectuat toți pașii din corpul ciclului.

• Deci corpul ciclului do-while este executat cel puțin


odată,
CICLUL do-while  spre deosebire de cazurile lui while şi for unde,
 dacă condiția de terminare are valoare zero de la
primul test,
 nu se intra deloc în corpul ciclului.
17:53 PCLP CURS 6 24

PCLP CURS 6 4
11/9/2016

Ciclul do-while Ciclul do-while


• Sintaxa lui do-while este:
do • Să observăm că punctul şi virgula care apar după
instrucțiune (expresie); aparţine sintaxei instrucţiunii.
while (expresie); • Experienţa a arătat că do-while este mult mai
• Întâi se execută instrucțiunea, apoi se evaluează puţin utilizată decât while şi for.
expresia. • Cu toate acestea, uneori ea este o instrucțiune
 Dacă aceasta este adevărată (are valoare nenulă), valoroasă
 instrucțiunea este executată încă o dată ş.a.m.d.
 ca în exemplul de mai jos în funcţia itoa(), care
• Când expresia devine falsă (are valoarea zero), ciclul converteşte un număr întreg la un şir de caractere
se termină.  este inversul funcţiei atoi()
17:53 PCLP CURS 6 25 17:53 PCLP CURS 6 26

/* itoa: convert n to characters in s */


Funcţia itoa void itoa(int n, char s[])
{
• Sarcina este un pic mai complicată decât ar părea int i, sign;
la prima vedere, if ((sign = n) < 0) /* record sign */
n = -n; /* make n positive */
 deoarece cea mai ușoară metodă de a genera cifre i = 0;
nu le generează în ordinea corectă, do { /* generate digits in reverse order */
s[i++] = n % 10 + '0'; /* get next digit */
 ci inversată pentru că folosește operațiile %10, /10. } while ((n /= 10) > 0); /* delete it */
if (sign < 0)
• Am ales să generăm şirul invers şi s[i++] = '-';
s[i] = '\0';
 apoi să îl inversăm. reverse(s);
}
17:53 PCLP CURS 6 27 17:53 PCLP CURS 6 28

Ciclul do-while
• Ciclul do-while este necesar, sau măcar convenabil,
 deoarece cel puţin un caracter trebuie să fie pus în
tabloul de caractere s, chiar dacă n este zero.

• De asemenea am utilizat acolade în jurul singurei


instrucţiuni care reprezintă corpul ciclului do-while
 chiar dacă ele nu erau necesare, INSTRUCŢIUNILE break ŞI
 pentru ca să nu confundăm partea finală de while a continue
ciclului do-while cu începutul unui ciclu while.

17:53 PCLP CURS 6 29

PCLP CURS 6 5
11/9/2016

Instrucţiunile break şi continue • Un break în interiorul unui switch aflat în


interiorul unui ciclu
 produce ieşirea din switch,
• Adesea este convenabil să controlăm ieșirile din bucle
 altfel decât testând condiția la începutul sau sfârșitul • Un break în interiorul unui ciclu aflat în interiorul
buclei. unui switch
 produce ieşirea din ciclu.
• Instrucțiunea break oferă
 o ieșire mai devreme din for, while, do și switch • Următoarea funcţie: trim
 șterge blank-urile, tab-urile şi newline-urile de la
• O instrucțiune break face ca bucla cea mai din sfârșitul unui şir de caractere,
interior sau switch-ul  folosind un break pentru a ieși din bucla când
 este găsit cel mai din dreapta caracter non-blank, non-
 să se termine imediat. tab sau non-newline.
17:53 PCLP CURS 6 31 17:53 PCLP CURS 6 32

/* trim: remove trailing blanks, tabs, newlines */ • Funcția strlen returnează lungimea șirului de
caractere.
int trim(char s[])
• Ciclul for începe de la sfârșitul șirului și îl scanează
{
mergând înapoi
int n;
 căutând primul caracter care nu este blank, tab sau
newline.
for (n = strlen(s)-1; n >= 0; n--)
Ciclul este terminat forțat
if (s[n] != ' ' && s[n] != '\t' && s[n] != '\n')
 când este găsit un astfel de caracter sau
break;  când n devine negativ (i.e. întregul șir a fost parcurs).
s[n + 1] = '\0'; Funcția returnează lungimea • Trebuie să verificați că funcția are un comportament
return n + 1; șirului rezultat după corespunzător și atunci
} îndepărtarea spațiilor albe.  când şirul este vid sau
 conţine numai caractere spaţii albe.
17:53 PCLP CURS 6 33 17:53 PCLP CURS 6 34

Instrucțiunea continue • Un continue în interiorul unui switch aflat într-un


ciclu declanșează următoarea iterație a ciclului.
• Este înrudită cu break
 dar este mai puțin folosită • Fragmentul de cod următor prelucrează numai
elementele pozitive dintr-un tablou a;
• Determină începerea următoarei iterații a ciclului
 valorile negative sunt sărite:
(while, for sau do) care o conţine. for (i = 0; i < n; i++){
• În cazul lui while şi do aceasta înseamnă că if (a[i] < 0) /* skip negative elements */
continue;
 partea de test se execută imediat; ... /* do positive elements */
}
• În cazul lui for,
 controlul se trece la pasul de incrementare. • Nici break, nici continue, nu are vreun efect
 într-un un bloc de instrucţiuni plasat între acolade urmând
• continue se aplica numai la cicluri, nu şi la switch.
unui if.
17:53 PCLP CURS 6 35 17:53 PCLP CURS 6 36

PCLP CURS 6 6
11/9/2016

Instrucţiunea goto şi etichetele


• Limbajul C oferă
 instrucțiunea – de care ne putem lipsi oricând - goto
 și etichete pentru ca goto să trimită controlul către
respectiva secvenţă etichetată.

• Formal, goto nu este necesară niciodată şi în practică


este totdeauna ușor să scriem cod fără ea.
INSTRUCŢIUNEA goto ŞI
ETICHETELE • În Kernighan, Ritchie, The C Programming Language, ea
nu a mai fost folosită niciodată,
 după ce a fost prezentată.
17:53 PCLP CURS 6 38

Instrucţiunea goto şi etichetele for ( ... )


Această modalitate de
• Cu toate acestea, se pot imagina câteva situaţii în for ( ... ) {
organizare este utilă dacă:
care să se justifice utilizarea lui goto. ...
• Utilizarea uzuală este aceea în care abandonăm if (disaster)
procesarea în anumite structuri puternic imbricate goto error;
 de exemplu, vrem să ieşim afară din două cicluri }
deodată. • codul de gestionare a erorii este netrivial şi
... • dacă erorile pot apare în mai multe locuri.
• Instrucțiunea break nu poate fi folosită
error: /*a label*/
 deoarece ea părăseşte numai ciclul cel mai din
clean up the mess
interior.
17:53 PCLP CURS 6 39 17:53 PCLP CURS 6 40

Eticheta
for (i = 0; i < n; i++)
• O etichetă are aceeaşi formă ca şi un nume de
variabilă şi for (j = 0; j < m; j++)
 este urmată de două puncte. if (a[i] == b[j])
goto found;
• Ea poate fi ataşată oricărei instrucţiuni aflată în
aceeaşi funcţie ca şi goto. /* didn't find any common element */

• Domeniul de vizibilitate al etichetei este întreaga ...


funcţie. found: /*a label*/

/* got one: a[i] == b[j] */


• De exemplu, să considerăm problema aflării dacă două
tablouri a şi b au un element în comun. ...
17:53 PCLP CURS 6 41 17:53 PCLP CURS 6 42

PCLP CURS 6 7
11/9/2016

Instrucţiunea goto şi etichetele Exemplul 1: căutarea în tablou fără funcţii


found = 0;
• Codul implicând un goto poate fi scris întotdeauna for (i = 0; i < n && !found; i++)
fără goto, for (j = 0; j < m && !found; j++)
 chiar dacă preţul pentru aceasta este if (a[i] == b[j])
 o variabilă suplimentară, sau found = 1;
 teste repetate. if (found)
/* got one: a[i-1] == b[j-1] */
• Iată două exemple pentru căutarea în tablou evitând
...
elegant folosirea instrucţiunii goto, De ce avem i-1 şi j-1 şi nu avem i şi j?
else
 primul exemplu nu utilizează funcţii,
/* didn't find any common element */
 al doilea utilizează o funcţie:
...
17:53 PCLP CURS 6 43 17:53 PCLP CURS 6 44

/* return i such that a[i] == b[j] for some j, or -1 if none */


Concluzie
int findequal(int a[], int na, int b[], int nb)
{
Exemplul 2: căutarea în tablou cu funcţie • Cu câteva excepţii – ca cele prezentate aici –
int i, j;
 codul care se bazează pe instrucţiunea goto este
for(i = 0; i < na; i++) { Sunt necesare
for(j = 0; j < nb; j++) { parantezele? în general
if(a[i] == b[j])  greu de înţeles şi
return i; Această funcţie poate  greu de întreţinut.
} fi apelată astfel:
} • Ca o concluzie,
i = findequal(a, na, b, nb);
return -1;
if(i == -1)  instrucţiunea goto ar trebui folosită rar,
} /* didn't find any common element */
else /* got one */ dacă nu chiar deloc.
17:53 PCLP CURS 6 45 17:53 PCLP CURS 6 46

Funcţii
• Funcțiile sparg sarcinile mari de calcul în sarcini mai
mici şi
 permit programatorilor să construiască începând de
la ceea ce alții au făcut deja,
 în loc de a lua totul de la zero.
• Funcțiile bine scrise ascund detaliile operaţiilor de
FUNCŢII părţile programului
 care nu au nevoie să le cunoască,
 clarificând astfel întregul şi
 uşurând efortul de a face modificări.
17:53 PCLP CURS 6 48

PCLP CURS 6 8
11/9/2016

• Limbajul C a fost proiectat pentru a face funcțiile


eficiente și ușor de folosit;
 programele C nu constau în câteva funcții mari,
 ci mai degrabă în numeroase funcții mici.

• Un program rezidă
 într-unul sau mai multe fișiere sursă.

• Fişierele sursă pot fi


 compilate separat şi APLICAȚIE: Selecție linii conținând
 încărcate laolaltă, un model
 alături de alte funcţii compilate anterior ce se găsesc în
biblioteci.
17:53 PCLP CURS 6 49

• Să proiectăm şi să scriem un program pentru a afişa • Sarcina de calcul se sparge perfect în trei bucăți:
fiecare linie de pe intrare care conţine un model (pattern)
particular reprezentat de un şir de caractere. while (există o altă linie)
• De exemplu, să căutăm pattern-ul "to" în mulţimea de if (linia conţine modelul)
linii de mai jos:
afişează linia care conţine modelul
To be, or not to be: that is the question:
Whether 'tis nobler in the mind to suffer
The slings and arrows of outrageous fortune,
Or to take arms against a sea of troubles, • Cu toate că se poate scrie codul pentru toate
• Aceasta va produce ieşirea: aceste sarcini doar în main,
To be, or not to be: that is the question:  o modalitate mai bună este aceea de a scrie
Whether 'tis nobler in the mind to suffer  trei funcţii separate folosind structura anterioară.
Or to take arms against a sea of troubles,
17:53 PCLP CURS 6 51 17:53 PCLP CURS 6 52

• Este mai uşor să gestionăm trei bucăţi mai mici 1.while (există o altă linie)
 decât o bucată mare,  este funcţia getline,
 deoarece detaliile nerelevante pot fi ascunse în  pe care am scris-o anterior,
funcţii şi
 posibilitatea unor interacţiuni nedorite este astfel 2.afişează linia care conţine modelul
minimizată.  este funcţia printf.

• Iar funcţiile, reprezentând bucăţile în care am 3. Nu trebuie să scriem decât o funcţie care
descompus o sarcină,
 decide dacă linia procesată la pasul curent al
 pot fi utilizate în alte programe în contexte noi. prelucrărilor
 conţine o apariţie a modelului.
17:53 PCLP CURS 6 53 17:53 PCLP CURS 6 54

PCLP CURS 6 9
11/9/2016

• Scriem funcţia strindex(s,t) care returnează • Biblioteca standard furnizează o funcţie strstr care este
similară cu strindex,
 poziţia sau indexul din şirul s în care începe şirul t,
 cu excepţia faptului că returnează un pointer în locul unui
 sau -1, daca s nu-l conţine pe t. index.
Deoarece tablourile în C încep din poziţia 0,
• Vom construi programul detaliind schiţa de mai sus.
 indecşii şirurilor de caractere vor fi 0 sau pozitivi şi
 o valoare negativă precum -1 va fi convenabilă • Să observăm că din cauză că modelul care trebuie căutat
 pentru a semnaliza nereuşita căutării. ("to") este un şir literal (i.e. constantă)
 programul pierde din generalitate.
• Dacă ulterior vom avea nevoie de o căutare a unui
model mai sofisticat, • Ulterior vom învăţa cum să iniţializăm tablourile de
caractere şi
 nu trebuie decât să înlocuim funcţia strindex;
 cum să facem modelul un parametru care este setat la
 restul codului rămâne acelaşi. lansarea în execuţie a programului.
17:53 PCLP CURS 6 55 17:53 PCLP CURS 6 56

#include <stdio.h> int main() /* find all lines matching pattern */


#define MAXLINE 1000 /* maximum input line length */ {
int getline(char line[], int max); char line[MAXLINE];
int strindex(char source[], char searchfor[]);
int found = 0;
char pattern[] = "to"; /* pattern to search for */
int main() /* find all lines matching pattern */ while (getline(line, MAXLINE) > 0)
{…} if (strindex(line, pattern) >= 0) {
/* getline: get line into s, return length */ printf("%s", line);
int getline(char s[], int lim) found++;
{…}
}
/* strindex: return index of t in s, -1 if none */ funcţia main returnează un status
(variabila found) reprezentat de
int strindex(char s[], char t[]) return found;
{…} } numărul de linii găsite şi afişate

17:53 PCLP CURS 6 57 17:53 PCLP CURS 6 58

• funcţia getline este într-o versiune nouă; comparaţi-o /* strindex: return index of t in s, -1 if none */

cu cea prezentată anterior. int strindex(char s[], char t[])


int getline(char s[], int lim) {
{ /* getline: get line into s, return length */ int i, j, k;
int c, i; for (i = 0; s[i] != '\0'; i++) {
i = 0; for (j = i, k = 0; t[k] != '\0' &&
while (--lim > 0 && (c = getchar()) != EOF && c != '\n') s[j] == t[k]; j++, k++)
s[i++] = c; ;
if (c == '\n') if (k > 0 && t[k] == '\0')
s[i++] = c; return i;
s[i] = '\0'; }
return i; return -1;
} }
17:53 PCLP CURS 6 59 17:53 PCLP CURS 6 60

PCLP CURS 6 10
11/9/2016

Forma unei funcții • o funcție minimală este:


dummy() {}
• Fiecare definiție funcția are forma următoare:
 care nu face nimic şi
tipul-valorii-returnate nume-funcţie(declaraţii de argumente)  nu returnează nimic.
{
declaraţii şi instrucţiuni • O astfel de funcţie este utilă uneori ca rezervare a
} unui loc în program
 pentru dezvoltări ulterioare ale acestuia.
• Diferite părți din sintaxa de mai sus pot lipsi
• Dacă tipul-valorii-returnate este omis
 se consideră implicit că funcţia returnează un int.
17:53 PCLP CURS 6 61 17:53 PCLP CURS 6 62

Un program Instrucţiunea return


• Un program este o mulţime de definiții • Instrucţiunea return este mecanismul de returnare
 de variabile şi de funcţii. a unei valori
• Comunicarea între funcţii se realizează prin:  din funcţia apelată către funcţia apelantă.
 argumente • După return poate urma orice expresie:
 valorile returnate de funcţii return expresie;
 variabile externe.
• Dacă este necesar expresia va fi convertită la tipul
• Funcțiile pot apare în orice ordine în fişierul sursă returnat de funcţie.
• Programul sursă poate fi împărţit în mai multe fişiere • Adesea expresia este plasată între paranteze,
 având grijă ca niciodată o funcţie să nu fie împărţită.  dar ele sunt opţionale.
17:53 PCLP CURS 6 63 17:53 PCLP CURS 6 64

Instrucţiunea return Instrucţiunea return


• În programul anterior, care caută un model,
• Nu este necesar să existe o expresie după
return;  funcţia main returnează un status:
 în acest caz, funcţia nu returnează apelantului return found;
nicio valoare.  reprezentat de numărul de linii găsite şi afişate
 această valoare este disponibilă pentru mediul
• Controlul este returnat apelantului fără nicio care a apelat programul.
valoare • Mecanismul prin care se compilează şi se încarcă un
 şi atunci când execuţia funcţiei ajunge la finalul program care rezidă în mai multe fişiere sursă variază de
acesteia, la un sistem la altul (pentru mediul CodeBlocks se va
 atingând acolada care închide funcţia. discuta la Laborator).
17:53 PCLP CURS 6 65 17:53 PCLP CURS 6 66

PCLP CURS 6 11
11/9/2016

Funcţii care returnează valori ne-întregi Funcţia atof


• În exemplele de până acum funcţiile atof e o extensie
• Funcţia trebuie să se ocupe
 fie nu returnau nicio valoare (void) a funcţiei atoi
 de un semn opţional şi prezentate anterior
 fie returnau un int.
 de punctul zecimal şi
• Multe funcţii numerice ca sqrt, sin şi cos
 de prezenţa sau absenţa părţii fracţionare a
 returnează valori de tip double numărului. șir de număr
atof
 alte funcţii returnează alte tipuri. caractere real

• Să scriem o funcţie atof(s), care converteşte şirul


• Versiunea este una didactică,
de caractere s la echivalentul său:  pentru că o versiune riguroasă ar ocupa prea mult
 număr real dublă precizie virgulă mobilă. spaţiu.
17:53 PCLP CURS 6 67 17:53 PCLP CURS 6 68

Funcţia atof #include <ctype.h>


double atof(char s[]) /* atof: convert string s to double */
{
double val, power; int i, sign;
for (i = 0; isspace(s[i]); i++)
• Biblioteca standard include o funcţie atof ;
/* skip white space */

sign = (s[i] == '-') ? -1 : 1;


 ea se declară cu header-ul <stdlib.h>. if (s[i] == '+' || s[i] == '-')
i++;
for (val = 0.0; isdigit(s[i]); i++) /* collect integer part */
val = 10.0 * val + (s[i] - '0');
• La început, atof trebuie să declare tipul valorii if (s[i] == '.') /* skip decimal point */
i++;
pe care o returnează, for (power = 1.0; isdigit(s[i]); i++) {/* collect fraction part */
val = 10.0 * val + (s[i] - '0');
 deoarece ea nu este int ca să fie subînţeleasă. power *= 10;
}

• Tipul valorii returnate precede numele funcţiei. }


return sign * val / power;

17:53 PCLP CURS 6 69 17:53 PCLP CURS 6 70

#include <stdio.h>
Funcţia main care apelează atof #define MAXLINE 100
int main() /* rudimentary calculator */
• Să scriem o funcţie main {
 care citește un număr pe linie, double sum, atof(char []);
char line[MAXLINE];
 precedat opțional de un semn int getline(char line[], int max);
 şi-l adună la toate numerele anterioare, sum = 0;
 tipărind suma după fiecare intrare. while (getline(line, MAXLINE) > 0)
printf("\t%g\n", sum += atof(line));
• Se observă că funcţia atof a fost declarată explicit ca Declaraţia: double sum, atof(char []); spune că:
returnând o valoare double, return 0; • sum este o variabilă de tip double şi
} • că atof este o funcţie care
 pentru că funcţia apelantă (la noi: main) trebuie să primeşte pe intrare un argument de tip char[] şi
returnează un double.
ştie că atof returnează o valoare neîntreagă.
17:53 PCLP CURS 6 71 17:53 PCLP CURS 6 72

PCLP CURS 6 12
11/9/2016

• Funcţia atof trebuie declarată şi definită consecvent Funcţia atoi


• Dacă atof şi apelul său în main au tipuri
inconsecvente în acelaşi fişier sursă,
• Având corect scrisă şi declarată funcţia atof,
această eroare va fi detectată de compilator.  putem scrie pe baza ei o funcţie atoi (care
converteşte un şir de caractere la un int) astfel:
• Dar dacă (cum este mult mai probabil) atof a fost
compilată separat, /* atoi: convert string s to integer using atof */

 eroarea nu va fi detectată, int atoi(char s[])


Operatorul typecast (int)
 atof va returna un double pe care main îl va trata ca { de conversie explicită
pe un int şi astfel
double atof(char s[]);
 vor apărea rezultate fără sens.
return (int) atof(s);
• În plus, dacă o funcţie are argumente, ele trebuie
}
declarate, dacă nu are argumente se foloseşte void.
17:53 PCLP CURS 6 73 17:53 PCLP CURS 6 74

Funcţia atoi
• Operatorul typecast (int) de conversie explicită
apare în expresia returnată
 pentru a evita o atenţionare a compilatorului
 care avertizează asupra unei posibile pierderi de
informaţie în cazul în care am scrie:
return atof(s);
VARIABILE EXTERNE
• pentru că atof(s) este un double
• şi el este forţat să devină int,
 adică tipul valorii returnate de funcţia atoi.
17:53 PCLP CURS 6 75

Variabile externe • Funcţiile înseşi sunt totdeauna externe


• Un program C constă dintr-un set de obiecte externe,  deoarece C nu permite să fie definite funcţii în
care sunt interiorul altor funcţii.
 fie variabile,
• Implicit, variabilele externe şi funcţiile au
 fie funcţii.
proprietatea că sunt globale
• Adjectivul „extern” este utilizat în contrast cu „intern”  standardul numeşte această proprietate
 care descrie argumentele şi variabilele definite în
interiorul funcţiilor.
external linkage

• Variabilele externe sunt definite în exteriorul oricărei • astfel încât toate referinţele la ele printr-un acelaşi
funcţii şi astfel nume (chiar şi pentru funcțiile compilate separat)
 ele sunt potenţial disponibile pentru multe funcţii. sunt referințe la un același lucru.
17:53 PCLP CURS 6 77 17:53 PCLP CURS 6 78

PCLP CURS 6 13
11/9/2016

• Ulterior vom vedea cum să definim variabile Variabile externe


externe şi funcţii
 care sunt vizibile numai în interiorul unui singur • Dacă mai multe funcţii trebuie să partajeze un
fişier sursă. număr mare de variabile,
• Deoarece variabilele externe sunt accesibile  variabilele externe sunt mai convenabile şi mai
eficiente decât listele lungi de argumente.
global, ele oferă o alternativă
 la argumentele funcţiilor şi • Dar această modalitate trebuie utilizată cu precauţie,
 a valorilor returnate pentru comunicarea datelor  deoarece ea poate avea efecte negative asupra
între funcţii. structurii programului şi
• Orice funcţie poate accesa o variabilă externă  poate conduce la programe cu prea multe conexiuni
de date între funcţii.
referindu-se la ea prin numele ei.
17:53 PCLP CURS 6 79 17:53 PCLP CURS 6 80

Variabile externe
• Variabilele externe sunt utile de asemenea,
 datorită vizibilităţii şi
 timpului de viaţă mari.

• Variabilele automate sunt interne unei funcţii;


 ele vin la viaţă când se intră în funcţie şi
 dispar când funcţia este părăsită. APLICAȚIE: Stiva şi notaţia poloneză
inversă
• Dar variabilele externe sunt permanente, așa că
 ele pot reţine valori între apelurile de funcţii.
17:53 PCLP CURS 6 81

Programul calculator Întrebare


• Programul calculator din exemplul următor realizează
calcule cu operatorii • Scrieţi în notaţia poloneză inversă următoarele
+, -, * şi / expresii:
• Se va folosi notaţia poloneză inversă în care fiecare a. (1 - 2) * (4 + 5)
operator urmează după operanzii săi.
b. 7 + ((1 + 8) * 12) − 3
• De exemplu, expresia:
(1 - 2) * (4 + 5)
 se scrie astfel în notaţia poloneză inversă: a. 1 2 - 4 5 + *
1 2 - 4 5 + *
b. 7 1 8 + 12 * + 3 −
 Parantezele nu sunt necesare.
17:53 PCLP CURS 6 83 17:53 PCLP CURS 6 84

PCLP CURS 6 14
11/9/2016

Programul calculator STIVA


• Implementarea este simplă.

• Fiecare operand este pus (push) pe o stivă.


• Stiva este o structură de
• Când soseşte un operator, date
 numărul corespunzător de operanzi (doi pentru  LIFO (Last In First Out)
operatorii binari) sunt extraşi din stivă (pop),
sau
 operatorul li se aplică şi apoi
 FILO (First In Last Out).
 rezultatul este pus (push) înapoi pe stivă.
17:53 PCLP CURS 6 85 17:53 PCLP CURS 6 86

• Punem 1, apoi 2 pe stivă.


1 2 - 4 5 + *
-1 9 • În continuare apărând operatorul –
 sunt înlocuiţi de diferenţa lor: -1.
-9
• Apoi 4 şi 5 sunt puşi pe stivă şi

• apărând operatorul +
 sunt înlocuiţi de suma lor: 9.

• Apărând operatorul *
 produsul lui 9 cu -1, adică -9, îi înlocuieşte pe
stivă.
17:53 PCLP CURS 6 87 17:53 PCLP CURS 6 88

• Structura programului calculator este reprezentată de un


• Să observăm că ciclu care efectuează operația adecvată pentru fiecare
 în stivă nu sunt plasaţi decât operanzii, operator şi operand care se citeşte pe intrare:
 operatorii nu se plasează în stivă, while (următorul operator/operand nu este EOF)
if (număr)
 ei produc doar modificarea operanzilor de pe
pune pe stivă
ultimele două nivele (în cazul operatorilor binari)
else if (operator)
din stivă
extrage operanzii din stivă
 înlocuindu-i cu valoarea rezultată din calcule. execută operaţia
pune rezultatul pe stivă
• Valoarea din vârful stivei este else if (newline)
 extrasă şi afişată extrage şi afişează valoarea din vârful stivei
 când se întâlneşte sfârşitul liniei de intrare. else
eroare
17:53 PCLP CURS 6 89 17:53 PCLP CURS 6 90

PCLP CURS 6 15
11/9/2016

• Principala decizie este să hotărâm unde va fi plasată • Aşa că am decis să stocăm stiva şi informaţia
stiva, asociată cu ea în variabile externe
 adică ce funcţii vor avea acces direct la ea.  doar pentru funcţiile push şi pop
• O posibilitate este să o păstrăm în main şi să trans-  dar nu şi pentru main.
mitem stiva şi poziţia curentă în stivă funcţiilor care
 pun (push) în stivă • Transformarea acestei scheme în cod este destul
 extrag (pop) din stivă. de uşoară.

• Dar main nu are nevoie să ştie despre variabilele care • Dacă gândim programul calculator ca fiind plasat
controlează stiva; într-un singur fişier sursă,
 main trebuie doar să realizeze operaţiile push şi pop.  el va avea schema următoare:
17:53 PCLP CURS 6 91 17:53 PCLP CURS 6 92

#include-uri Ulterior vom discuta cum se poate #include <stdio.h>


#define-uri împărţi acest program calculator în #include <stdlib.h> /* for atof() */
două sau mai multe fişiere sursă.
declaraţii de funcţii pentru main #define MAXOP 100 /* max size of operand or operator */
Funcţia main este un
#define NUMBER '0' /* signal that a number was found */
ciclul conţinând o
main() { ... } instrucţiune switch int getop(char s[]);
pentru tipul operatorilor
variabile externe pentru push şi pop sau operanzilor. void push(double);
double pop(void);
void push( double f) { ... }
main() /* reverse Polish calculator */
double pop(void) { ... }
{

int getop(char s[]) { ... } int type;


double op2;
funcţii apelate de getop char s[MAXOP];
17:53 PCLP CURS 6 93 17:53 PCLP CURS 6 94

while ((type = getop(s)) != EOF) { • Deoarece + şi * sunt operatori comutativi,


switch (type) {
case NUMBER: push(atof(s)); break; ordinea în care sunt extraşi din stivă operanzii lor nu are importanţă
case '+': push(pop() + pop()); break;
case '*': push(pop() * pop()); break; • dar pentru - şi /
case '-': op2 = pop(); push(pop() - op2); break;  trebuie să distingem între operandul din stânga şi cel din dreapta.
case '/': op2 = pop();
if (op2 != 0.0)
push(pop() / op2); • În secvenţa:
else push(pop() - pop()); /* WRONG */
printf("error: zero divisor\n");
break;  ordinea în care cele două apeluri ale funcţiei pop sunt
case '\n': printf("\t%.8g\n", pop()); break; evaluate nu este definită.
default: printf("error: unknown command %s\n", s);
break; • Pentru a garanta ordinea corectă este necesar să extragem
}
} primul operand într-o variabilă temporară
return 0;
}
 aşa cum am făcut pentru operatorii de scădere şi împărţire.
17:53 PCLP CURS 6 95 17:53 PCLP CURS 6 96

PCLP CURS 6 16
11/9/2016

sp = indicatorul vârfului val = stiva ca un tablou de /* pop: pop and return top value from stack */
stivei (variabilă externă) numere reale (variabilă externă)
double pop(void) sp = indicatorul
#define MAXVAL 100 /* maximum depth of val stack */
{ vârfului stivei
int sp = 0; /* next free stack position */ if (sp > 0)
double val[MAXVAL]; /* value stack */ val = stiva ca un
return val[--sp];
tablou de numere reale
void push(double f) /* push: push f onto value stack */
{ else {
val: STIVĂ
sp
if (sp < MAXVAL) MAXVAL poziţie liberă printf("error: stack empty\n");
val[sp++] = f; xxxxxxx val: STIVĂ
return 0.0; sp

MAXVAL
else xxxxxxx poziţie liberă
printf("err: stack full, can't push %g\n", f); } xxxxxxx
} } xxxxxxx
17:53 PCLP CURS 6 97 17:53 PCLP CURS 6 98

Variabilele externe val şi sp Funcţia getop


• Funcţia getop citeşte următorul operator sau
• O variabilă este externă dacă
operand.
 este definită în afara oricărei funcții.
• Ea va ignora blank-urile şi tab-urile.
• Deci stiva (val) și indexul stivei (sp) care trebuie
partajate de funcțiile push și pop • Dacă următorul caracter nu este o cifră sau un punct
zecimal,
 sunt definite în afara acestor funcţii.
 acest caracter este returnat.
• Dar deoarece main nu se referă la stivă (val) sau
• Acest caracter poate fi:
la poziția în stivă (sp),
 operator
 reprezentările val și sp îi sunt ascunse şi în acest caz se realizează operaţia corespunzătoare
 în program val și sp sunt declarate după main între el şi operanzii de pe ultimele nivele din stivă.
17:53 PCLP CURS 6 99 17:53 PCLP CURS 6 100

 poate fi newline Funcţia getop


 şi în acest caz programul calculator afişează valoarea
expresiei de pe linia de intrare curentă, • Deci în realitate funcţia getop returnează două
 poate fi EOF valori:
 şi în acest caz programul calculator se termină,
 Prima valoare este cea returnată formal,
 sau poate fi altceva
 şi se semnalează o eroare pentru că nu se înţelege  ea este un caracter (preluat de variabila type din
operaţia care trebuie efectuată. main)
 reprezentând următoarea operaţie care trebuie
• Altfel, funcţia colectează un şir de cifre
efectuată.
 care pot include şi un punct zecimal
• în variabila s  Uzual, acel caracter este chiar caracterul pe care l-a
tastat utilizatorul,
• şi returnează constanta caracter NUMBER,
 adică +, -, * sau /.
 semnalul că a fost colectat un număr.
17:53 PCLP CURS 6 101 17:53 PCLP CURS 6 102

PCLP CURS 6 17
11/9/2016

Funcţia getop Funcţia getop


• În cazul în care utilizatorul tastează un număr,
#include <ctype.h>
• prima valoare, cea returnată formal, este un cod
NUMBER int getch(void);
 căruia cu #define i s-a dat arbitrar valoarea '0'. void ungetch(int);
 Returnarea valorii NUMBER semnalizează faptul că
tocmai s-a tastat un şir de cifre reprezentând un număr, /* getop: get next character or numeric operand */

 acest şir fiind copiat într-un tablou de caractere s int getop(char s[])
 şi returnat – doar în acest caz - ca a doua valoare către {…}
main de către getop.
17:53 PCLP CURS 6 103 17:53 PCLP CURS 6 104

int getop(char s[])


{
Ignoră blank sau tab Ce sunt getch şi ungetch?
int i, c;
while ((s[0] = c = getch()) == ' ' || c == '\t') • Se întâmplă adesea ca un program să nu poată
;
s[1] = '\0';
Returnează un operator +, -, *, / determina dacă a citit suficient pe intrare
newline, EOF sau altceva (err)
if (!isdigit(c) && c != '.')  până în momentul când a citit prea mult.
return c; /* not a number */
i = 0; • Un exemplu este dat de colectarea caracterelor care
if (isdigit(c)) /* collect integer part */
while (isdigit(s[++i] = c = getch())) alcătuiesc un număr:
;
if (c == '.') /* collect fraction part */
 până când primul caracter ne-cifră nu este întâlnit,
while (isdigit(s[++i] = c = getch()))  numărul nu este complet.
;
s[i] = '\0'; Peste ultimul caracter citit în plus • Dar în acel moment programul a citit un caracter prea
if (c != EOF) (care îl scoate din while) pune ‘\0‘
ungetch(c);
mult,
Pune înapoi pe intrare caracterul citit în plus
return NUMBER;}  un caracter de care nu mai era nevoie.
17:53 PCLP CURS 6 105 17:53 PCLP CURS 6 106

Ce sunt getch şi ungetch? • Funcţia getch furnizează următorul caracter de


intrare care urmează să fie luat în considerare;
• Problema ar fi rezolvată dacă am putea să anulăm
citirea caracterului nedorit. • ungetch îl va returna înainte de a citi o nouă intrare.
• Astfel de fiecare dată când programul citeşte un • De fiecare dată când getop vrea să execute operaţia:
caracter mai mult,
citeşte următorul caracter
 el îl poate pune înapoi în intrare,
 astfel încât restul codului poate să se comporte ca şi  ea trebuie de fapt, să execute schema de mai jos:
cum acel caracter nu ar fi fost citit. if (există un caracter vechi)
• Din fericire, este uşor să simulăm ne-obţinerea unui foloseşte-l
caracter else
 prin scrierea unei perechi de funcţii care cooperează. citeşte următorul caracter
17:53 PCLP CURS 6 107 17:53 PCLP CURS 6 108

PCLP CURS 6 18
11/9/2016

• Cum lucrează ungetch şi getch împreună: #define BUFSIZE 100


 ungetch pune caracterele respinse într-un bufer partajat –
un tablou de caractere;
char buf[BUFSIZE]; /* buffer for ungetch */
 getch citeşte din bufer - dacă este ceva acolo - şi dacă nu este
apelează getchar dacă buferul este gol.
int bufp = 0; /* next free position in buf */

• Trebuie să existe o variabilă index care înregistrează int getch(void) /* get a (possibly pushed-back)
poziţia caracterului curent în bufer. character */

• Deoarece buferul și indexul sunt partajate de getch și {


ungetch și return (bufp > 0) ? buf[--bufp] :
trebuie să păstreze valorile lor între apeluri, getchar();
STIVĂ poziţie bufp
acestea trebuie să fie externe pentru ambele funcţii. } liberă
char buf[] char
• Scriem getch, ungetch şi variabilele pe care le partajează char
17:53 PCLP CURS 6 109 17:53 PCLP CURS 6 110

• Biblioteca standard conţine o funcţie ungetch care


void ungetch(int c)
/* push character back on input */
furnizează un caracter respins;
 funcţia va fi discutată într-un curs viitor.
{
if (bufp >= BUFSIZE) • Programul calculator utilizează un tablou pentru
printf("ungetch: too many characters\n"); caracterele respinse,
 mai degrabă decât un singur caracter,
else STIVĂ  pentru a ilustra o abordare mai generală.
buf[bufp++] = c; poziţie bufp
} liberă • Să observăm o limitare a programului calculator:
 el nu poate lucra cu numere cu semn,
char
 semnul fiind interpretat drept operatorul + sau -.
char
char buf[] • Evident, rezultate parţiale memorate în stivă pot fi
numere negative (vezi exemplul numeric iniţial).
17:53 PCLP CURS 6 111 17:53 PCLP CURS 6 112

• Funcțiile şi variabilele externe care compun un program


C nu trebuie să fie compilate toate în acelaşi timp.
• Textul sursă al programului poate fi păstrat în mai multe
fişiere,
 funcţiile compilate anterior pot fi încărcate din biblioteci
Printre întrebările care prezintă interes sunt:
• Cum sunt scrise declarațiile astfel încât variabilele să fie declarate
adecvat în timpul compilării?
• Cum sunt aranjate declarațiile astfel încât toate componentele să
REGULILE DOMENIULUI fie conectate corect atunci când programul este încărcat?
• Cum sunt declarațiile organizate astfel încât să existe o singură
copie?
• Cum sunt inițializate variabilele externe?
17:53 PCLP CURS 6 114

PCLP CURS 6 19
11/9/2016

• Vom discuta aceste chestiuni reorganizând programul • Variabile locale cu nume identice aflate în funcții
calculator în câteva fișiere.
diferite
• Din punct de vedere practic programul calculator este  nu au nicio legătură între ele.
prea mic pentru a merita să îl descompunem,
 dar el reprezintă o ilustrare excelentă pentru problematica • Același lucru este valabil și pentru parametrii sau
programelor mari.
argumentele unei funcții,
• Domeniul (scope) unui nume este  care au efectul unor variabile locale.
 partea programului în interiorul căruia acel nume poate fi
utilizat. • Domeniul unei variabile externe sau a unei funcții
• Pentru o variabilă automată declarată la începutul unei  ține de la punctul în care variabila este declarată
funcții,
 până la sfârșitul fișierului care se compilează.
 domeniul este funcția în care numele este declarat.
17:53 PCLP CURS 6 115 17:53 PCLP CURS 6 116

• De exemplu, dacă main, sp, val, push şi pop sunt • Pe de altă parte, dacă o variabilă externă
definite în acelaşi unic fişier în ordinea prezentată  este referită înainte de a fi definită, sau
anterior, adică:  este definită într-un fișier sursă diferit față de acela în
main() { ... } care este utilizată,
int sp = 0;
• atunci este necesară o declarație extern.
double val[MAXVAL];
void push(double f) { ... } • Este important să distingem între declarația unei
double pop(void) { ... } variabile externe și definiția ei.
• atunci variabilele sp şi val pot fi utilizate în funcţiile • O declarație anunță proprietățile unei variabile (în
push şi pop prin numele lor primul rând tipul ei);
 nu sunt necesare alte declaraţii. • o definiție determină să fie rezervat un spațiu de
 Dar aceste nume (sp şi val) nu sunt vizibile în main. memorare.
17:53 PCLP CURS 6 117 17:53 PCLP CURS 6 118

• Dacă liniile: int sp; • Trebuie să existe o singură definiţie pentru o variabilă
double val[MAXVAL];
externă
• apar în exteriorul oricărei funcții,  într-un singur fişier dintre toate fişierele care compun
 ele definesc variabilele externe sp şi val, programul;
 determinând să fie rezervat un spațiu de memorare și  celelalte fişiere sursă care compun programul pot conţine
 ele servesc ca declarații pentru restul fișierului sursă. declaraţii extern pentru a o accesa.
• Evident, pot fi declaraţii extern în fişierul care conţine
• În schimb, liniile: extern int sp; definiţia.
extern double val[];
• Dimensiunile tablourilor trebuie specificate la definirea lor,
• declară pentru restul fişierului sursă că sp este un int şi
 dar ele sunt opţionale într-o declaraţie extern.
că val este un tablou double (a cărui dimensiune este
determinată în altă parte), • Iniţializarea unei variabile externe se face numai la
 dar nu creează variabilele nici nu rezervă spaţiu pentru ele. definiţia ei.
17:53 PCLP CURS 6 119 17:53 PCLP CURS 6 120

PCLP CURS 6 20
11/9/2016

• Deşi nu este o organizare adecvată la programul calculator • Deoarece declaraţiile extern din fişierul1 se află
 funcţiile push şi pop pot fi definite într-un fişier1, înaintea şi în afara definiţiilor funcţiilor push şi pop,
 iar variabilele val şi sp pot fi definite şi iniţializate în alt fişier2.  ele se aplică la ambele funcţii;
 un set de declaraţii este suficient pentru tot fişierul1.
• Apoi aceste declaraţii şi definiţii trebuie legate împreună.
• O organizare similară este necesară dacă definiţia
• Iată cum se organizează această situaţie:
variabilelor sp şi val este ulterioară utilizării lor într-un
în fişierul2: singur fişierul sursă, astfel:
int sp = 0; Declarații
în fişierul1: extern int sp;
double val[MAXVAL]; extern double val[];
extern int sp;
extern double val[]; void push(double f) { ... }
void push(double f) {…} double pop(void) { ... }
double pop(void) {…} int sp = 0; Definiții
double val[MAXVAL];
17:53 PCLP CURS 6 121 17:53 PCLP CURS 6 122

BIBLIOGRAFIE
[1] Kernighan, B., Ritchie, D., The C Programming
Language, ediția a II-a, Ed. Prentice Hall, 1988.

17:53 PCLP CURS 6 123

PCLP CURS 6 21

S-ar putea să vă placă și