Sunteți pe pagina 1din 21

10/18/2015

Programarea Calculatoarelor si CUPRINS


Limbaje de Programare
I. Tablouri
CURS 3 II. Funcţii
II.1 Apelul prin valoare
- suport de curs - II.2 Variabile externe şi domeniul de vizibilitate
III. Rezolvarea unor aplicaţii propuse

Tablouri şi funcţii
PCLP CURS 3 2

Afișarea unui tablou unidimensional: vector


#include <stdio.h>
int main() v[0] v[1] v[2] v[3] v[4] v[5] v[6]
{ 4 0 2 5 12 33 3
int v[7] = {4, 0, 2, 5, 12, 33, 3};
int i, n = 7;
for (i = 0; i < n; i++)
I. TABLOURI printf("v[%d]=%d\n", i, v[i]);
return 0;
}
PCLP CURS 3 3 PCLP CURS 3 4

Programul numără apariţiile:


1. fiecărei cifre (0, 1, 2, … , 9)
2. a caracterelor spaţii albe (blank, tab, LF) şi
3. a tuturor celorlalte caractere.

• Sunt 12 categorii de intrări:


 utilizăm un tablou (array) unidimensional care să
Aplicaţie memoreze numărul de apariţii ale fiecărei cifre
NUMĂRAREA APARIŢIILOR FIECĂREI (ndigit[10]) și
CIFRE, A CARACTERELOR ALBE ŞI A  două variabile simple (nwhite, nother) care să
memoreze numărul de apariţii a caracterelor albe,
TUTUROR CELORLALTE CARACTERE respectiv numărul de apariţii a celorlalte caractere
PCLP CURS 3 5 PCLP CURS 3 6

PCLP CURS 1 1
10/18/2015

#include <stdio.h> /* count digits, white space, others */


main()
{
Ieşirea acestui program atunci când intrarea • Contorizăm 12 categorii de intrări:
este programul însuşi este:
int c, i, nwhite, nother;
digits = 9 3 0 0 0 0 0 0 0 1,
1. fiecare din cele 10 cifre (0..9) cu 10 contoare:
int ndigit[10];
nwhite = nother = 0;
white space = 122, other = 345 ndigit[0], …, ndigit[9]
for (i = 0; i < 10; ++i) 1. caracterele spaţii albe (blank, tab, LF) cu 1 contor: nwhite
ndigit[i] = 0;
2. toate celelalte caractere cu 1 contor: nother
while ((c = getchar()) != EOF)
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
else if (c == ' ' || c == '\n' || c == '\t')
• Utilizăm un tablou: ndigit[10], care memorează
++nwhite; numărul de apariţii ale fiecărei cifre:
else
++nother;  ndigit[0] memorează numărul de apariţii ale cifrei 0
printf("digits =");
for (i = 0; i < 10; ++i)
…
printf(" %d", ndigit[i]);  ndigit[9] memorează numărul de apariţii ale cifrei 9
printf(", white space = %d, other = %d\n",nwhite, nother);
}
PCLP CURS 3 7 PCLP CURS 3 8

Declaraţia: int ndigit[10]; Întrebare


• declară ndigit ca un tablou de 10 întregi.
• în C indicii tablourilor pornesc de la 0, astfel că • De ce iniţializarea elementelor tabloului
elementele sunt: ndigit[] care memorează frecvenţele de
 ndigit[0], ndigit[1], ..., ndigit[9]. apariţie a fiecărei cifre se face cu 0 ?
• Acest lucru se vede clar în cele două cicluri for care
iniţializează: for (i = 0; i < 10; ++i)
for (i = 0; i < 10; ++i)
ndigit[i] = 0;
ndigit[i] = 0;
şi afişează tabloul:
for (i = 0; i < 10; ++i)
printf(" %d", ndigit[i]);
PCLP CURS 3 9 PCLP CURS 3 10

Răspuns Indicele unui tablou


• Indicele unui tablou poate fi orice expresie
• 0 este elementul neutru la adunare întreagă,
• aici incluzându-se
 variabile întregi ca i şi
 constante întregi.

• Exemple:
 ndigit[i]
 ndigit[7]
 ndigit[c-'0'], unde int c; este un
caracter din codul ASCII
PCLP CURS 3 11 PCLP CURS 3 12

PCLP CURS 1 2
10/18/2015

c-'0' Testul if (c >= '0' && c <= '9')


• c este un caracter din codul ASCII cu valori între
• determină dacă caracterul memorat de variabila c este o
0…255 cifră.
• Dacă c este un caracter cifră el va avea valori între:
• Dacă este cifră, valoarea numerică a acestei cifre este:
 48 (codul ASCII al lui ’0’) şi c - '0‘
 57 (codul ASCII al lui ’9’)
• Prin definiţie tipul char conţine întregi mici, astfel că
• Dacă scădem din valoarea lui c, valoarea 48, a  variabilele şi constantele de tip char sunt identice cu cele de
tip int în expresiile aritmetice.
caracterului ’0’, obţinem exact valoarea numerică
corespunzătoare caracterului cifră c. • De exemplu, c-'0' este o expresie întreagă cu o valoare
între 0 şi 9 corespunzând caracterului dintre '0' şi '9'
• Exemplu: dacă c este ‘7’ el va avea codul 55, dacă din stocat în c şi astfel este un indice valid pentru tabloul
55 scădem codul ASCII al lui ’0’ (i.e. 48) obţinem 7. ndigit.
PCLP CURS 3 13 PCLP CURS 3 14

Decizia asupra faptului că un caracter if (condiţie1) else if


