6.3. Operaţii cu pointeri
Asupra pointerilor se pot face diferite operaţii. Deoarece ei conţin adrese atunci operaţiile se realizează cu adrese.
6.3.1. Incrementare şi decrementare
Operatorii de incrementare şi decrementare se pot aplica variabilelor de tip pointer.
Efectul:
-
operatorul de incrementare aplicat asupra unui operand de tip pointer spre tipul tip măreşte adresa conţinută de operand cu numărul de octeţi necesari pentru a păstra o dată de tipul tip.
-
operatorul de decrementare se execută în mod analog, cu singura diferenţă că în loc să se mărească adresa, ea se micşorează cu numărul corespunzător de octeţi.
De obicei decrementările şi incrementările adreselor sunt mai rapide ca execuţie când se au în vedere prelucrări de tablouri.
Exemplu:
int tab[10];
int *p;
int i=0;
p=&tab[i];
p++; // p contine adresa lui tab[1]
// cu p se pot face referiri la orice element de tablou
6.3.2. Adunarea şi scăderea unui întreg dintr-un pointer
Dacă p este un pointer, sunt corecte expresiile de forma:
p+n şi p-n
unde n este de tip întreg.
Efectul:
-
expresia p+n măreşte valoarea lui p cu n*nr_tip, unde nr_tip este numărul de octeţi necesari pentru a memora o dată de tipul tip spre care pointează p;
-
analog expresia p-n micşorează valoarea lui p cu n*nr_tip.
Dacă x este un tablou de tipul tip, atunci x este pointer, deci o expresie de forma:
x+n;
este corectă şi deoarece x este un pointer spre primul său element x[0], x+n va fi un pointer spre elementul x[n]. Rezultă că valoarea elementului x[n] se poate reprezenta prin expresia:
*(x+n);
Astfel variabilele cu indici se pot înlocui prin expresii cu pointeri. Aceasta permite ca la tratarea tablourilor să se folosească expresii cu pointeri în locul variabilelor cu indici. Versiunile cu pointeri sunt de obicei optime în raport cu cele realizate prin intermediul indicilor.
6.3.3. Compararea a doi pointeri
Doi pointeri care pointează spre elementele aceluiaşi tablou pot fi comparaţi folosind operatorii de relaţie şi de egalitate. Astfel, dacă p şi q sunt doi pointeri care pointează spre elementele tab[i], respectiv tab[j] ale tabloului tab, expresiile următoare au sens:
pObservaţii:
1o. Pointerii nu pot fi comparaţi decât în condiţiile amintite mai sus (deci dacă sunt pointeri spre elementele aceluiaşi tablou).
2o. Operatorii = = şi != permit compararea unui pointer şi cu o constantă simbolică specială având numele NULL. Aceste comparaţii permit să stabilim dacă un pointer conţine o adresă sau nu. Astfel, dacă expresia:
p= = NULL
este adevărată, p nu conţine o adresă. Dacă expresia respectivă are valoarea fals atunci p conţine o adresă. Constanta simbolică NULL este definită în fişierul stdio.h
6.3.4. Diferenţa a doi pointeri
Doi pointeri care pointează spre elementele aceluiaşi tablou pot fi scăzuţi. Rezultatul diferenţei a doi pointeri este definit astfel: fie t un tablou de un tip oarecare şi p şi q doi pointeri, p conţine adresa elementului t[i] iar q conţine adresa elementului t[i+n]. Atunci diferenţa q-p are valoarea n.
6.3.5. Exemple
Vom da câteva funcţii asupra şirurilor de caractere:
funcţia lungime
unsigned lungime (char*x)
{ int i;
for (i=0; *x != ‘\0’; i++) x++; // sau for (i=0; *x++; i++);
return i;
}
funcţia copiaza
void copiaza(char *x, char *y) // copiaza din zona de adresa y
// in zona de adresa x
{ while(*x++ = *y++); }
funcţia concateneaza
void concateneaza (char *x, char *y)
// concateneaza sirul de adresa y la sfarsitul sirului
// de adresa x
{ while (*x) x++; // avans de adresa pana la sfarsitul sirului x
while (*x++= *y++);
}
funcţia compara
int compara (char *x, char *y)
{ while (*x= = *y)
{ if (*x= = ‘\0’) return 0;
x++;
y++;
return *x - *y; // daca diferenta caracterelor este
// negativa atunci xy
}
}
6.4. Alocarea dinamică a memoriei
Biblioteca standard a limbajului C pune la dispoziţia utilizatorului funcţii care permit alocarea de zone de memorie în timpul execuţiei programului. O astfel de zonă de memorie poate fi utilizată pentru a păstra date temporare. Zona respectivă poate fi eliberată în momentul în care nu mai sunt necesare datele care au fost păstrate în ea. Alocarea de zone de memorie şi eliberarea lor în timpul execuţiei programelor permite gestionarea optimă a memoriei de către programator. Un astfel de mijloc de gestionare a memoriei îl vom numi alocare dinamică a memoriei.
Vom indica două funcţii din bibloteca limbajului C utilizate frecvent în alocarea dinamică a memoriei. Prototipurile lor se află în fişierele standard alloc.h şi stdlib.h, deci pentru a le utiliza vom include unul din aceste fişiere.
Funcţia malloc permite alocarea unui bloc de memorie a cărui dimensiune se specifică în octeţi. Funcţia returnează un pointer spre începutul zonei alocate. Întrucât acest pointer trebuie să permită memorarea oricărui tip de dată în zona alocată, el este de tip void *.
Prototipul funcţiei este:
void *malloc (unsigned n);
unde n este numărul de octeţi al zonei de memorie care se alocă. În cazul în care n este prea mare, funcţia returnează pointerul NULL.
Funcţia free eliberează o zonă de memorie alocată prin malloc. Prototipul ei este:
void free (void *p);
unde p este pointerul returnat de malloc la alocare, deci este pointerul spre începutul zonei care se eliberează.
Exemplu:
Funcţia memchar memorează un şir de caractere într-o zonă de memorie alocată prin funcţia malloc. Ea returnează adresa de început a zonei în care s-a salvat şirul de caractere, deci returnează un pointer spre tipul char.
#include
#include
#include
char *memchar (char *s)
{ char *p;
if ((p=(char *)malloc(strlen(s)+1) ) != NULL)
{ strcpy (p,s);
return p;
} else
return NULL;
}
Observaţii:
1o. În fişierul stdio.h există definiţia constantei NULL.
2o. Fişierul alloc.h s-a inclus deoarece conţine prototipul funcţiei malloc.
3o. Fişierul string.h conţine prototipurile funcţiilor strlen şi strcpy.
4o. Funcţia malloc se apelează pentru a rezerva strlen(s)+1 octeţi; strlen returnează numărul de octeţi ocupaţi de caracterele proprii ale lui s (fără caracterul NUL). Cum în zona de memorie rezervată prin malloc se păstrează şi caracterul NUL, lungimea returnată de funcţia strlen s-a mărit cu 1.
5o. Pointerul returnat de malloc a fost convertit spre char *, deoarece el este de tip void *. Acest pointer se atribuie lui p, deci p pointează spre începutul zonei de memorie alocate prin apelul funcţiei malloc. Se testează dacă acest pointer este diferit de NULL (deci dacă s-a putut aloca memoria de dimensiunea cerută). În caz afirmativ, se transferă şirul prin apelul funcţiei strcpy, returnându-se apoi valoarea pointerului p.
Dostları ilə paylaş: |