POINTERI. Exemple

 

 

Pointerii sunt variabile care au ca valori adresele altor variabile (obiecte). Din punctul de vedere al conţinutului zonei de memorie adresate, se disting următoarele categorii de pointeri:

q       pointeri de date (obiecte) - conţin adresa unei variabile din memorie;

q       pointeri generici (numiţi şi pointeri void) - conţin adresa unui obiect oarecare, de tip neprecizat;

q       pointeri de funcţii - conţin adresa codului executabil al unei funcţii.

Exemplu:

int x, y, ptr;

// ptr- variabilă pointer către un int; x,y-variabile predefinite, simple, de tip int

x=5; cout<<”Adresa variabilei x este:”<<&x<<endl;

cout<<”Valoarea lui x:”<<x<<endl;

ptr=&x;          // atribuire: variabila ptr conţine adresa variabilei x

cout<<”Variabila pointer ptr are valoarea:”<<ptr;

cout<<” si adreseaza obiectul:”<< ptr<<endl;

y=ptr; cout<<”y=”<<y<<endl; // y=5

x=4; cout<<”x=”<<x<<endl; cout<<”ptr=”<<ptr<<endl;

// x si ptr reprezinta acelasi obiect, un intreg cu valoarea 4

x=70;            // echivalenta cu ptr=70;

y=x+10;          // echivalenta cu y=ptr+10

 

Variabilele pointer, alături de operatorii de referenţiere şi de deferenţiere, pot apare în expresii.

Exemple:

int x, y, q; q=&x;

q=8;             // echivalentă cu x=8;

q=&5;             // invalidă - constantele nu au adresă

x=9;             // invalidă - x nu este variabilă pointer

x=&y; //invalidă: x nu este variabilă pointer, deci nu poate fi folosită cu operatorul de indirectare

y=q + 3;                 // echivalentă cu y=x+3;

q = 0;                // setează x pe 0

q += 1;                     // echivalentă cu (q)++ sau cu x++

int r; r = q;  

/* copiază conţinutul lui q (adresa lui x) în r, deci r va pointa tot către x (va conţine tot adresa lui x)*/

double w=10.10, r = &w, r1, r2;

r1= &w; r2=r1;

cout<<”r1=”<<r1<<endl;       //afişează valoarea pointerului r1 (adresa lui w)

cout<<”&r1=”<<&r1<<endl;     // afişează adresa variabilei r1, pointerul are si el o adresa proprie

cout<<”r1= ”<<r1<<endl;   //afiseaza 10.10

double z=r1;               // echivalentă cu z=w

cout<<”z=”<<z<<endl;

 

Exemplu:

void v1, v2;

int a, b, q1, q2;

q1 = &a; q2 = q1; v1 = q1;

q2 = v1;    // eroare: unui pointer cu tip nu i se poate atribui un pointer generic

q2 = (int ) v1;

double s, ps = &s;

int c, l;

void sv;

l = (int ) sv;

ps = (double ) sv;

(char ) sv = 'a';        /*Interpretare: adresa la care se găseşte valoarea lui sv este interpretată ca fiind adresa zonei de memorie care conţine o data de tip char. */

Exemplu:

int a=5, pa, pb;

cout<<”&a=”<<&a<<endl;

pa=&a;

cout<<”pa=”<<pa<<endl;

cout<<”pa+2”<<pa+2<<endl;

pb=pa++;

cout<<”pb=”<<pb<<endl;

int i=pa-pb;

cout<<”i=”<<i<<endl;               

 

POINTERI ŞI VECTORI

Exemplu:

int a[10], ptr;       // a este definit ca &a[0]; a este pointer constant

a = a + 1;             // ilegal

ptr = a ;        // legal: ptr are aceeaşi valoare ca şi a, respectiv adresa elementului a[0]

                                    // ptr este variabilă pointer, a este constantă pointer.

int x = a[0];    // echivalent cu x = ptr; se atribuie lui x valoarea lui a[0]

 

Deoarece numele tabloului a este sinonim pentru adresa elementului de indice zero din tablou, asignarea ptr=&a[0] poate fi înlocuită, ca în exemplul anterior, cu ptr=a.

 

Exemplu:

char sir[10];    

char psir;

sir = ”hello”;    // ilegal

psir = ”hello”;   // legal

Operaţia de indexare a elementelor unui tablou poate fi realizată cu ajutorul variabilelor pointer.

 

Exemplul 1:

int a[10]={10,20,30,40.50,60,70,80,90}, ptr;  // a este pointer constant; ptr este variabilă pointer

ptr = a;         // ptr este adresa lui a[0]

ptr+i      înseamnă ptr+(isizeof(int)), deci:  ptr + i  & a[i]

Deoarece numele unui tablou este un pointer (constant), putem concluziona:

a+i  & a[i]

a[i]  (a+i)

ceea ce inseamna ca:

cout<<a[3]<<” “<<*(a+3)<<” “<<*(ptr+3)<<” “<<3[a]<<” “<<*(3+a);//afiseaza 40 40 40 40

cout<<a+3<<” “<<ptr+3<<” “<<&(a[3]);//afiseaza adresa celei de a patra componente.

 

Exemplul 2:

