Sunteți pe pagina 1din 9

Algoritmic & Programare

POINTERI (I)
1. Operatorul adresa lui (operatorul de refereniere, operatorul &) Pentru a putea lucra cu un obiect (variabil simpl, tablou, func ie, etc), progra! matorul trebuie s "ispun "e o mo"alitate "e referire, "e in"icare, a respectivului obiect# $ea mai simpl mo"alitate este referirea direct, prin utili%area numelui obiectului, a"ic a i"entificatorului asociat acestuia &n momentul "efinirii lui# Nu orice obiect are un nume, "e e'emplu, fiecare "intre cele () elemente ale tablului tab "efinit astfel
int tab[10];

este o variabila anonim "e tip int# Pentru a accesa valorile unor astfel "e variabile tre! buie s folosim o mo"alitate "e referire in"irect, cum ar fi, &n acest ca%, utili%area ope! ratorului "e in"e'are * +,
tab[2]=13;

-o"alitatea general "e referire indirect a unui obiect const &n in"icarea obi! ectului prin a"resa sa "e memorie, pentru c orice obiect "efinit "e programator trebuie s ocupe, mcar &n momentul utili%rii lui, o anumit %on "e memorie alocat lui "e ctre compilator sau "e ctre sistemul "e operare .i, &n consecin , fiecare obiect are o a"res "e memorie# /ona "e memorie ocupat "e un obiect se numeste locaia obiectului .i, prin "efini ie, a"resa unui obiect este a"resa primului octet al loca iei sale# Amintim c memoria este organi%at la nivel "e octet, octe ii fiin" numerota i &ncep&n" "e la numrul (, aceast numerotare atribuie fiecrui octet o a"res "e memorie (a"resa %ero nu este atribuit), a"resele sunt memorate pe 01 bi i (&n ca%ul P$!urilor cu micro!procesoare pe 01 "e bi i) .i, &n consecin , spa iul "e a"rese este "e la ( la 101!(# 2ac "ispunem "e3a "e o cale "e referire la un obiect (printr!o e'presie l!valoare, nume, e'presie cu in"ici), putem afla a"resa acestuia cu a3utorul operatorului 4a"resa lui 56 (operatorul &), astfel,
#include<iostream> using namespace std; int main(void) c!ar c; int i; double "; int tab[10]; int #un(int$int); cout<<%adresa lui cout<<%adresa lui cout<<%adresa lui cout<<%adresa lui cout<<%adresa lui

i " tab #un c

%<<&i<<endl; %<<&"<<endl; %<<&tab<<endl; %<<&#un<<endl; %<<(int')&c<<endl;

cout<<%(n)*+1 numele unui tablou==adresa tabloului,(n%<<endl; cout<<%adresa lui tab= %<<&tab<<endl; cout<<%numele lui tab= %<<tab<<endl;

cout<<%adresa cout<<%adresa cout<<%(n)*+2 cout<<%adresa cout<<%numele return 0;

lui tab[0]=%<<&tab[0]<<endl; lui tab[1]=%<<&tab[1]<<endl; numele unei #unctii==adresa #unctiei,(n%<<endl; #unctiei #un=%<<&#un<<endl; #unctiei #un=%<<#un<<endl;

int #un(int i$ int .) return i/.; 0' adresa adresa adresa adresa adresa lui lui lui lui lui i " tab #un c 00121123 00121133 00121113 00311224 00121153

)*+1 numele unui tablou==adresa tabloului, adresa numele adresa adresa lui lui lui lui tab= 00121113 tab= 00121113 tab[0]=00121113 tab[1]=00121114

)*+2 numele unei #unctii==adresa #unctiei, adresa #unctiei #un=00311224 numele #unctiei #un=00311224 6ress an7 8e7 to continue 9 9 9 '0

