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
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
#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