Sunteți pe pagina 1din 10

Valeriu Iorga 8. Tablouri i pointeri. 8.1. Tablouri cu o dimensiune (vectori).

Programare n C / C++

Un tablou cu o singur dimensiune este o succesiune de variabile avnd toate de acelai tip (tipul de baz al tabloului), care ocup o zon contigu de memorie. Un tablou are: o dimensiune (egal cu numrul de elemente al tabloului) un nume (care identific global tabloul) o clas de alocare un tip comun tuturor elementelor tabloului Dimensiunea tabloului precizeaz numrul de elemente printr-o constant ntreag sau printr-o expresie constant. La declararea unui tablou se specific: numele, tipul de baz, clasa de alocare i dimensiunea. tip nume[dimensiune]; sau clas tip nume[dimensiune]; Exemple: int x[10]; char litere[2*26]; definit. /* tablou de 10 intregi */ /* tablou de 52 caractere */

Tipul elementelor tabloului poate fi un tip fundamental, enumerat, inregistrare, pointer sau un tip

Numele tabloului este adresa primului element din tablou (de exemplu x este adresa primului element, adic @x[0] ). Aceasta explic de ce nu este permis o atribuire ntre dou tablouri. Accesul la un element din tablou se face printr-o variabil indexat, format din numele tabloului i un index - o expresie cuprins ntre 0 i dimensiune-1. Primul element va fi desemnat aadar prin x[0], al doilea element prin x[1],al N-lea prin x[N1] Un tablou declarat n interiorul unei funcii are implicit clasa auto, n timp ce tablourile declarate n exteriorul tuturor funciilor au n mod implicit clasa extern. Un tablou declarat n exteriorul tuturor funciilor cu specificatorul static este alocat la adrese fixe, fiind vizibil numai n fiierul n care este declarat. Un tablou declarat n interiorul unei funcii cu specificatorul static este alocat la adrese fixe, fiind vizibil numai n interiorul funciei. Prelucrrile pe tablouri se implementeaz cu cicluri for. Exemplul 15: S se afieze elementele unui tablou citit de la intrarea standard, cte 10 pe un rnd. #include <stdio.h> void main(void) /* citirea si afisarea elementelor unui vector */ { int x[10], n, j; scanf(%d, &n); for (j=0; j < n; j++) scanf(%d, &x[j]); for (j=0; j < n; j++) printf(%5d%c, x[j],(j%10==9||j==n-1)?\n: ); } La declararea unui tablou, acesta poate fi i iniializat, dac declaraia este urmat de semnul = i de o list de valori iniiale, separate prin virgule i incluse ntre acolade. Exemple: int prime[5]={2,3,5,7,11};

Valeriu Iorga

Programare n C / C++

char vocale[5]={a,e,i,o,u}; La declararea unui tablou iniializat se poate omite dimensionarea, situaie n care se ia ca dimensiune numrul de valori iniiale: char operator[]={+,-,*,/}; long x[]={1,10,100,1000,10000,100000}; Tablourile vor avea 4, respectiv 6 elemente. Exemplul 16: Scriei un program care convertete un ir de caractere reprezentnd un numr scris cu cifre romane n corespondentul su cu cifre arabe. Notaia cu cifre romane este un sistem nepoziional, care folosete cifrele: M, D, C, L, X, V, I, avnd respectiv valorile: 1000, 500, 100,50, 10, 5, 1. Pentru a obine valoarea numrului, se pleac cu acesta de la 0 i se adaug pe rnd contribuiile cifrelor astfel: dac valoarea cifrei romane curente este mai mare sau egal cu cifra care urmeaz, atunci valoarea cifrei curente se adaug la valoarea numrului arab, altfel se scade din acesta. De exemplu numrul roman MCMXCVIII are ca valoare pe 1998 Cifra curent M C M X C V I I I Cifra urmtoare C M X C V I I I Relaia dintre ele > < > < > > = = > Contribuia cifrei crte +1000 -100 +1000 -10 +100 +5 +1 +1 +1 Valoare numr 1000 900 1900 1890 1990 1995 1996 1997 1998