instrucţiune1
este cifră, spaţiu alb sau altceva else if (condiţie2)
• Modelul din stânga apare frecvent
în programe ca o modalitate de a
instrucţiune2 exprima o decizie cu mai multe
... variante.
if (c >= '0' && c <= '9') ... • condiţiile sunt evaluate în ordine de
++ndigit[c-'0']; else sus până o anumită condiţie este
instrucţiunen satisfăcută;
else if (c == ' ' || c == '\n' || c == '\t') • în acel moment partea de
• Dacă nicio condiţie
++nwhite; instrucţiune corespunzătoare este
nu este satisfăcută, executată şi întreaga construcţie
else este executată este terminată.
++nother; instrucţiunea de • Orice instrucţiune poate fi
după ultimul else, reprezentată şi de mai multe
în caz că există. instrucţiuni incluse între acolade.
PCLP CURS 3 15 PCLP CURS 3 16

if (condiţie1)
instrucţiune1
• Dacă ultimul else şi instrucţiunea Instrucţiunea switch
de după el nu există, nu se face
else if (condiţie2) nimic.
instrucţiune2 • care va fi discutată ulterior, furnizează un alt mod
... • Pot fi oricâte grupuri de de a scrie o structură decizională cu multe
... else if(condiţie) ramificaţii,
else instrucţiune
instrucţiunen • dar ea este în special adecvată când condiţia
între if-ul iniţial şi else-ul final.
caută potrivirea unei expresii întregi sau caracter
• Se recomandă respectarea stilului de scriere a construcţiei
într-un set de constante.
cum s-a arătat mai sus;
• altfel dacă fiecare if ar fi fost indentat spre dreapta în • O versiune cu switch a programului anterior va
raport cu else-ul anterior, secvenţa de decizii s-ar fi fi prezentată când se va discuta instrucţiunea
întins mult spre marginea din dreapta a paginii. switch.
PCLP CURS 3 17 PCLP CURS 3 18

PCLP CURS 1 3
10/18/2015

Funcţii
• O funcţie furnizează un mod convenabil pentru a încapsula
anumite calcule şi apoi
• poate fi utilizată fără nicio grijă asupra modului cum a fost
implementată.
• Cu funcţii proiectate corect este posibil
 să ignori cum a fost realizată o sarcină;
 este suficient să ştii doar ce a fost realizat.
• C face utilizarea funcţiilor facilă, comodă şi eficientă;
II. FUNCŢII • de multe ori o funcţie mică face mai clară o bucată de cod.
• Până acum am utilizat doar funcţii predefinite furnizate de
limbaj, ca printf, getchar şi putchar ;
• acum vom învăţa să scriem propriile noastre funcţii.
PCLP CURS 3 19 PCLP CURS 3 20

#include <stdio.h>
SUMA A DOUĂ NUMERE
tipul valorii numele
int suma(int ,int ); /* prototipul functiei */
returnate funcţiei parametrii formali
int main() main: funcţie apelantă
{
apelul funcţiei suma de funcţie parametrii de intrare
int x, y, adunare;
x = 3;
parametrii actuali (efectivi) int suma(int a, int b)
y = 4; {
adunare = suma(x, y); parametrii actuali variabilă locală
printf("suma = %d\n",adunare); coincid cu cei formali
int s;
return 0; s = a + b; CORPUL FUNCŢIEI
}
ca
• număr, return s;
int suma(int a, int b)
{ • poziţie şi a, b suma suma
int s;
suma: funcţie apelată • tip de dată }
s = a + b;
NU coincid ca nume
return s; valoarea returnată de funcţie
}
PCLP CURS 3 21 PCLP CURS 3 22

#include <stdio.h> #include <stdio.h>


int suma(int ,int ); /* prototipul functiei */ int suma(int ,int ); /* prototipul functiei */
int main() 1. main: funcţie apel… int main() 1. main: funcţie apelantă
{ {
int x, y, adunare; int x, y, adunare; 2. apelul funcţiei suma
2. ... funcţiei suma
x = 3; x = 3;
y = 4; y = 4;
3. parametrii …. (…..) 3. parametrii actuali (efectivi)
adunare = suma(x, y); adunare = suma(x, y);
printf("suma = %d\n",adunare); printf("suma = %d\n",adunare);

}
return 0; Completaţi }
return 0;

int suma(int a, int b) spaţiile libere int suma(int a, int b)


{
int s;
4. suma: funcţie apel… {
int s;
4. suma: funcţie apelată Răspuns
s = a + b; s = a + b;
return s; return s;
} }
PCLP CURS 3 23 PCLP CURS 3 24

PCLP CURS 1 4
10/18/2015

Completaţi spaţiile libere 1. tipul valorii Răspuns


2. … 3. parametrii … returnate de funcţie 2. numele 3. parametrii formali
1. … funcţiei 4. parametrii de intrare
4. parametrii de …
int suma(int a, int b) int suma(int a, int b)
{ 5. variabilă ...
{ 5. variabilă locală
int s; int s;
s = a + b; 6. ... FUNCŢIEI s = a + b; 6. CORPUL FUNCŢIEI

return s; return s;
7.a,b 9.suma
8. suma
} 7. … 8. … 9. … }

10. … 10. valoarea returnată de funcţie


PCLP CURS 3 25 PCLP CURS 3 26

#include <stdio.h>
ÎNTREBARE int suma(int ,int ); /* prototipul functiei */

int main()
{
• Scrieţi un program care apelează o funcţie int x, y, adunare;
care calculează suma a două numere întregi x = 3;
y = 4;
adunare = suma(x, y);
printf("suma = %d\n",adunare);
return 0;
}

int suma(int a, int b)


{
int s;
s = a + b; RĂSPUNS
return s;
}
PCLP CURS 3 27 PCLP CURS 3 28

#include <stdio.h>
int power(int m, int n);
int main()
{
base, power power
int i; n
for (i = 0; i < 10; ++i)
printf("%d %d %d\n", i, power(2,i), power(-3,i));
return 0;
}
int power(int base, int n) /* power: raise base to n-th power; n >= 0 */

