8.1. Declaratia de pointer si tipul pointer

2019/03/03 in Programare in C

Un pointer se declara ca orice variabila, cu singura deosebire ca numele este precedat de caracterul *. Astfel, daca dorim sa declaram variabila p pentru a pastra adresa lui x, vom folosi declaratia:

int *p;

Tipul int stabileste faptul ca p contine adrese de memorie in care se pastreaza date de tip int. Declaratia de mai sus se poate interpreta astfel:

*p reprezinta continutul zonei de memorie spre care pointeaza p, iar acest continut are tipul int.

In general, un pointer se declara prin:

tip *nume;

ceea ce inseamna ca nume este un pointer care pointeaza spre o zona de memorie care contine o data de tipul int.

Cmparand declaratia de mai sus cu cea obisnuita:

tip nume;

putem considera ca tip * dintr-o declaratie de pointeri reprezinta tip dintr-o declaratie obisnuita. De aceea constructia:

tip *

se spune ca reprezinta un tip nou, tipul pointer. Acest tip se spune ca este tipul pointer spre tip.

Daca avem declaratiile:

int x;
int *p;
float y;

atunci atribuirea:

p = &x;

este corecta, in timp ce:

p = &y;

nu este corecta, deoarece p poate contine numai adrese de zone de memorie in care se pastreaza date de tip int.

Daca exista declaratia:

float *q;

atunci se poate face atribuirea:

q = &y;

Exemple:

int x, y;
int *p;
  1. y = x + 100;

    este echivalenta cu secventa:

    p = &x;
    y = *p + 100;
  2. x = y;

    este echivalenta cu secventa:

    p = &x;
    *p = y;
  3. x++;

    este echivalenta cu secventa:

    p = &x;
    (*p)++;

Exista cazuri in care dorim ca un pointer sa fie utilizat cu mai multe tipuri de date. In acest caz, la declararea lui se utilizeaza cuvantul void:

void *nume;

Exemplu:

int x;
float y;
char c;
void *p;
...
p = &x;
...
p = &y;
...
p = &c;
...

Deoarece p a fost declarat cu ajutorul cuvantului cheie void, lui p i se pot atribui adrese de memorie care pot contine date de tipuri diferite: int, float, char etc.

Cand se folosesc pointeri de tip void, este necesar sa se faca conversii explicite prin expresii de tip cast, pentru a putea preciza tipul datei spre care pointeaza un astfel de pointer. Intr-adevar, daca se utilizeaza p declarat ca mai sus, atunci o atribuire de forma:

*p = 10;

nu este corecta, deoarece nu este definit tipul datei spre care pointeaza p.

Pentru a putea realiza o astfel de atribuire, va trebui sa convertim valoarea lui p spre tipul "pointer spre tipul int". Tipul pointer spre tipul int se exprima prin constructia:

int *

Amintim ca valoarea unui operand se poate converti spre tipul tip folosind operatorul unar (tip).

(tip) operand

De exemplu, pentru a coverti valoarea lui y, din exemplul de mai sus, spre long, vom scrie:

(long)y

In cazul de fata, valoarea lui p trebuie convertita spre tipul int *, deci vom folosi expresia cast:

*(int *)p

*(int *)p = 10

In mod analog, o expresie de forma:

*p + 1.5

este eronata. Este necesar sa se converteasca explicit valoarea lui p spre tipul de data continut in zona de memorie a carui adresa este valoarea lui p. Rezulta ca expresiile:

*(int *)p + 1.5
*(float *)p + 1.5
*(char *)p + 1.5

pot fi utilizate in locul expresiei de mai sus. Expresia:

*(int *)p + 1.5

se evalueaza astfel:

  1. Adresa care este valoarea lui p se interpreteaza ca fiind adresa zonei de memorie care contine o data de tip int.
  2. Valoarea de la adresa definita de expresia (int *)p se converteste din int spre double in conformitate cu regula conversiilor implicite.
  3. Valoarea obtinuta la punctul 2 se aduna cu 1.5 si suma este de tip double.

Conversia tipului pointer void * spre un tip pointer concret (int *, float * etc.) este totdeauna posibila si nu inseamna altceva decat precizarea tipului de pointer pe care il are valoarea pointerului la care se aplica conversia respectiva. Deci, conversia realizata prin expresia cast (int *)p precizeaza faptul ca p are ca valoare o adresa a unei zone de memorie in care se pastreazaintregi de tip int.

Utilizarea tipului void * asigura o flexibilitate mai mare in utilizarea pointerilor. Cu toate acestea, se recomanda sa nu se foloseasca in mod abuziv, deoarece aceasta poate fi si o sursa de erori. Intr-adevar, programatorul trebuie sa stie, in fiecare moment, ce fel de tip de pointer este valoarea atribuita variabilei pointer de tip void *.

De exemplu, daca se utilizeaza expresia:

(int *)p

intr-un moment in care p are ca valoare adresa unei zone de memorie care contine o data flotanta, rezultatul va fi imprevizibil.

8.2. Realizarea apelului prin referinta utilizand parametri de tip pointer