start     Articole     Despre mine     Contact     Cursul ABCprog    

Ce sunt pointerii si la ce sunt ei buni in programare

Multi programatori incepatori sufera de pointerofobie — adica o teama inexplicabila de pointeri. Si cum nu se poate scapa de teama de “Bau-bau”-ul din dulap decat mergand la dulap, deschizandu-l si vazand ca nu e acolo nimic de speriat, in acest articol te voi lua de mana si te voi duce la “dulapul” cu pointeri.

OK, dar mai intai: Ce sunt pointerii (caci poate nici macar n-ai auzit vreodata de ei)? Si la ce sunt ei buni?

Incep cu intrebarea “La ce sunt buni?” — ca sa intelegi ca sunt foarte importanti si ca merita sa studiezi cu mare atentie explicatiile ce urmeaza.

La ce sunt buni pointerii?

Folosesti Google si Facebook? Ai vazut cat de repede cauta informatiile solicitate (site-uri, conturi) printre milioanele de informatii disponibile?

Cum crezi ca se face asta? Oare la fiecare cautare ceruta de tine Google isi parcurge toate site-urile pe care le are inregistrate si le compara unul cate unul cu textul cautat?

N-ar fi prea placut sa se intample asa. Ti-ar trebui rabdare. Multa rabdare. Chiar extrem de multa rabdare.

Secretul cautarilor Google (ca si al oricarei aplicatii serioase pe care o folosesti (inclusiv browserul de pe care citesti randurile astea)) sunt structurile de date. Adica modalitati de organizare isteata a datelor.

Adica (mai pe romaneste (intr-o romana specifica celor care deja stiu bazele programarii)) e vorba despre modalitati de grupare isteata a variabilelor.

Doua modalitati de grupare a variabilelor ai vazut deja in lectia despre vectori si matrici. Da si vectorii si matricile sunt structuri de date si ne permit sa facem multe lucruri. Dar modalitatea prin care ele grupeaza variabilele e destul de limitata — le “aseaza” pe linii sau pe linii si coloane.

Dar daca am vrea sa grupam variabilele in moduri oarecare? Daca am vrea, de exemplu, sa le legam intre ele asa cum orasele dintr-o tara sunt legate prin drumuri?

Ne-ar trebui o modalitate de a “trasa drumuri” intre variabile — sau de a spune “variabila asta e legata de variabila astalalta”.

Pointerii ne permit sa facem acest lucru.

Datorita lor cresc arbori pe taramul programarii. 🙂
(Nu e o gluma. Arborii sunt o structura de date fara de care chiar nu imi imaginez cum ar fi aratat utilizarea calculatoarelor in prezent. (Probabil mai mult ne-am fi uitat la ele si le-am fi sters de praf decat sa le utilizam efectiv.))

Ce sunt pointerii?

Am spus deja ca pointerii sunt un fel de “legaturi” intre variabile. Adica printr-un pointer putem spune ca “variabila A e lagata de variabila B” sau ca “exista un drum care leaga orasul A de orasul B” sau ca “dosarul A se gaseste plasat in interiorul dosarului B”.

Deci ce e un pointer, mai precis? Uite figura asta:

Pointerul este “sageata” care arata catre variabila B.

Uau! N-a fost greu, nu? Pointerii sunt “sageti”, deci. (Nu e de mirare, atunci, ca atat de multi programatori in devenire sunt speriati de ei.) 🙂

Serios vorbesc. Asa “traiesc” pointerii in mintea mea. Daca nu i-as “vedea” sub forma grafica chiar nu stiu daca as fi in stare sa lucrez cu ei. (Caci eu nu sunt “matematician”, ci “desenator” (deci nu lucrez cu notiuni abstracte, ci cu forme concrete).)

Acum vine partea a doua: Cum “desenezi” o “sageata” intr-un program?

Ei bine… printr-o variabila! (Si uite cum iar te-am bagat in ceata…) 🙂

Cum implementezi practic un pointer?

Am zis, deci, ca un pointer este un fel de sageata care arata catre o variabila si ca el poate fi realizat practic intr-un program cu ajutorul unei (alte) variabile. Deci e cazul sa reluam (un pic mai aprofundat acum) notiunea de variabila.

Ce era o variabila?… (Iti amintesti?)

O variabila e o entitate (ca sa nu zic “chestie”) care tine in ea o valoare si are un nume.

In programul pe care il scriu ii folosesc numele, dar de fapt lucrez cu valoarea stocata in ea. De exemplu, daca am variabila a