Observa ie, numele unui obiect este "e fapt a"resa acelui obiect# In ca%ul variabi! lelor simple, aceast utili%are a numelor este re%ervat compilatorului# A"resa unei varia! bile simple poate fi aflat numai cu a3utorul operatorului &# Numele unui tablou este o e'presie care are ca valoare a"resa primului element al tabloului iar numele unei func ii in"ic a"resa primului octet al %onei "e memorie ocupate "e co"ul functiei# Re%ultatul aplicrii operatorului & este o e'presie .i, ca orice alt e'presie &n $, are un anumit tip# 2ac variabila x are tipul tip_x, atunci e'presia &x are tipul 4pointer ctre tip_x6# -ai precis, &x este o constant "e tip 4pointer ctre tip_x6# 7n pointer este o variabil care are ca valoare a"resa unei loca ii "e memorie# O variabil pointer este o variabil simpl, ea ocup numai spa iul necesar pentru scrierea unei a"rese, (patru octe i &n ca%ul compilatorului -8 9isual $::)# 2e.i toate variabilele pointer au valorile "e acela.i fel (a"rese, a"ic numere &n "omeniul (, 1, ### , 1 01!(), ele se "eosebesc &ntre ele prin tipul variabilelor la care fac referire (tipul intei)# Avem astfel 4pointer ctre int6, 4pointer ctre tablouri de 10 intre i6, etc# 2e e'emplu, "ac x este o variabil "e tip int .i "orim s re inem un"eva a"resa sa, vom "eclara o variabil p "e tip 4pointer ctre int6 astfel
int 'p;

.i apoi &i atribuim valoarea "orit,

int main(void) int "; int 'p; p=&"; cout<<p<<endl; return 0; 0' 00121150 6ress an7 8e7 to continue 9 9 9'0

O "eclara ie "e pointer "eclar "e fapt tipul intei pointerului, astfel &nc;t compila! torul s poat organi%a calculele cu "ata referit "e pointer# !. Operatorul inta lui (operatorul de derefereniere, opreatorul ") O variabil pointer, "up cum am v%ut, are ca valoare a"resa unui obiect (&n general anonim) "e un tip bine preci%at, numit inta pointerului# Pentru a putea utili%a inta unui pointer trebuie s facem o referire ctre ea# $alea ctre inta poinerului p se ob ine prin aplicarea operatorului unar prefi'at <, e'presia <p "esemnea% obiectul a carui a"res este con inut "e pointerul p, at;t ca r!valoare c;t .i ca l!valoare# E'presia <p este "e fapt numele intei, poate s apar &ntr!o e'presie oriun"e poate apare numele unui obiect "e tipul intei (at;t &n "reapta c;t .i &n st;nga unei atribuiri)# E'emplu,
int i; int 'p$':; p=&i; i=13; cout<<%i=%<<i<<% 'p=%<<'p<<endl;00i=13 'p=13 'p=12; cout<<%i=%<<i<<% 'p=%<<'p<<endl;00i=12 'p=12 :=p; ':=11; cout<<%i=%<<i<<% 'p=%<<'p<<endl;00i=11 'p=11 cout<<i/'p/':<<endl; 0033

In acest e'emplu, pointerul p a fost ini iali%at cu a"resa variabilei i .i astfel inta lui p este i, iar e'presia "p este sinonim cu numele variabilei i# Operatorul < ,4 inta lui56, se aplic unui pointer .i are ca re%ultat o referin ctre inta pointerului# Operatorul &, 4a"resa lui56 se aplic unei referin e (unei l!valori) .i are ca re%ultat o constant "e tip 4pointer ctre 56 Operatorii 4a"resa lui56 .i 4 inta lui56 sunt unul inversul celuilalt (cu anumite preci%ri)# 2in acest motiv ei sunt numi i (oarecum impropriu) 4operatorul "e referen iere &6 .i 4operatorul "e "ereferen iere <6# 2aca x este o variabil "e tip_x, atunci e'presiile x .i "&x sunt sinonime (au aceea.i r!valoare .i aceea.i l!valoare, ambele nu au efecte secun"are)#
int .$8; 8=12;

.='&8; cout<<%.=%<<.<<endl;00.=12 '&8=13; cout<<%8=%<<8<<endl;008=13

2e fapt, compilatorul 4sterge6 orice perec=e <& &nt;lnit,


00311213 cmp esi$esp 00311215 call ;<=>/312(??@>A?A!ec8Bsp) (3111C3!) '&8=13; 0031121* mov dDord ptr [8]$0E! cout<<%8=%<<8<<endl;008=13 999 00311222 mov esi$esp 999

Reciproc, "ac p este un pointer, atunci p .i &"p au aceea.i r!valoare# Totu.i, "eoarece re%ultatul aplicrii operatorului 4a"resa lui56 nu are l!valoare, fiin" o constant "e tip pointer, cele "ou e'presii nu sunt complet ec=ivalente,
int 'p$':; int !=10; p=&!; :=&'p; cout<<%p=%<<p<<% :=%<<:<<endl; 00 p=00121134 :=00121134 &'p=:; 00 error A2105, F=F , le#t operand must be lGvalue