Aplicaţie {
int i, p; Programul conţine o funcţie
PROGRAM PENTRU RIDICAREA LA O p = 1;
power(m,n) pentru a ridica
un întreg m la o putere întreagă
for (i = 1; i <= n; ++i)
PUTERE ÎNTREAGĂ POZITIVĂ p = p * base;
pozitivă n. Adică valoarea
returnată de power(2,5)
return p;
} este 32.

PCLP CURS 3 29 PCLP CURS 3 30

PCLP CURS 1 5
10/18/2015

Forma definiţiei unei funcţii Apelul funcţiei power


tipul-valorii-returnate nume-funcţie(declaraţii de parametrii)
{ • Funcţia power este apelată de 2 ori de main, în
declaraţii linia:
instrucţiuni printf("%d %d %d\n", i, power(2,i), power(-3,i));
}
• Declaraţiile funcţiilor pot apărea în orice ordine, • Fiecare apel transmite 2 argumente către power,
într-un fişier sursă sau în mai multe, de fiecare dată se returnează un întreg pentru a fi
• deşi nici o funcţie nu poate fi ruptă între mai multe formatat şi afişat.
fişiere.
• Într-o expresie, power(2,i) este un întreg ca şi
• Pentru moment vom presupune că funcţiile sunt în 2 şi ca şi i.
acelaşi fişier.
PCLP CURS 3 31 PCLP CURS 3 32

int power(int base, int n) int power(int base, int n)


• Alte funcţii pot utiliza aceleaşi nume (base, n) fără să
• Prima linie a funcţiei power, declară: apară niciun conflict.
 tipurile parametrilor funcţiei (int, int)şi • Acest lucru este valabil şi pentru variabilele i şi p:
 variabila i din power nu are nicio legătură cu variabila i
 numele lor (base, n), precum şi din main.
 tipul rezultatului returnat de funcţie (int).
• parametru este sinonim cu argument
• şi se referă la numele variabilei din lista pusă între
• Numele utilizate de power pentru parametrii
paranteze rotunde după numele funcţiei.
săi (base, n) sunt locali funcţiei power,
• Un argument poate fi:
 ei nu sunt vizibili pentru alte funcţii.  formal
 actual (sau efectiv).
PCLP CURS 3 33 PCLP CURS 3 34

printf("%d %d %d\n", i, power(2,i), power(-3,i));


int power(int base, int n)
• În linia din main care apelează de 2 ori funcţia
• În prima linie a funcţiei power, base şi n sunt power,
parametrii (argumente) formali,  2 şi i, respectiv
 -3 şi i
• adică parametrii cu care funcţia a fost definită. • sunt parametrii actuali / argumente actuale
• adică valorile cu care funcţia este apelată.

• Uneori în loc de parametru/argument actual se


foloseşte expresia parametru/argument efectiv.
PCLP CURS 3 35 PCLP CURS 3 36

PCLP CURS 1 6
10/18/2015

Parametru /argument actual şi formal Completaţi spaţiile libere

• Parametrii actuali (efectivi) şi cei formali • Parametrii actuali (efectivi) şi cei formali
trebuie să corespundă ca trebuie să corespundă ca
 poziţie,  ……….,
 număr şi  ………… şi
 tip de dată.  …………...

• Parametrii actuali (efectivi) substituie la apel • Parametrii … (...) substituie la apel parametrii
parametrii formali. ………. .

PCLP CURS 3 37 PCLP CURS 3 38

return expresie;
Răspuns
• Valoarea pe care funcţia power o calculează este
• Parametrii actuali (efectivi) şi cei formali returnată funcţiei main prin instrucţiunea
trebuie să corespundă ca return.
 poziţie, • După return poate urma orice expresie
 număr şi • Nu este obligatoriu ca o funcţie să returneze o
 tip de dată. valoare.
• Să observăm că există o instrucţiune return la
• Parametrii actuali (efectivi) substituie la apel finalul lui main.
parametrii formali. • Deoarece main este o funcţie ca oricare alta, ea
poate returna o valoare către apelantul său aflat în
mediul în care programul a fost executat.
PCLP CURS 3 39 PCLP CURS 3 40

main() : return 0; Prototipul funcţiei


• De obicei, returnarea valorii 0 presupune o
int power(int base, int n);
terminare normală a programului; • Declaraţia int power(int base, int n);
• valori non-zero semnalizează condiţii de • plasată chiar înaintea lui main spune că power este
terminare neobişnuite sau cu erori. o funcţie care:
• În exemple anterioare, din motive de simplitate  aşteaptă două argumente de tip int şi
funcţia main nu avea o instrucţiune return,  returnează un int.
• dar ea va apărea în toate programele ulterioare • Această declaraţie, numită prototipul funcţiei, trebuie
pentru că programele trebuie să returneze starea să fie în conformitate cu definiţia şi utilizarea lui
către mediile în care au fost lansate. power.
PCLP CURS 3 41 PCLP CURS 3 42

PCLP CURS 1 7
10/18/2015

Prototipul funcţiei
• Se semnalează eroare dacă definiţia unei funcţii sau
orice utilizare a ei nu este în conformitate cu
prototipul său.
• Numele parametrilor nu trebuie să se conformeze.
• Numele parametrilor sunt opţionali în prototipul
funcţiei, aşa că pentru prototip putem scrie şi aşa: II.1 APELUL PRIN VALOARE
int power(int, int);

PCLP CURS 3 43 PCLP CURS 3 44

În C toate argumentele sunt transmise /* power: raise base to n-th power; n >= 0; version 2 */

funcţiilor prin valoare int power(int base, int n)