var a;

atunci cand scriu

a = 3;

inlocuiesc valoarea care se gasea in variabila a cu valoarea 3. Iar daca apoi scriu

a = a+4;

mai intai (calculez valoarea expresiei din dreapta operatorului de atribuire, adica) calculez valoarea expresiei “a+4” (iar rezultatul este “(valoarea stocata in variabila a) plus (valoarea 4)”), adica 7 (daca tin cont de faptul ca prin instructiunea precedenta (“a = 3;”) am pus in variabila a valoarea 3) si apoi (realizez atribuirea “a = 7”, adica) in variabila a stochez valoarea rezultata prin evaluarea expresiei, adica valoarea 7; deci in urma executarii acestei instructiuni variabila numita a va avea valoarea 7.

Aceasta instructiune (“a = a+4”) este interesanta pentru ca iti arata ambele moduri in care o variabila poate fi folosita intr-un program, adica pentru:

– citire valoare (atunci cand numele variabilei apare in expresii (iar la evaluarea acestor expresii numele va fi inlocuit automat cu valoarea continuta de variabila))

– scriere valoarea (atunci cand numele variabilei apare in stanga operatorului de atribuire (iar la executarea operatiei de atribuire valoarea veche a variabilei va fi inlocuita cu noua valoare)).

Hai sa revenim. Ziceam ca o variabila e o chestie (entitate, pardon) care tine in ea o valoare si care are un nume…

Completez (in urma discutiei anterioare) aceasta definitie cu:

… pe care il pot folosi fie pentru a citi valoarea memorata in variabila, fie pentru a scrie o noua valoare in variabila.

(Sau, altfel spus, variabila este ceva care contine o valoare si care are un nume cu ajutorul caruia poate fi accesata acea valoare.)

Buuun, dar astea le stiai deja, nu?

Si cred ca mai stiai si ca variabilele sunt depozitate in memoria calculatorului. De fapt, in realitate ele sunt mici “bucatele” din memoria calculatorului.

Ceea ce probabil ca nu stiai pana acum este faptul ca memoria calculatorului seamana foarte mult cu un vector urias. Adica este formata din foarte multe bucati mici (numite locatii de memorie) asezate in linie una langa alta si care pot fi accesate prin indici.

Adica daca memoria calculatorului ar fi un vector numit mem (de 1000 de elemente, sa zicem (desi in realitate un numar de la un miliard in sus ar fi mai veridic))

var mem = Vector(1000);

atunci prima locatie de memorie ar fi mem[0], ultima locatie de memorie (adica cea de-a o mia locatie) ar fi mem[999] si orice locatie de memorie ar putea fi accesata printr-un indice, astfel: mem[i] (unde in cazul asta indicele i poate avea valori intre 0 si 999 inclusiv).

Heeei! Dar daca-i asa, asta nu inseamna ca variabilele mai au si o alta caracteristica in afara de valoare si nume — si anume indicele la care se gasesc plasate in memorie?

Pai da. Am zis ca memoria e ca un vector in care locatiile de memorie sunt elemente (deci pot fi accesate prin indici). Si am mai zis ca variabilele sunt in realitate locatii de memorie.

Deci atunci cand definesc o variabila a, ea va fi plasata in (vectorul) memorie la o anumita pozitie (adica la un anumit indice in vector). Indicele din memorie la care este plasata variabila a poarta numele de “adresa” variabilei a.

Asadar, variabila este o entitate caracterizata de:

valoarea stocata in ea (la momentul curent din executia programului)

numele (folosit pentru a-i accesa valoarea (fie pentru citire, fie pentru scriere))

– si adresa la care este plasata variabila in memoria calculatorului (care este organizata ca un vector in care elementele pot fi accesate prin indici (sau adrese)).

Oof, cam lunga discutia, nu? Probabil ai si uitat despre ce vorbeam.

Era vorba despre pointeri si despre faptul ca un pointer este o “sageata” care “arata catre” o variabila. Si ziceam ca poti implementa un pointer folosind o variabila.

Cum implementezi practic un pointer? (pe bune, acum)

Faptul ca variabila are si adresa e ca si cum ar avea un al doilea nume.

Sa zicem ca variabila a este plasata in memorie la adresa 10. Atunci ma pot referi la ea in doua moduri echivalente:

– 1) variabila numita a

– 2) variabila care se gaseste in memorie la adresa 10.