00

#. $%estiuni ele&entare despre pointeri. a) In "efinirea unei variabile "e tip pointer simbolul < poate fi interpretat ca fiin" simbo! lul operatorului 4 inta lui56# -ai precis, "eclara ia
int ' pi;

poate fi scris sub forma ec=ivalent


int' pi;

.i citit 4pi este o variabil "e tip int", a"ic un pointer ctre int, sau poate fi scris, la fel "e bine, sub forma
int 'pi;

.i citit a.a, 4 inta lui pi este o variabil "e tip int, a"ic pi este un pointer a crei int este "e tip int# $;n" "eclarm mai mul i pointeri "e acela.i tip se utili%ea% numai aceast ultim interpretare, instruc iunea
int 'pi$ ':i$ 'ti;

"eclar "e fapt c intele celor trei pointeri au tipul int# Tipul abstract int", util &n multe alte situa ii, aici poate provoca confu%ii, instruc iunea
int' p1$ p2$ p3;

nu "eclar trei variabile "e tip int", a.a cu ar fi "e a.teptat, ci numai una, p1, celelalte "ou fiin" "e tip int# $ompilatorul o 4&n elege6 sub forma
int ('p1)$ p2$ p3;

2eclararea unui pointer ctre un tip compus (tablou, func ie) se face "up aceea.i regul ca &n ca%ul pointerilor ctre tipurile simple, "eclarm "e fapt tipul intei, "ar acum

mai trebuie sa inem cont .i "e prioritatea operatorilor implica i (amintim c operatorul unar < leag mai slab "ec;t operatorii postfi'a i ( ) .i * +)# 2e e'emplu, "aca "orim s "efinim un pointer p ctre un tablou "e () caractere, regula practic este urmtoarea, "efinim o variabil x "e tipul intei,
c!ar "[10];

"up care &nlocuim numele x cu inta lui p, a"ic "p, scris &ntre parante%e rotun"e,
c!ar ('p)[10];

7neori parante%ele rotun"e nu sunt necesare, "ar &n ca%ul "e mai sus ele nu pot fi omise, "eoarece "eclaratia
c!ar 'p[10];

nu "eclar un pointer ci un tablou "e () elemente "e tip c=ar<, a"ic un tablou "e () pointeri ctre c%ar# E'plica ie, &n "eclara ia "e mai sus asupra operan"ului p ac ionea% "oi operatori, < .i * +, cum operatorul "e in"e'are * + leag mai tare "ec;t operatorul int < compilatorul cite.te aceast ultim "eclara ie sub forma,
c!ar '(p[10]);

"e un"e "e"ucem c p este un tablou cu () elemente, fiecare element e al su fiin" "at "e "eclara ia pe care o ob inem &nlocuin" p'10( cu e
c!ar '(e);

care este ec=ivalent cu


c!ar 'e;

.i care "eclar pe e ca pointer ctre c%ar# Alt e'emplu, cu instruc iunea


double '#(int$ int);

"eclarm o func ie f cu "ou argumente int .i care &ntoarce un re%ultat "e tip double", a"ic un pointer ctre "ouble, iar cu instruc iunea
double ('#)(int$ int);

"eclarm un pointer f a crui int este "at "e "eclara ia


double tinta(int$ int);

a"ic este o func ie cu "ou argumente int .i un re%ultat "e tip double# In e'emplele "e mai sus observm utilitatea declaratorilor abstraci de tip secven e "e co" care "escriu tipurile compuse, cum ar fi int" (pentru tipul 4pointer catre int6), double", etc# 2eclaratorul abstract al unui anumit tip se ob ine .terg;n" pur .i simplu numele variabilei "in "eclara ia unei variabile "e acel tip# E'emple, ! "in int x ob inem int ) tipul int> ! "in double &at'10( ob inem double'10( ? tablou "e () elemente "e tip double> ! "in int "p ob inem int ", a"ic 4pointer ctre int6 ! "in c%ar ("ptab)'*( ob inem c%ar (")'*(, a"ic 4pointer ctre tablouri de tip c%ar '*(6 ! "in +oid ("p)(int, int) re%ult +oid (")(int, int) 4pointer ctre functii de tip +oid (int,int)6 b) Orice variabil pointer are o loca ie &n memorie ("e patru octe i (-8 9isual $::)), .i "eci are o a"res,
#include<iostream> using namespace std; int main(void) int 8=12;

int 'pi; pi=&8; cout<<%adresa lui pi &pi=%<<&pi<<endl; cout<<%valoarea lui pi pi=%<<pi<<% (adresa tintei)%<<endl; cout<<%valoarea tintei 'pi=%<<'pi<<endl; return 0; 0' @BHI=>C> adresa lui pi &pi=00121123 valoarea lui pi pi=00121150 (adresa tintei) valoarea tintei 'pi=12 6ress an7 8e7 to continue 9 9 9 '0

In e'emplul "e mai sus, e'presia &pi este un pointer ctre pi, "eci "e tip 4pointer ctre tipul lui pi6, cum tipul lui pi este int" ob inem c &pi este un 4pointer ctre int"6, a"ica "e tip int"" (pointer ctre pointer ctre int)# 9aloarea pointerului &p este a"resa intei sale, "eci a"resa variabilei pi# O variabil pointer pp creia s i se poat atribui valoarea constantei &pi trebuie "eclarat astfel,
int ''pp;

Aceast "eclara ie poate fi scris .i sub forma


int '('pp);

a"ic 4 inta intei lui pp este un int6# 7rmatoarea secven "e co" este ec=ivalent cu pre! ce"enta,
int 8=12; int 'pi=&8; int ''pp; pp=&pi; cout<<%adresa lui pi &pi=%<<pp<<endl; cout<<%valoarea lui pi pi=%<<'pp<<% (adresa tintei)%<<endl; cout<<%valoarea tintei 'pi=%<<''pp<<endl;

c) Operatorul & nu poate fi aplicat &n mo" succesiv, &x este o constant (entitate fr loca ie "e memorie) iar &&x, a"resa unei constante, nu are sens# In sc=imb, operatorul "e "ereferen iere < poate fi aplicat succesiv, at;t timp c;t re%ultatul fiecarei 4"ereferen ieri6 este tot "e tip pointer# ") Tipul pointerului trebuie respectat cu stricte e# 2e.i to i pointerii au valorile "e acela.i fel (a"rese), nu sunt permise atribuiri &ntre pointeri "e tip "iferit# E'emplu,
int 8; double 'g; g=&8;00 error A2330, cannot convert #rom Fint 'F to Fdouble 'F