{ Parametrul n este utilizat ca o variabilă tempo-
• Adică funcţia apelată dă valorile argumentelor
int p; rară, el numărând înapoi în ciclul for până când
sale unor variabile temporare cu care lucrează, devine zero; se elimină necesitatea variabilei i.
lăsând nemodificate originalele.
for (p = 1; n > 0; --n)
• Apelul prin valoare este un avantaj, nu o datorie. p = p * base;
• El conduce de obicei la programe mai compacte return p;
cu mai puţine variabile străine, deoarece } Tot ceea ce este făcut asupra lui n în interiorul funcţiei power
parametrii pot fi trataţi ca variabile locale nu are niciun efect asupra argumentului n original cu care
iniţializate convenabil în funcţiile apelate. power a fost apelată.
PCLP CURS 3 45 PCLP CURS 3 46

Parametrii adresă Tablouri ca parametrii


• Uneori este necesar ca o funcţie să modifice o
variabilă din funcţia apelantă. • Când numele unui tablou este utilizat ca
argument, valoarea transmisă funcţiei apelate
• Apelantul trebuie atunci să furnizeze adresa este locaţia sau adresa de început a tabloului,
variabilei care trebuie modificată (tehnic vorbind nu se face o copie a elementelor tabloului.
este vorba de un pointer la variabilă),
• Utilizând această valoare, funcţia poate accesa şi
• iar funcţia apelată trebuie să declare parametrul modifica orice argument din tablou.
ca fiind un pointer şi să acceseze variabila indirect • Despre aceste lucruri se va vorbi în continuare.
prin intermediul lui.
PCLP CURS 3 47 PCLP CURS 3 48

PCLP CURS 1 8
10/18/2015

Aplicaţie

III. TABLOURI DE CARACTERE AFIŞAREA CELEI MAI LUNGI LINII


CITITE PE INTRARE

PCLP CURS 3 49 PCLP CURS 3 50

Tablouri de caractere Schiţa programului este destul de simplă


while (este o linie nouă)
• Numite şi şiruri de caractere if (lungimea ei > lungimea celei mai lungi linii anterioare)
• Cel mai uzual tip de tablou în C salveaz-o
salvează-i lungimea
• Programul următor ilustrează utilizarea:
afişează cea mai lungă linie
 tablourilor de caractere şi
 a funcţiilor care le manipulează. Schemă arată că programul se poate împărţi
natural în bucăţi:
• El citeşte o mulţime de linii de text şi o afişează pe o bucată obţine o line nouă
cea mai lungă. o alta o salvează
restul controlează procesul.
PCLP CURS 3 51 PCLP CURS 3 52

Funcţia getline Funcţia getline


• Funcţia getline încărcă o linie nouă a intrării.
• 0 este o valoare acceptabilă pentru a fi
• Ar trebui ca funcţia să fie utilă şi în alte contexte. returnată
 deoarece ea nu poate fi niciodată o lungime
• Minim minimorum getline trebuie să returneze validă pentru o linie.
un semnal despre un posibil sfârşit de fişier;
• Orice linie de text are cel puţin 1 caracter.
• o proiectare mai utilă trebuie să returneze
 lungimea liniei, sau
• Chiar şi o linie conţinând numai 1 caracter
 0 dacă este întâlnit un sfârşit de fişier.
newline are lungimea 1.
PCLP CURS 3 53 PCLP CURS 3 54

PCLP CURS 1 9
10/18/2015

/* getline: read a line into s, return length */