Se observ c pentru a considera i contribuia ultimei cifre a numrului am fost nevoii s prelungim numrul cu caracterul spaiu liber, cruia i-am asociat valoarea 0. Pentru stabilirea corespondenei cifr roman valoare asociat, vom defini o funcie int conv(char) care folosete dou tablouri: roman i arab, iniializate respectiv cu caracterele reprezentnd cifrele romane i cu valorile acestora, definite ca externe. Numrul roman nrom, citit de la intrarea standard va fi terminat prin spaiu liber. #define LMAX 15 #include <conio.h> #include <stdio.h> char roman[]=MDCLXVI ; int arab[]={1000,500,100,50,10,5,1,0}; int conv(char); void main(void) { char nrom[LMAX]; int i,n=0; //n = lungimea numarului scris cu cifre romane int narab=0; int crt,urm; while((nrom[n++]=getchar())!= ) ; n--; for (i=0; i<n-1; i++){ crt=conv(nrom[i]); urm=conv(nrom[i+1]); if(crt>=urm) narab+=crt; else

Valeriu Iorga

Programare n C / C++

narab-=crt; } for (i=0;i<n;i++) printf(%c,nrom[i]); printf(=%d\n,narab); } int conv(char c) { int j=0; while(roman[j++]!=c && j<8) ; if(j<8) return arab[--j]; else return 1; }

Valeriu Iorga

Programare n C / C++

8.2. Pointeri. Un pointer este o variabil care are ca valori adrese ale altor variabile, sau mai general adrese de memorie. Un pointer este asociat unui tip de variabile, deci avem pointeri ctre int, char, float, etc. n general o variabil pointer p ctre tipul T se declar: T *p; Un tip pointer la tipul T are tipul T*. Exemple: int j,*pj; /*pj este o variabila de tip pointer la ntregi*/ char c, *pc;

Se introduc doi noi operatori: operatorul de adresare & - aplicat unei variabile furnizeaz adresa acelei variabile

pj=&j; /* iniializare pointer */ pc=&c; Aceste iniializri pot fi fcute la definirea variabilelor pointeri: int j, *pj=&j; char c, *pc=&c; O greeal frevent comis o reprezint utilizarea unor pointeri neiniializai. int *px; *px=5; /* greit, pointerul px nu este iniializat (legat la o adres de variabil ntreag */

Pentru a evita aceast eroare vom iniializa n mod explicit un pointer la NULL, atunci cnd nu este folosit. operatorul de indirectare (derefereniere) * permite accesul la o variabil prin intermediul unui pointer. Dac p este un pointer de tip T*, atunci *p este obiectul de tip T aflat la adresa p. n mod evident avem: *(&x) = x; &(*p) = p; Exemplu; int *px, x; x=100; px=&x; // px contine adresa lui x printf(%d\n, px); // se afiseaza 100 Dereferenierea unui pointer neiniializat sau avnd valoarea NULL conduce la o eroare la execuie. 8.3. Pointeri void. tip. Pentru a utiliza un pointer cu mai multe tipuri de date, la declararea lui nu l legm de un anumit

void *px; // pointerul px nu este legat de nici un tip Un pointer nelegat de un tip nu poate fi derefereniat. Utilizarea acestui tip presupune conversii explicite de tip (cast). Exemplu: int i; void *p; . . .

Valeriu Iorga

Programare n C / C++

p=&i; *(int)p=5; // ar fi fost gresit *p=5 Exemplul 17: Definiti o functie care afiseaza o valoare ce poate aparine unuia din tipurile: char, int, double. #include <stdio.h> enum tip {caracter, intreg, real}; void afisare(void *px, tip t) { switch(t) { case caracter: printf("%c\n", *(char*)px); break; case intreg: printf("%d\n", *(int*)px); break; case real: printf("%lf\n",*(double*)px); break; } } void main(void) { char c='X'; int i=10; double d=2.5; afisare(&c, caracter); afisare(&i, intreg); afisare(&d, real); } 8.4. Pointeri constani i pointeri la constante. In definiiile: const int x=10, *px=&x; x este o constant, n timp ce px este un pointer la o constant. Aceasta nsemn c x, accesibil i prin px nu este modificabil (operaiile x++ i (*px)++ fiind incorecte, dar modificarea pointerului px este permis (px++ este corect). Un pointer constant (nemodificabil), se definete prin: int y, * const py=&y; In acest caz, modificarea pointerului (py++) nu este permis, dar coninutul referit de pointer poate fi modificat ( (*py)++ ). Un pointer constant (nemodificabil) la o constant se definete prin: const int c=5, *const pc=&c; In cazul folosirii unor parametri pointeri, pentru a preveni modificarea coninutului referit de acetia se prefer definirea lor ca pointeri la constante. De exemplu o functie care compar dou iruri de caractere are prototipul: int strcmp(const char *s, const char *d); 8.5. Operaii aritmetice cu pointeri.