Programatorul poate for a, pe propria raspun"ere, astfel "e atribuiri prin conversii e'plici! te utili%an" operatorul cast,
#include<iostream> using namespace std; int main(void) int .$8; double ..$'pp; 8=12; pp=(double ')&8;

..='pp; cout<<%..=%<<..<<endl; 00..=GJ9222J5e/051 .=(int)'pp; cout<<%.=%<<.<<endl; .='(int')pp; cout<<%.=%<<.<<endl; 00.=G213K343534 00.=12

..=(double)'(int')pp; cout<<%..=%<<..<<endl; 00..=12 ..=GJ9222J5e/051; .=(int)..; cout<<%.=%<<.<<endl; return 0;

00.=G213K343534

Observm c pointerul pp, "e tip double ", a fost &ncrcat (printr!o e'presie cast) cu a"resa unui &ntreg# Pentru a regsi &n mo" corect valoarea intei, trebuie s folosim iara.i o conversie e'plicit, e'presia (int ")pp are &n elesul, "e.i pp este "e tip double ", acum el este utili%at ca .i cum ar fi "e tip int "# Aceste conversii sunt necesare pentru c tipul intei preci%ea% formatul intern al "atei intite, iar formatul intern al unei "ate "e tip int este complet "iferit "e al uneia "e tip double# 7n ca% special &l constituie ponterii "e tip +oid "# 7n pointer p+ "e tip +oid " poate con ine, prin "efini ie, a"rese ctre "ate "e orice tip, &n consecin , la o atribuire ctre p+ nu mai sunt necesare conversii e'plicite, &n sc=imb inta sa, "p+, are tipul ne"eterminat .i trebuie preci%at prin e'presii cast,
c!ar c!$c=FCF; c!ar 'pc=&c; int n=1; int 'pn=&n; void 'pv; pv=pc; 00)L c!='pv; 00 error, illegal indirection c!='(c!ar ')pv; cout<<%reM1, c!=%<<c!<<endl; 00reM1, c!=C pv=pn; cout<<%reM2, n=%<<'(int ')pv<<endl; 00reM2, n=1 pc=pv; 00error, cannot convert #rom Fvoid 'F to Fc!ar 'F pc=(c!ar ')pv; 00)L

00