Funcţia getline int getline(char s[],int lim)
Citeşte o linie de text de pe intrare { int getline(char s[], int lim) spune că primul
int c, i; argument, s, e un tablou, iar al doilea, lim, e un întreg.
şirul (linia de pe intrare) curent citit
for(i=0;i<lim-1&&(c=getchar())!=EOF&&c!='\n‘;++i)
s[i] = c; Scopul furnizării mărimii unui tablou într-o
if (c == '\n') { declaraţie este de a stabili dimensiunea
s[i] = c; spaţiului în care va fi stocat. Mărimea
++i; lungimii tabloului s[] nu este necesară în
getline deoarece mărimea sa a fost
} stabilită în declaraţia
s[i] = '\0'; char line[MAXLINE];
return i; din main (vezi acolo)
Lungimea maximă a lungimii lungimea şirului (liniei de
unei linii citite pe intrare pe intrare) curent citit
}
getline utilizează return pentru a trimite valoarea
lungimii şirului curent citit, înapoi la funcţia apelantă main.

PCLP CURS 3 55 PCLP CURS 3 56

Funcţia copy Funcţia copy


• Când găsim o linie mai lungă decât cea mai lungă
şirul de caractere în care s-a
linie anterioară, salvat linia curentă pentru o
 trebuie să o salvăm undeva, pentru că posibilă afişare viitoare
 în final cea mai lungă linie va trebui afişată, iar
 în tabloul ce conţine linia curentă vom citi în
continuare următoarea linie.

• Aceasta sugerează existenţa unei a doua funcţii:


copy şirul de caractere care conţine linia
 pentru a copia linia nouă (din from) la un loc curentă care se doreşte salvată
sigur (în to).
PCLP CURS 3 57 PCLP CURS 3 58

STRUCTURA PROGRAMULUI
/* copy: copy 'from' into 'to'; assume to is big enough */
#include <stdio.h>
void copy(char to[], char from[]) #define MAXLINE 1000/* maximum input line length */
{
int getline(char line[], int maxline);
int i; void copy(char to[], char from[]);
Funcţiile getline şi copy sunt declarate
i = 0; main()
la începutul programului, care presupunem
{…} că este conţinut într-un singur fişier.
while ((to[i] = from[i]) != '\0')
++i; int getline(char s[],int lim)
{…}
} copy se bazează pe faptul că argumentul său de intrare (char
from[]) este terminat cu un '\0' şi copiază acest caracter pe void copy(char to[], char from[])
ieşire (char to[]). {…}
PCLP CURS 3 59 PCLP CURS 3 60

PCLP CURS 1 10
10/18/2015

/* print the longest input line */


Funcţia main main()
{
main şi getline comunică printr-o pereche de
argumente (line, MAXLINE) şi o valoare returnată (len).
int len; /* current line length */
• Avem nevoie de funcţia main care să int max; /* maximum length seen so far */
char line[MAXLINE]; /* current input line */
controleze funcţiile: char longest[MAXLINE];/* longest line saved here */
 getline şi max = 0;
 copy. while ((len = getline(line, MAXLINE)) > 0)
if (len > max) {
max = len;
copy(longest, line);
}
if (max > 0) /* there was a line */
printf("%s", longest);
return 0;
}
PCLP CURS 3 61 PCLP CURS 3 62

int getline(char s[], int lim) void copy(char to[], char from[])
• Unele funcţii returnează valori utile.
• Această linie spune că primul argument formal, s,
e un tablou, iar al doilea, lim, e un întreg. • Altele, precum copy, sunt utilizate numai pentru
ceea ce fac şi nu returnează nicio valoare.
• Declară că getline returnează un int
• Deoarece int este tipul implicit returnat, el putea • Tipul returnat de copy este void, care afirmă
explicit că nu este returnată nicio valoare.
fi omis.
• Adică linia • Cu toate acestea, funcţia returnează către main şirul
int getline(char s[], int lim) to[] în care a copiat şirul from[], dar prin
intermediul parametrilor de ieşire - de tip adresă -
• putea fi substituită de linia adrese care, în cazul tablourilor, sunt tot una cu
getline(char s[],int lim) numele lor.
PCLP CURS 3 63 PCLP CURS 3 64

În getline : s[i] = '\0‘;


• getline pune caracterul '\0' (null character, a În main: printf("%s", longest);
cărui valoare ASCII e 0) la finalul tabloului de
caractere, la crearea lui, pentru a marca finalul şirului • Specificatorul de format %s din printf este
de caractere.
pus în corespondenţă cu un argument care
• Această conversie este utilizată de asemenea de trebuie să fie un şir de caractere (longest)
limbajul C: când o constantă şir, de exemplu, ce va fi reprezentat în acest format.
"hello\n" h e l l o \n \0
• apare într-un program C, ea este stocată ca un tablou
de caractere conţinând caracterele şirului şi
terminându-se cu un '\0' pentru a marca finalul
acestui şir de caractere.
PCLP CURS 3 65 PCLP CURS 3 66

PCLP CURS 1 11
10/18/2015

Probleme de proiectare Probleme de proiectare


• Ce trebuie să facă main dacă întâlneşte o linie care • Nu există o modalitate pentru utilizatorul funcţiei
este mai mare decât limita sa?
getline să ştie în avans cât de lungă ar putea fi
• getline lucrează în siguranţă, prin aceea că
opreşte culegerea caracterelor când tabloul este o linie pe care o citeşte,
plin, chiar dacă nici un caracter newline nu a fost  aşa că getline verifică depăşirea.
găsit. • Pe de altă parte, s-a considerat că utilizatorul
• Testând lungimea şi ultimul caracter returnat main funcţiei copy deja ştie (sau poate afla) cât de
poate determina dacă linia a fost prea lungă şi apoi mari sunt şirurile de caractere,
face aşa cum doreşte.
 astfel că în programul prezentat s-a ales să nu se
• Dar din motive de concizie, această testare a fost
adauge verificări ale erorilor.
ignorată.
PCLP CURS 3 67 PCLP CURS 3 68

EXEMPLIFICARE CU “AFIŞAREA
II.2 VARIABILE EXTERNE ŞI CELEI MAI LUNGI LINII CITITE PE
DOMENIUL DE VIZIBILITATE INTRARE”

PCLP CURS 3 69 PCLP CURS 3 70

main() int getline(char s[],int lim)


{ Acelaşi lucru este valabil şi
variabilele din main, cum ar fi {
pentru variabilele din alte
int len; len, max, line, longest int c, i;
int max;
funcţii.
sunt private sau locale funcţiei
char line[MAXLINE]; for(i=0;i<lim-1&&(c=getchar())!=EOF&&c!='\n‘;++i)
main.
char longest[MAXLINE];
s[i] = c; Variabila i din getline nu
max = 0; if (c == '\n') { are absolut nicio legătură
while ((len = getline(line, MAXLINE)) > 0) s[i] = c; cu variabila i din copy.
if (len > max) { ++i;
max = len; } void copy(char to[], char from[])
copy(longest, line); Deoarece ele sunt în {
s[i] = '\0'; int i;
} interiorul funcţiei
if (max > 0) return i;
main, nici o altă i = 0;
printf("%s", longest); }
funcţie nu poate avea while ((to[i] = from[i]) != '\0')
return 0; ++i;
} acces direct la ele. }

PCLP CURS 3 71 PCLP CURS 3 72

PCLP CURS 1 12
10/18/2015

Variabile automate Variabile automate


• Fiecare variabilă locală dintr-o funcţie • Ulterior vom discuta clasa de memorare static
 apare numai când funcţia este apelată şi  în care variabilele locale îşi păstrează valorile lor
 dispare când se iese din funcţie. între apeluri.

• Acesta este motivul pentru care astfel de variabile • Deoarece variabilele automate apar şi dispar la
sunt numite de obicei variabile automate apelul funcţiei:
(automatic variables) urmând terminologia din  ele nu reţin valorile lor între două apeluri ale funcţiei
alte limbaje de programare.  trebuie să fie setate explicit la fiecare intrare.

• Vom utiliza termenul automat de aici înainte • Dacă ele nu sunt setate, aceste variabile vor
pentru a ne referi la aceste variabile locale. conţine resturi de memorie (garbage).
PCLP CURS 3 73 PCLP CURS 3 74

Variabile externe Variabile externe


• Ca o alternativă la variabilele automate, este • Mai mult, datorită faptului că variabilele externe
posibil să definim variabile care sunt externe continuă să existe permanent,
tuturor funcţiilor, adică,  chiar dacă funcţiile care le utilizează sunt apelate şi
se termină,
 variabile care pot fi accesate prin nume de orice
funcţie.  ele reţin valorile lor chiar după ce funcţiile care le-au
modificat le-au returnat.
• Deoarece variabilele externe sunt accesibile
global, • O variabilă externă trebuie definită o singură
dată, în afara oricărei funcţii;
 ele pot fi utilizate în locul listei de argumente
 această declarare pune deoparte un spaţiu de
 pentru a comunica date între funcţii.
stocare pentru ea.
PCLP CURS 3 75 PCLP CURS 3 76

Variabile externe Completaţi spaţiile libere


• Variabila trebuie de asemenea declarată în 1. O variabilă locală dintr-o funcţie care apare
fiecare funcţie care doreşte să o acceseze; numai când funcţia este apelată şi dispare când
 aceasta specifică tipul variabilei. se iese din funcţie se numeşte variabilă ………….

• Declaraţia poate fi 2. O variabilă care este accesibilă tuturor


 o instrucţiune explicită folosind cuvântul cheie funcţiilor şi îşi reţine valoarea chiar după ce
extern sau funcţiile care au modificat-o au returnat-o se
 poate fi implicită din context. numeşte variabilă ………….

PCLP CURS 3 77 PCLP CURS 3 78

PCLP CURS 1 13
10/18/2015

Răspunsuri

1. automată

2. externă
Aplicaţie

AFIŞAREA CELEI MAI LUNGI LINII


CITITE PE INTRARE (VERSIUNEA 2)

PCLP CURS 3 79 PCLP CURS 3 80

/* print longest input line; specialized version */


Linia de lungime maximă main()
{
int len;
• Reluăm programul care afişează linia de lungime extern int max;
maximă într-o versiune nouă, extern char longest[];
 în care line, longest şi max sunt variabile max = 0;
externe. while ((len = getline()) > 0)
if (len > max) {
max = len;
• Acest lucru presupune modificări ale copy();
 apelurilor, }
if (max > 0) /* there was a line */
 declaraţiilor şi printf("%s", longest);
 corpurilor celor trei funcţii. return 0;
}
PCLP CURS 3 81 PCLP CURS 3 82

/* getline: specialized version */


/* copy: specialized version */
int getline(void)
{ void copy(void)
int c, i;
extern char line[]; {
int i;
for (i = 0; i < MAXLINE – 1 && (c=getchar)) !=
EOF && c != '\n'; ++i) extern char line[], longest[];
line[i] = c;
if (c == '\n') {
line[i] = c;
++i; i = 0;
} while ((longest[i] = line[i]) != '\0')
line[i] = '\0';
return i; ++i;
}
}
PCLP CURS 3 83 PCLP CURS 3 84

PCLP CURS 1 14
10/18/2015

#include <stdio.h>
Variabile externe
#define MAXLINE 1000 /* maximum input line size */
• Din punct de vedere sintactic, definirile de variabile
int max; /* maximum length seen so far */
externe
char line[MAXLINE]; /* current input line */
char longest[MAXLINE]; /* longest line saved here */  sunt exact ca şi definiţiile de variabile locale, dar
 datorită faptului că ele apar în afara funcţiilor, variabilele
int getline(void);
sunt externe.
void copy(void);
Variabilele externe din • Înainte ca o funcţie să poată utiliza, în partea sa de
main() main, getline şi copy
{…} instrucţiuni, o variabilă externă,
Se specifică tipul lor şi se  numele variabilei trebuie să fie făcut cunoscut funcţiei în
int getline(void) determină să le fie alocat
partea sa de declaraţii;
{…} spaţiu de stocare.
void copy(void) • declaraţia este asemănătoare cu cea anterioară cu
{…} excepţia faptului că apare cuvântul cheie extern.
PCLP CURS 3 85 PCLP CURS 3 86

Variabile externe Mai multe fişiere sursă


• În anumite circumstanţe, declaraţia cu extern în
interiorul funcţiilor poate fi omisă.
Dacă programul este plasat în câteva fişiere sursă şi
• Dacă definiţia variabilei externe apare în fişierul sursă
înainte de utilizarea sa într-o oarecare funcţie,  o variabilă este definită în fişier1 şi
 nu este nevoie de o declaraţie cu extern în funcţie.
 utilizată în fişier2 şi în fişier3,
• Deci declaraţiile cu extern în exemplul anterior în
funcţiile main, getline şi copy sunt din acest motiv  atunci declaraţiile extern sunt necesare
redundante.  în fişier2 şi
• În fapt, practica comună este:  în fişier3
 să plasăm definiţiile tuturor variabilelor externe la începutul
fişierului sursă şi  pentru a conecta apariţiile variabilei.
 să omitem toate declaraţiile de variabile externe din interiorul
funcţiilor.
PCLP CURS 3 87 PCLP CURS 3 88

Mai multe fişiere sursă Listă explicit vidă de argumente


• Practica comună este să se colecteze declaraţiile • Datorită faptului că în program funcţiile getline şi
extern ale variabilelor şi funcţiilor în fişiere copy nu au niciun argument, logic ar fi ca
separate, prototipurile lor de la începutul fişierului sursă să fie
de forma int getline(void);
 numite header, care getline() void copy(void);
 sunt incluse prin directiva #include la începutul şi
fiecărui fişier sursă. copy()
• Extensia .h este prin convenţie asociată cu • dar compilatorul întâlnind o listă vidă invalidează
fişierele header verificarea listei de argumente.
• De exemplu, funcţiile din biblioteca standard • Din acest motiv cuvântul cheie void trebuie utilizat
sunt declarate în headere ca <stdio.h>. pentru a preciza o listă explicit vidă de argumente.
PCLP CURS 3 89 PCLP CURS 3 90

PCLP CURS 1 15
10/18/2015

Definire şi Declarare Variabile extern


• Trebuie să observăm că am utilizat termenii
definire şi declarare asociaţi cu o oarecare • Există o tendinţă să se lucreze numai cu variabile
subtilitate când ne-am referit la variabilele extern deoarece se pare că
externe.  se simplifică comunicarea,
• DEFINIREA se referă la locul unde variabila este  lista de argumente este scurtă şi
creată sau i se asociază spaţiu de stocare în  variabilele sunt totdeauna acolo unde le vrei.
memoria calculatorului.
• DECLARAREA se referă la locurile unde este • Dar variabilele externe sunt totdeauna acolo
specificată natura variabilei, dar nu i se aloca chiar şi atunci când nu le doreşti.
spaţiu de memorie.
PCLP CURS 3 91 PCLP CURS 3 92

Variabile extern Versiunea 2 vs. Versiunea 1


• Versiunea 2 a programului este inferioară celei
• A te baza prea mult pe variabilele externe este
dintâi,
periculos deoarece
 pe de-o parte datorită motivelor expuse anterior,
 aceasta conduce la programe ale căror conexiuni  pe de altă parte deoarece ea distruge generalitatea
între date nu sunt toate evidente celor două funcţii extrem de utile
 variabilele pot fi modificate în moduri • scriind în ele numele variabilelor pe care le
neaşteptate sau accidentale şi
manipulează
 programul este apoi greu de reparat.  funcţiile nu mai pot fi utilizate şi
 în alte contexte
 pentru alte variabile
PCLP CURS 3 93 PCLP CURS 3 94

REZOLVAREA UNOR APLICAŢII PROPUSE SUBSTITUIRE TAB-URI CU


BLANK-URI

PCLP CURS 3 95 PCLP CURS 3 96

PCLP CURS 1 16
10/18/2015

Scrieţi o funcţie detab care înlocuieşte caracterele tab


din intrare cu un număr corespunzător de blank-uri pentru
a lăsa spaţiu corespunzător până la următoarea poziţie de
tabulare (tab stop).
Presupunem
că la fiecare
tab
corespunde
un număr fix
blank-uri.

PCLP CURS 3 97 PCLP CURS 3 98

#include <stdio.h> Structura programului int main(void)


{
#define MAXLINE 1000
#define TAB_WIDTH 6 /* un tab stop la 6 char s1[MAXLINE];
spatii */ char s2[MAXLINE];
int getchars(char s[], int maxline); printf(“caractere si tab-uri, apoi Enter:\n");
void detab(char s1[], char s2[], int while (getchars(s1, MAXLINE) == 0)
tabwidth); ; cât timp nu se citeşte nimic se reia citirea
int main(void) detab(s1, s2, TAB_WIDTH);
{ … } printf("rezultatul substituirii:\n");
int getchars(char s[], int lim) printf("123456789012345678901234567890\n");
{ … } printf("%s\n", s2);
return 0;
void detab(char s1[], char s2[], int w)
}
{ … }
PCLP CURS 3 99 PCLP CURS 3 100

int getchars(char s[], int lim) void detab(char s1[], char s2[], int w)
{
{ int i, j, l, c, blanks; blanks:
int c, i, l; numărul de
i = 0; /* contorul lui s1[] */
blank-uri ce
l = 0; /* contorul lui s2[] */
while ((c = s1[i++]) != '\0') { substituie
for (i = 0, l = 0; (c = getchar()) tab-ul
if (c == '\t') {
!= EOF && c != '\n'; ++i)
blanks = w - l % w;
if (i < lim - 1) for (j = 0; j < blanks; ++j)
s[l++] = c; s2[l++] = ' ';
Se pun caractere în s[]
} else {
s[l] = '\0'; cât timp i < MAXLINE
s2[l++] = c; Se copiază caracterele din
din acel moment l nu
} s1[] în s2[] înlocuind
mai creşte, dar
return l; } fiecare tab cu un număr
caractere se citesc în
s2[l] = '\0'; corespunzator de blank-uri
} continuare
}
PCLP CURS 3 101 PCLP CURS 3 102

PCLP CURS 1 17
10/18/2015

• Scrieţi un program entab care înlocuieşte


şirurile de blank-uri cu un număr minim de
tab-uri şi blank-uri (în cazul în care deşi apar
spaţii ele nu sunt până la poziţia de tabulare)
pentru a obţine aceiaşi spaţiere.
Aplicaţie

ÎNLOCUIREA BLANK-URILOR CU UN
NUMĂR MINIM DE
TAB-URI ŞI BLANK-URI
PCLP CURS 3 103 PCLP CURS 3 104

#include <stdio.h> int main(void)


{
#define MAXLINE 1000 char s1[MAXLINE];
#define TAB_WIDTH 6 char s2[MAXLINE];

int main(void) while (getchars(s1, MAXLINE) == 0)


{ … } ;
int getchars(char s[], int lim)
entab(s1, s2, TAB_WIDTH);
{ … }
printf(“substitui spatii:\n%s\n", s2);
void entab(char s1[], char s2[], int w)
{ … } return 0;
}
PCLP CURS 3 105 PCLP CURS 3 106

int getchars(char s[], int lim) /* copiaza caracterele din s1 in s2 si inlocuieste spatiile cu tab-uri */
void entab(char s1[], char s2[], int w)
{ {
int c, i, l; int i, j, l, c, blanks;
int blanksenough;
for (i = 0, l = 0; (c = getchar()) /* ia valorile 1 sau 0 dupa cum in momentul intalnirii unui spatiu dupa el
sunt numai spatii pana la urmatorul tab stop, sau nu */
!= EOF && c != '\n'; ++i)
if (i < lim - 1) i = 0; /* contorul lui s1[] */
l = 0; /* contorul lui s2[] */
s[l++] = c;
while ((c = s1[i]) != '\0') {
s[l] = '\0'; if (c == ' ') {/* la intalnirea unui spatiu in s1 */
blanksenough = 1;
return l; /* consideram ca exista numai spatii pana urmatorul tab stop */
} blanks = w - i % w;
/* calculam cate spatii ar trebui sa fie pana la urmatorul tab stop */

PCLP CURS 3 107 PCLP CURS 3 108

PCLP CURS 1 18
10/18/2015

for (j = 1; j < blanks && blanksenough; ++j)


/* verificam daca sunt in continuare spatii suficiente pana la urmatorul tab stop */
if (s1[i + j] != ' ')
blanksenough = 0;
if (blanksenough) { /* daca putem substitui spatiile cu un tab */
s2[l++] = '\t'; /* punem in s2[] un tab */
i += blanks - 1; /* contorul lui s1[] sare spatiile substituite de tab */
} else {
s2[l++] = c; /* daca nu putem substitui spatiile din s1 cu un tab in s2 */
} /* punem in s2 spatiile (insuficiente pentru tab) din s1 */
} else Aplicaţie
s2[l++] = c; /* daca nu am avut blank in s1, in s2 se pune caracterul din s1 */
++i; /* trecem la urmatorul caracter din s1[] */ ÎNDEPĂRTAREA TUTUROR
}
s2[l] = '\0'; /* finalizam cu \0 sirul s2[] */ COMENTARIILE DINTR-UN PROGRAM C
}

PCLP CURS 3 109 PCLP CURS 3 110

#include <stdio.h>

#define MAXLENGTH 1000


• Scrieţi un program pentru a îndepărta toate
comentariile dintr-un program C.
int getline(char s[], int max);
• Comentariile din C nu sunt imbricate.
int main(void)
{ … }

int getline(char s[], int lim)


{ … }

PCLP CURS 3 111 PCLP CURS 3 112

int main(void)
{ int getline(char s[], int lim)
int len, i;
char s[MAXLENGTH]; {
while ((len = getline(s, MAXLENGTH)) > 0) { int c, i, l;
printf("\nRezultat:\n");
i = 0;
while (s[i] != '\0') {
if (s[i] == '/' && s[i+1] == '*') { for (i = 0, l = 0; (c = getchar()) != EOF; ++i)
i += 2;
while (s[i] != '\0' && s[i+1] != '\0' && (s[i] != '*' || s[i+1] != '/'))
if (i < lim - 1)
++i; s[l++] = c;
if (s[i] != '\0' && s[i+1] == '\0')
++i; s[l] = '\0';
if (s[i] == '*' && s[i+1] == '/’)
i += 2;
} else
putchar(s[i++]);
return l;
}
}
}
return 0;
}

PCLP CURS 3 113 PCLP CURS 3 114

PCLP CURS 1 19
10/18/2015

• Scrieţi un program pentru a verifica un


program C pentru erori de sintaxă rudimentare
cum ar fi:
 paranteze rotunde,
 pătrate şi
 acolade care nu se închid corect.
Aplicaţie • Nu uitaţi de ghilimele, apostrofuri, secvenţe
VERIFICAREA ERORILOR DE escape şi comentarii.
SINTAXĂ DINTR-UN PROGRAM

PCLP CURS 3 115 PCLP CURS 3 116

#include <stdio.h>
if (c == '/') {
#define NOTHING 0 do
#define COMMENT 1
#define DOUBLE_QUOTE 2
if ((c = getchar()) == '*')
#define SINGLE_QUOTE 3 state = COMMENT;
while (c == '/');
int line;
void print_error (char s[]); }
else {
int main ()
if (c == '\"')
{
int state, parentheses, brackets, braces, c; state = DOUBLE_QUOTE;
line = 1; else if (c == '\'')
state = NOTHING;
state = SINGLE_QUOTE;
parentheses = brackets = braces = 0; /* ( [ { */ else if (c == '\n')
while ((c = getchar()) != EOF) line++;
if (state == NOTHING) {

PCLP CURS 3 117 PCLP CURS 3 118

else if (c == '(') else if (c == '{')


braces++;
parentheses++;
else if (c == '}') {
else if (c == ')') { if (--braces < 0) {
if (--parentheses < 0) { print_error("paranteze {} inchise incorect");
print_error(" paranteze () inchise incorect"); return -1;
return -1; }
} }
} }
}
else if (c == '[')
else if (state == COMMENT) {
brackets++; if (c == '\n')
else if (c == ']') { line++;
if (--brackets < 0) { else
print_error("parenteze [] inchise incorect"); while (c == '*')
return -1; if ((c = getchar()) == '/')
} state = NOTHING;
}
}
PCLP CURS 3 119 PCLP CURS 3 120

PCLP CURS 1 20
10/18/2015

else { if (state == COMMENT) {


if (c == '\n') { print_error("Comentariu neterminat");
print_error("Caracter newline in return -1;
interiorul apostroafelor sau
ghilimelelor"); }
return -1; else if (state == DOUBLE_QUOTE ||
} state == SINGLE_QUOTE) {
else if (c == '\\') print_error("Ghilimele sau
c = getchar(); apostrofuri neterminate");
else if (state == DOUBLE_QUOTE && c == return -1;
'\"' || state == SINGLE_QUOTE && c == } else
'\'')
return 0;
state = NOTHING;
} }

PCLP CURS 3 121 PCLP CURS 3 122

#include <stdio.h>
void print_error(char s[])
{ #define NOTHING 0
#define COMMENT 1
printf("Eroare (%d): %s!\n", #define DOUBLE_QUOTE 2
line, s); #define SINGLE_QUOTE 3
} int line;
void print_error (char s[]);
int main ()
{…}
void print_error(char s[])
{…}

PCLP CURS 3 123 PCLP CURS 3 124

Bibliografie

[1] Brian Kernighan, Dennis Ritchie, The C


Programming Language, ediţia a II-a, Ed.
Prentice Hall, 1988.

PCLP CURS 3 125

PCLP CURS 1 21

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