Asupra pointerilor pot fi efectuate urmtoarele operaii: adunarea / scderea unei constante incrementarea / decrementarea scderea a doi pointeri de acelai tip

Valeriu Iorga

Programare n C / C++

Prin incrementarea unui pointer legat de un tip T, adresa nu este crescut cu 1, ci cu valoarea sizeof(T) care asigur adresarea urmtorului obiect de acelai tip. n mod asemntor, p + n reprezint de fapt p+n*sizeof(T) . Doi pointeri care indic elemente ale aceluiai tablou pot fi comparai prin operatorii de relaie i relaia de egalitate, sau pot fi sczui. Pointerii pot fi comparai prin relaiile == i != cu constanta simbolic NULL (definit n stdio.h). 8.6. Legtura ntre pointeri i tablouri. ntre pointeri i tablouri exist o legtur foarte strns. Orice operaie realizat folosind variabile indexate se poate obine i folosind pointeri. adic, dac x este un tablou (de exemplu int x[10];) atunci x &x[0] n C numele unui tablou este un pointer constant la primul element din tablou: x=&x[0] Numele de tablouri reprezint pointeri constani, deci nu pot fi modificai ca pointerii adevrai. Exemplu: int x[10], *px; px=x; /* sunt operatii permise */ px++; x=px; /* sunt operatii interzise, deoarece x este */ x++; /* pointer constant */ Prin urmare variabilele indexate pot fi transformate n expresii cu pointeri i avem echivalenele: Notaie indexat &x[0] &x[1] &x[i] &x[n-1] Adres Notaie cu pointeri x x+1 x+i x+n-1 Valoare Notaie indexat x[0] x[1] x[i] x[n-1] Notaie cu pointeri *x *(x+1) *(x+i) *(x+n-1)

n C avem urmtoarea echivalen ciudat!:Dac x este un tablou de ntregi x[i] i[x] ntr-adevr: x[i]=*(x+i)=*(i+x)=i[x] 8.7. Parametri tablouri. Dac n lista de parametri a unei funcii apare numele unui tablou cu o singur dimensiune se va transmite adresa de nceput a tabloului. Aceasta ne permite s nu specificm dimensiunea tabloului, att la definirea, ct i la apelul funciei. Exemplul 18: Scriei o funcie care calculeaz produsul scalar a doi vectori x i y, avnd cte n componente fiecare. Antetul funciei va fi: double scalar(int n, double x[], double y[]) Funcia poate fi declarat cu parametri formali pointeri n locul tablourilor: double scalar(int n, double *x, double *y) { double P=0; for (int i=0; i<=n; i++) P=P+x[i]*y[i] return P; }

Valeriu Iorga

Programare n C / C++

8.8. Probleme propuse.(Tablouri cu o dimensiune) 1. Intr-un ir x cu n componente reale, s se determine media aritmetic a elementelor pozitive situate ntre primul element pozitiv i ultimul element negativ al irului, exceptnd aceste elemente. Cazurile speciale vor fi clarificate prin mesaje corespunztoare. 2. Intr.un ir S cu n elemente ntregi (n 100) s se determine elementele distincte. 3. Doi vectori x i y au n, respectiv m elemente reale distincte (m,n 10). S se creeze un nou vector z cu elementele comune ale celor doi vectori. (intersecia elementelor mulimilor reprezentate de cei doi vectori). 4. Doi vectori x i y au n, respectiv m elemente reale distincte (m,n 10). S se creeze un nou vector z cu coninnd elementele celor doi vectori. Elementele comune din cei doi vectori apar n z o singur dat. (reuniunea elementelor mulimilor reprezentate de cei doi vectori). 5. Se citete o valoare ntreag n ( 0 < n 100) i n valori reale cu care se creaz un vector x. Scriei un program C care calculeaz i afieaz: Valoarea medie Abaterea medie ptratic:
n 1