00

e) A"resele (valorile pointerilor), "e.i sunt e'primate prin numere &ntregi (ob inute &n urma numerotrii octe ilor "e memorie), nu sunt "ate "e tip &ntreg# In consecin , nu sunt permise atribuiri &ntre pointeri .i tipuri aritmetice# 8unt permise ("ar ne!u%uale) "oar conversii e'plicite &ntre pointeri .i tipul int#
int 8; double d=13913; double 'p;

p=&d; cout<<%p=%<<p<<% 'p=%<<'p<<endl;00p=00121120 'p=13913 8=(int)d; cout<<%8=%<<8<<endl; 008=1232004 cout<<!e"<<%8=%<<8<<dec<<endl; 008=12##20 8=1232004; p=(double ')8; cout<<%p=%<<p<<endl; 00p=00121120

Este permis, fr conversie e'plicit, numai atribuirea


double 'p; pd=0;

"eoarece %ero are o semnifica ie special &n acest conte't (ve%i mai 3os)# e) Ini iali%area pointerilor# $a orice variabil, un pointer trebuie "efinit .i ini iali%at &nain! te "e a fi folosit# 7tili%area unui pointer "efinit "ar neini iali%at con"uce la erori "e e'e! cu ie,
#include<iostream> using namespace std; int main(void) int 'pn; cout<<%adresa lui pn,%<<&pn<<endl; 00adresa lui pn,00121150 cout<<%adresa tintei lui pn,%<<pn<<endl; 00adresa tintei lui pn,AAAAAAAA cout<<%valoarea tintei lui pn,%<<'pn<<endl; 006lease tell Nicroso#t about t!is 00problemO -

In e'emplul "e mai sus &ncercm s citim un int aflat la a"resa $$$$$$$$=, care se "ove"e.te a fi intr!o %on prote3at memorie, fapt sanc ionat "e sistemul "e operare prin &ntreruperea e'ecutrii programului# 7nui pointer i se poate atribui &n mo" corect o valoare ini ial numai &n urmatoarele mo"uri, (# prin atribuirea a"resei unui obiect "e3a "efinit, "e e'emplu
int n=K; int 'pn; pn=&n; int 'p; p=PI==;

1# prin atribuirea valorii unui pointer "e3a ini itiali%at, &n particular a pointerului N7@@# Pointerul N7@@ este "e fapt o constant simbolic "efinit &n <stdio9!> "at, &n functie "e compilator, prin #de#ine PI== ((void ')0) sau prin #de#ine PI== 0 astfel &nc;t pAN7@@ atribuie pointerului p valoarea %ero, fapt care semnalea% c pointerul p con ine o a"res invali" (limba3ul $B$:: garantea% c %ero nu este a"resa nici unei loca ii "e memorie)# Ciblioteca <stdio9!> este inclus &n <iostream> .i nu trebuie cerut &n mo" e'plicit printr!o "irectiv include# In -8 9isual $:: D#) putem folosi "irect atribuirea pA)#

0# prin atribuirea a"resei unei loca ii "e memorie "in %ona alocat programului, a"res obtinut prin utili%area operatorului ne, (specific $::) sau a func iilor "e alocare "e memorie &alloc, calloc, etc (specific $)# O mo"alitate legal "ar cu efecte imprevi%ibile "e ini iali%are a unui pointer const &n atribuirea unei valori intregi printr!o e'presie cast,
c!ar 'pc; pc=(c!ar ')0"0012##50;

O astfel "e ini iali%are este complet =a%ar"at, programatorul nu poate .ti a priori care va fi %ona "e memorie alocat programului la rulare# In final, un e'emplu simplu "e utili%are a pointerilor ctre func ii,
#include<iostream> using namespace std; int ma"(int "$ int 7) return "<7 Q 7 , "; int min(int "$ int 7) return "<7 Q " , 7; int Mero(int "$ int 7) return 0; int main(void) int "$ 7; c!ar c; int ('p)(int$int); cout<<%"=%; cin>>"; cout<<%7=%; cin>>7; cout<<%tastati <N BP>B@> pentru ma"im sau <m BP>B@> pentru minim%<<endl; cout<<%c=%; cin>>c; 00numele unei #unctii este o constanta 00de tip pointer catre acea #unctie, i#(c==FNF) p=ma"; else i# (c==FmF) p=min; else p=Mero; cout<<%reMulatat=%<<('p)("$7)<<endl; return 0; -

S-ar putea să vă placă și