Pentru a putea vizualiza lucrurile, sa zicem ca memoria ar fi un vector mem (asa cum am discutat mai sus) si ca mai am in program inca doua variabile: variabila b, plasata la adresa 13, variabila c, plasata la adresa 7 si variabila p, plasata la adresa 2.

Adica ceva gen:

Asta inseamna ca atunci cand accesez variabila a accesez de fapt locatia de memorie de la adresa 10, adica elementul mem[10] din vectorul mem.

Similar, variabila b este de fapt elementul mem[13], variabila c este elementul mem[7], iar variabila p este elementul mem[2].

(Numele variabilelor este doar o simplificare pentru programator (caci in realitate calculatorul foloseste adresele variabilelor pentru a accesa locatiile de memorie corespunzatoare lor).)

Hei, dar era vorba despre pointeri si despre cum poti face un pointer folosind o variabila!

Uita-te, te rog, la variabila p. E o variabila ca oricare alta, doar ca vreau s-o fac pointer — adica “sageata” care sa-mi “arate catre” o alta variabila (sa zicem, catre variabila a).

Cum pot face asta? Stocand in p adresa variabilei a, adica 10. Voila !

Dar daca voiam ca pointerul p sa “arate catre” variabila b? Evident, puneam in el adresa variabilei b, adica 13.

OK. Ai vazut cum poti face ca pointerul p sa arate catre o variabila.

Dar cum poti face sa folosesti acea variabila? (Adica s-o accesezi.) Sa zicem ca vrei sa pui in variabila c valoarea variabilei “pointate” de catre pointerul p. Pai, simplu:

c = mem[p];

Daca p “pointa” catre a (deci in p era adresa variabilei a, adica 10), efectul intructiunii anterioare este “c = mem[10]” (adica “c = a”, practic). Iar daca p pointa catre b (adica in p era valoarea 13 (care este adresa lui b)), efectul instructiunii anterioare este “c = mem[13]” (adica, practic, “c = b”).

Deci asa faci citirea.

Dar daca vrei sa scrii in variabila “pointata” de catre pointerul p valoarea variabilei c? Tot simplu (daca ai inteles cum functioneaza vectorii):

mem[p] = c;

Daca p pointa catre a (deci in p era 10), efectul instructiunii e “mem[10] = c” (adica practic “a = c”). Iar daca p pointa catre b (deci in p era 13), efectul instructiunii e “mem[13] = c” (adica practic “b = c”).

In concluzie

Pointerii din programare sunt o banalitate. Dar asta e valabil doar daca ai inteles bine ce e o variabila si mai ales ce e si cum se foloseste un vector de variabile.

Deci nu pointerii sunt dificili, ci dificil e sa iti antrenezi mintea sa lucreze cu variabile nu folosindu-le numele, ci folosindu-le adresele. Adica sa nu le mai identifici folosind nume, ci sa le identifici folosind numere.

Altfel spus, daca vrei sa te imprietenesti cu pointerii, e cazul sa-ti bagi variabilele la “puscarie” si sa le vorbesti pointerilor (care sunt un fel de gardieni docili, dar tacuti, incruntati si fara simtul umorului) pe limba lor — adica nu le spune despre “detinutul” Andreea, ci despre “detinutul” din celula 137. 🙂

Javascripticul nostru limbaj de programare minimalist nu permite folosirea (explicita a) pointerilor (asa cum o permit limbaje ca C si C++), dar iti poti face “antrenamentul” foarte bine folosind un vector mem (asa cum am discutat mai sus). De exemplu, spune-mi, te rog, cat face suma variabilelor a si b in urma rularii programului urmator:

var mem = Vector(100);
// Variabila a e plasata in mem la adresa 75.
// Variabila b e plasata in mem la adresa 13.
var pointer;
pointer = 13;
mem[pointer] = 75;
pointer = pointer+62;
mem[pointer] = 13;
mem[pointer] = mem[pointer] * 100;
// Deci cat este acum a+b?…

 

Lasa-mi raspunsul intr-un comentariu mai jos. Recomand foaie si pix. (Caci daca reusesti sa inveti pointerii fara elementele astea doua, atunci eu sunt cel care are nevoie de lectii de la tine.) 🙂

 

Alatura-te celor peste 3600 de oameni din armata noastra de creiere cu muschi si vei primi testul care iti va spune daca ai sau nu minte de programator:

(nu trimit spam; te tin la curent cu noutatile)

 

 

Cu drag,

Florin





Loading Facebook Comments ...