i= 0

(x

x m e d2 )

n(n 1)

Numrul de componente care depesc valoarea medie S se creeze un vector y cu componentele din x mai mari dect valoarea medie i s se afieze cte 5 elemente pe o linie.

6. Se citesc n ( n 100 ) coordonate reale x, y ale unor puncte n plan i se creaz cu acestea dou tablouri x i y. S se afieze toate tripletele de puncte coliniare. S se afieze punctele i, j, k pentru care aria triunghiului determinat de aceste puncte este maxim.. Indicaie: Aria determinat de punctele i,j,k este: xi 1 s = yi 2 1 xj yj 1 xk yk 1

Dac punctele sunt coliniare, atunci S=0. 7. S se calculeze coeficienii binomiali Cn1,Cn2,,Cnp n care n < n), cunoscnd relaia de recuren: Cnk = (n-k+1)/k*Cnk-1 Se vor utiliza tablouri 8. S se calculeze coeficienii:c0 ,c1 ,...,cn-1 , pentru n dat, tiind c: C0/(p+1) + c1/p + + cp/1 = 1 pentru p=0,1,2,...,n. pornind cu Cn0 = 1 i p sunt ntregi pozitivi dai (p

Valeriu Iorga

Programare n C / C++

9. S se calculeze coeficieni polinomului Cebev de ordinul n, pornind de la relaia de recuren Tk(x) = 2xTk-1(x) Tk-2(x), T0(x) = 1, T1(x) = x k > 2

obinnd n prealabil relaii de recuren pentru coeficieni. 10. Un numr ntreg este reprezentat prin cifrele sale c[0],c[1],... c[n-1], (c[0] fiind cifra cea mai semnificativ). S se calculeze ctul q[0],q[1],... ,q[m-1] obinut prin imprirea numrului dat prin numrul ntreg p. 11. Dndu-se o valoare ntreag n, s se genereze reprezentarea fraciilor zecimale 1/2k unde k = 1,2, ... ,n. 12. Dou polinoame sunt date prin gradele lor i tablourile coeficienilor dup puterile descresctoare ale lui x. S se calculeze i s se afieze polinoamele ct i rest ale mpririi celor dou polinoame. 13. S se ordoneze cresctor irul x cu n elemente utiliznd observaia c n irul ordonat cresctor orice subir x[i], |x[i+1],...,x[n] cu i=0,1,2,...,n-2 are elementul x[i] maxim. 14. S se ordoneze cresctor o list avnd n componente (n 100) de numere intregi, utiliznd metoda contorizrii inversrilor (denumit i metoda bulelor) 15. Un numr de bare (N 100) sunt date prin lungimile lor.Se dau de asemenea P categorii de lungimi(sau standarde) ntre care trebuie s se ncadreze lungimile pieselor (P 10). O categorie de lungimi este precizat prin 2 limite:una minim i cealalt maxim; presupunem c aceste categorii de lungimi formeaz intervale disjuncte. O pies i se incadreaz n categoria de lungimi j dac: LMIN[j] L[i] LMAX[j]. S se calculeze i s se afieze: -numrul de piese din fiecare clas -dimensiunea medie a pieselor din fiecare clas de lungimi -numrul de rebuturi i lungimile barelor rebutate. 16. S se calculeze coeficienii bi , i=0..n-1 din dezvoltarea produsului: (x+a0 )(x+a1 )...(x+an-1 )=xn Se dau n i coeficienii a0 ,a1 ,...an-1 17. N copii identificai prin numerele 1,2,...,N, joac urmtorul joc:se aeaz n cerc n ordinea 1,2,..,N i ncepnd de la copilul k numr de la 1 la p eliminnd din cerc pe cel care a fost numrat cu p;numrtoarea ncepe de la urmtorul eliminndu-se al 2-lea .a.m.d. Folosindu-se identificarea iniial s se stabileasc ordinea de ieire a copiilor din joc. 18. ntr-un ir S cu n elemente s se determine elementele distincte. Exemplu: n irul 2 2 5 4 5 1 2 elementele distincte sunt : 2 5 4 1 Indicaie - elementele unice sunt distincte i se tipresc - dintre elementele cu mai multe apariii se tiprete un singur reprezentant. La ntlnirea primei egaliti S[i]=S[j] se abandoneaz cutarea i se tiprete S[i] numai dac i<j (este prima apariie a lui S[i]). 19. S se stabileasc dac o valoare dat y se afl printre cele n componente ale unui vector dat X i: + b0 xn-1 + ...+ bn-1

Valeriu Iorga

Programare n C / C++

n caz afirmativ se va afia poziia componentei din X egal cu y n caz negativ se va afia un mesaj corespunztor Se va utiliza o cutare secvenial. Indicaie Cutarea secvenial a lui y n vectorul X presupune compararea ntre y i X[k] pn la gsirea valorii cutate: y=X[k] sau pn la epuizarea tuturor componentelor lui X 20. S se ordoneze cresctor un vector x cu n componente prin inserie. Vectorul se consider partiionat n dou zone: o zon ordonat format iniial din primul element o zon neordonat format din restul elementelor Se extrage n mod repetat primul element din zona neordonat i se insereaz n zona ordonat astfel nct relaia de ordine s se pstreze.irul iniial i cel obinut prin ordonare vor fi afiate cu cte 10 elemente pe linie. 21. De pe mediul de intrare se citete un numr ntreg n 0 urmat de n valori reale. S se introduc aceste valori ntr-un tablou x pe msura citirii lor, astfel nct tabloul s fie ordonat cresctor. 22. Dndu-se o valoare x i un tablou a cu n elemente, s se separe acest tablou n dou partiii astfel nct elementele din prima partiie s fie mai mici sau egale cu x, iar cele din a doua partiie strict mai mari dect x. 23. S se determine elementul maxim dintr-un ir cu n elemente i poziia pe care el apare.n cazul unui maxim cu mai multe apariii se va nota prima sa apariie. 24. Se dau dou iruri x i y ordonate strict cresctor, avnd M i respectiv N elemente. S se construiasc un ir z ordonat strict cresctor coninnd elementele irurilor x i y.-("interclasare de iruri"). 25. Se consider un vector x cu n componente, ordonat strict cresctor i o valoare y. S se insereze aceast valoare n vectorul x astfel nct el s rmn ordonat strict cresctor. Se va face o cutare rapid a lui y n ir (cutare binar). irul iniial i cel rezultat se vor tipri cu cte 5 elemente pe linie. 26. Dintr-un ir dat s se determine lungimea i poziia subirului strict cresctor cel mai lung, format din elemente alturate din irul dat. irul dat se tiprete n ecou cu cte 10 elemente pe linie.Subirul de lungime maxim se afieaz cu 5 elemente pe linie. 27. Se spune c irul x cu k elemente "intr" n irul s cu n elemente k n, dac exist un subir contiguu si,sI+1,...,sI+k cu proprietatea c elementele lui sunt identice cu elementele irului x. S se stabileasc numrul de "intrri" ale lui x n s i poziiile n s ale elementelor de unde ncepe intrarea. 28. Doi vectori a i b au cte n componente fiecare, precizate pe mediul de intrare. S se calculeze unghiul dintre ei exprimat n radiani. 29. Dou numere sunt pstrate prin tablourile cifrelor lor. S se obin tabloul cifrelor produsului numerelor. 30. Dndu-se un numr ntreg n s se construiasc dou tablouri, primul coninnd factorii primi ai lui n, iar cel de-al doilea multiplicitile acestora. 31. S se calculeze cel mai mare divizor comun cmmdc a dou numere date m i n utiliznd urmtoarea metod: se creeaz tablouri cu factorii primi ai celor dou numere i multiplicitile lor se selecteaz n cmmdc factorii primi comuni la puterea cea mai mic 32. S se calculeze cel mai mare divizor comun a dou numere date m i n prin urmtoarea metod:

Valeriu Iorga

Programare n C / C++

pentru fiecare numr se creeaz un tablou cu toi divizorii acestuia, inclusiv divizorii banali; se selecteaz apoi ntr-un tablou divizorii comuni i se ia cel mai mare dintre acetia.

10