Masive de pointeri si pointeri la pointeri
Deoarece pointerii sint variabile, are sens notiunea de masiv de pointeri. Vom ilustra modul de lucru cu masive de pointeri pe un exemplu.
Sa scriem un program care sa sorteze lexicografic liniile de lungimi diferite ale unui text, linii care spre deosebire de intregi nu pot fi comparate sau schimbat 848f55i e printr-o singura operatie.
Daca memoram liniile textului una dupa alta intr-un masiv lung de caractere (gestionat de functia alloc), atunci fiecare linie poate fi accesibila cu ajutorul unui pointer la primul ei caracter. Pointerii tuturor liniilor, la rindul lor, pot fi memorati sub forma unui masiv. Atunci doua linii de text pot fi comparate transmitind pointerii lor functiei strcmp. Daca doua linii care nu respecta ordinea trebuie sa fie schimbate, se schimba doar pointerii lor din masivul de pointeri si nu textul efectiv al liniilor.
Procesul de sortare il vom realiza in trei pasi:
1) se citesc toate liniile textului de la intrare;
2) se sorteaza liniile in ordine lexicografica;
3) se tiparesc liniile sortate in noua ordine.
Vom scrie programul prin functiile sale, fiecare functie realizind unul din cei trei pasi de mai sus. O rutina principala va controla cele trei functii. Ea are urmatorul cod:
#define LINES 100 /* nr maxim de linii de sortat */
main()
else printf
('Intrarea prea mare pentru sortn');
}
Cele 3 functii care realizeaza intregul proces sint: readlines sort si writelines
Rutina de intrare readlines trebuie sa memoreze caracterele fiecarei linii si sa construiasca un masiv de pointeri la liniile citite. Trebuie, de asemenea, sa numere liniile din textul de la intrare, deoarece aceasta informatie este necesara in procesul de sortare si de imprimare. Intrucit functia de intrare poate prelucra numai un numar finit de linii de intrare, ea poate returna un numar ilegal, cum ar fi 1, spre a semnala ca numarul liniilor de intrare este prea mare pentru capacitatea de care dispune.
Atunci functia readlines care citeste liniile textului de la intrare este urmatoarea:
#define MAXLEN 1000
#define NULL 0
#define EOF -1
readlines(char *lineptr[], int maxlines)
return nlines;
}
Instructiunea line[len-1] = '0'; sterge caracterul <LF> de la sfirsitul fiecarei linii ca sa nu afecteze ordinea in care sint sortate liniile si depune in locul lui caracterul ca marca de sfirsit de sir.
writelines(char *lineptr[], int nlines)
Declaratia noua care apare in aceste programe este:
char *lineptr[LINES];
care indica faptul ca lineptr este un masiv de LINES elemente, fiecare element al masivului fiind un pointer la un caracter. Astfel lineptr[i] este un pointer la un caracter, iar *lineptr[i] permite accesul la caracterul respectiv.
Deoarece lineptr este el insusi un masiv, care se transmite ca argument functiei writelines, el va fi tratat ca un pointer (vezi sectiunea 9.3) si atunci functia writelines mai poate fi scrisa si astfel:
writelines(char *lineptr[], int nlines)
In functia printf lineptr indica initial prima linie de imprimat; fiecare incrementare avanseaza pe *lineptr la urmatoarea linie de imprimat, in timp ce nlines se micsoreaza dupa fiecare tiparire a unei linii cu 1.
Functia care realizeaza sortarea efectiva a liniilor se bazeaza pe algoritmul de injumatatire si are urmatorul cod:
#define NULL 0
#define LINES 100 /* nr maxim de linii de sortat */
sort(char *v[], int n)
}
Deoarece fiecare element al masivului v (care este de fapt masivul lineptr) este un pointer la primul caracter al unei linii, variabila temp va fi si ea un pointer la un caracter, deci operatiile de atribuire din ciclu dupa variabila j sint admise si ele realizeaza reinversarea pointerilor la linii daca ele nu sint in ordinea ceruta.
Sa retinem deci urmatoarele lucruri legate de masive si pointeri. De cite ori apare intr-o expresie un identificator de tip masiv el este convertit intr-un pointer la primul element al masivului. Prin definitie, operatorul de indexare este interpretat astfel incit E E este identic cu E E . Daca E este un masiv, iar E un intreg, atunci E E se refera la elementul de indice E al masivului E .
O regula corespunzatoare se aplica si masivelor multi-dimensionale. Daca E este un masiv d-dimensional, de rangul i*j**k, atunci ori de cite ori e1 apare intr-o expresie, e1 va fi convertit intr-un pointer la un masiv d 1 - dimensional de rangul j**k, ale carui elemente sint masive. Daca operatorul se aplica acestui pointer, rezultatul este masivul d 1 - dimensional, care se va converti imediat intr-un pointer la un masiv d 2 - dimensional s.a.m.d. Rationamentul se poate aplica in mod inductiv pina cind, in final, ca urmare a aplicarii operatorului se obtine ca rezultat un intreg, de exemplu, daca masivul a fost declarat de tipul int
Sa consideram, de exemplu, masivul:
int x[3][5];
x este un masiv de intregi, de rangul 3*5. Cind x apare intr-o expresie, el este convertit intr-un pointer la (primul din cele trei) masive de 5 intregi.
In expresia x[i], care este echivalenta cu expresia *(x+i) x este convertit intr-un pointer la un masiv, ale carui elemente sint la rindul lor masive de 5 elemente; apoi i se converteste la tipul x, adica indicele i se inmulteste cu lungimea elementului pe care il indica x (adica 5 intregi) si apoi rezultatele se aduna. Se aplica operatorul pentru obtinerea masivului i (de 5 intregi) care la rindul lui este convertit intr-un pointer la primul intreg din cei cinci.
Se observa deci ca primul indice din declaratia unui masiv nu joaca rol in calculul adresei.
|