Documente Academic
Documente Profesional
Documente Cultură
PCLP CURS 6 1
11/9/2016
• 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
PCLP CURS 6 2
11/9/2016
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
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.
PCLP CURS 6 4
11/9/2016
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.
PCLP CURS 6 5
11/9/2016
/* 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
PCLP CURS 6 6
11/9/2016
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 */
PCLP CURS 6 7
11/9/2016
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
• Un program rezidă
într-unul sau mai multe fișiere sursă.
• 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
• funcţia getline este într-o versiune nouă; comparaţi-o /* strindex: return index of t in s, -1 if none */
PCLP CURS 6 10
11/9/2016
PCLP CURS 6 11
11/9/2016
#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 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
• 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
Variabile externe
• Variabilele externe sunt utile de asemenea,
datorită vizibilităţii şi
timpului de viaţă mari.
PCLP CURS 6 14
11/9/2016
• 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
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
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
PCLP CURS 6 17
11/9/2016
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
PCLP CURS 6 18
11/9/2016
• Trebuie să existe o variabilă index care înregistrează int getch(void) /* get a (possibly pushed-back)
poziţia caracterului curent în bufer. character */
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.
PCLP CURS 6 21