struct complex{float re, im, modul;};

complex v[30],*p=v;

 

componenta de index 3, campul re se poate accesa astfel:

Pentru continut:

v[3].re sau   (*(v+3)).re  sau (*(p+3)).re sau (v+3)->re sau (p+3)->re

 

Pentru adresa:

v+3, p+3, &v[3]

 

 

POINTERI ŞI TABLOURI MULTIDIMENSIONALE

 

Elementele unui tablou bidimensional sunt păstrate tot într-o zonă continuă de memorie, dar inconvenientul constă în faptul că ne gândim la aceste elemente în termeni de rânduri (linii) şi coloane . Un tablou bidimensional este tratat ca un tablou unidimensional ale cărui elemente sunt tablouri unidimensionale.

 

Fie matricea:

int a[3][3]={{5,6,7}, {55,66,77}, {555,666,777}};

 

 

5

6

7

55

66

77

555

666

777

 a[0] acceseaza primul rand (care este practic un vector)

 a[1] acceseaza al doilea rand

 a[2] acceseaza al treilea rand

 

Desi a si a[0] reprezinta aceeasi adresa (a este un pointer constant) reprezinta totusi tablouri de dimensiuni diferite: a este un tablou bidimensional cu 9 componente iar a[0] este un tablou unidimensional cu 3 componente. Atat a cat si a[0] acceseaza adresa de inceput a tabloului.

 

cout<<a<<” “<<a[0];// vor afisa acelasi lucru, adica o adresa. Aceasta adresa poate fi privita atat ca adresa de inceput a matricii cat si ca adresa de inceput a vectorului a[0].

 

Daca a[0] este un vector atunci a[0][0] este prima componenta a vectorului. a[1]  reprezinta adresa de inceput a celei de a doua linii ceea ce inseamna ca daca dorim sa accesam adresa celei de a treia componente din linia 1 vom scrie: a[1]+3. Continutul (valoarea) acestei componente va fi *(a[1]+3). In mod uzual a[1][3].

 

Urmariti urmatorul exemplu si observati rezultatele obtinute in urma rularii.

 

#include <iostream.h>

#include <conio.h>

void main()

{int a[3][3]={{5,6,7}, {55,66,77}, {555,666,777}};

clrscr();

cout<<"a="<<a<<" &a="<<&a<<" &a[0]="<<&a[0]<<endl;

 

cout<<"Pointeri catre vectorii linii\n";

for (int i=0; i<3; i++){

    cout<<" a["<<i<<"]="<<a[i]<<endl;

}

 

cout<<endl;

cout<<"afisarea adreselor componentelor"<<endl;

 

for (i=0; i<3; i++){

            for (int j=0; j<3; j++)

                          cout<<a[i]+j<<' ';

            cout<<endl;

            }

 

cout<<endl<<"afisarea continutului matricii";

cout<<endl;

for (i=0; i<3; i++){

            for (int j=0; j<3; j++)

                          cout<<*(a[i]+j)<<' ';

            cout<<endl;

            }

 

//o variabila de tip pointer care poate retine pe a se declara astfel:

cout<<endl;

int (*p)[3]=a;

cout<<p<<" "<<p[0];  //este echivalent cu a si a[0]

cout<<endl<<"p[1][2]="<<p[1][2];

getch();

}

 

 

 

 

PROBLEME PROPUSE:

Utilizand aritmetica pointerilor rezolvati urmatoarele cerinte:

 

1.       Se citesc cele 3 note la o disciplina ale unui elev. Sa se determine media elevului.

2.       Pentru 2 elevi se vor citi: numele, prenumele, cele doua note la o disciplina. Sa se afiseze elevul cu media cea mai mare

3.       Sa se genereze un vector care retine primele n numere din sirul lui Fibonacci. Sa se declare un pointer catre vector. Sa se afiseze continutul vectorului in 4 moduri. Sa se afiseze pt. fiecare componenta si adresa la care a fost memorata (in trei moduri).

4.       Sa se genereze o matrice a[4][5] in care sa se retina valorile de la 1 la 20. Sa se afeseze adresele componentelor unei linii. Sa se afiseze adresele unei coloane.

5.       Să se scrie un program care citeşte elementele unui vector de întregi, cu maxim 20 elemente şi înlocuieşte elementul (elementele) maxim din vector cu o valoare introdusă de la tastatură. Se va folosi aritmetica pointerilor.

6.       Se citesc n segmente date prin coordonatele punctelor care le formează. Să se calculeze lungimile segmentelor. Să se afişeze coordonatele segmentului de lungime maximă.

7.       Într-un magazin sunt n produse. Pentru fiecare se citeşte de la tastatură numele produsului, preţul unitar şi numărul de bucăţi vândute şi se calculează preţul total de vânzare. Să se afişeze numele produsului celui mai scump. Să se calculeze media aritmetică a preţurilor unitare. Să se afişeze produsele în ordinea alfabetică a numelor.

1.       Se citesc n numere naturale. Să se calculeze pentru fiecare inversul

2.       Sa se genereze un vector cu n componente naturale, fiecare divizibila cu 5 si mai mica sau egala 5000. Sa se determine cea mai mare valoare