Punters Basics

NOTA: Aquest article s'ha escrit like loc i conté faltes d'ortografia i montonades de polls. Li fa falta una revisió.

Qué es un punter?

Anem a començar vegent qué es una variable normal o, en realitat, com es guarda en memòria.

img1.png

Podem imaginar la memòria com una ristra de bytes o celdes. Cada celda conté informació i, a més, segons el seu ordre, te una adreça. Així, en el dibuix, la primera celda conté com a informació "45" i te l'adreça "1".

Quan declarem una variable, per exemple la següent:

int peiv;

En realitat el que fem es reservar el espai necessari per a eixa variable en algún lloc de la memòria (el lloc el decidirà el sistema segons li convinga, i no ens importa). En aquest cas, un enter ocupa 4 bytes:

img2.png

Ara ja podem donar-li valor a la variable:

peiv = 4;

lo qual es reflectirà en la memòria de la següent forma:

img3.png

Quan eixim del programa (o si la variable era local a una funció, pos quan eixim d'eixa funció) el sistema alliberarà la memòria que usava eixa variable, ja que sap que ja no es necesita. Per ara està tot molt clar, no?

A tot açò li anomenarem memòria estàtica.

Val pero, qué es un punter??

Un punter es declara de forma pareguda a una variable:

int *peiv2;

Pero siga del tipus que siga, sempre reserva 4 bytes en memòria (be, en sistemes de 64 bits en reservarà 8. 4bytes=32bits, 8bytes=64bits):

img4.png

Per qué? perque no ha reservat memòria per a un enter, sinò per a un punter. En realitat el valor que conté la zona de memòria reservada per a "peiv2" es la adreça en memòria on està guardat el enter que volem. El que pasa es que, nomes declarar el punter, el sistema encara no ha reservat un espai per a eixe enter. De fet, l'adreça que conté es "basura" que hi havia abans en eixa zona de memòria. Així, el que tenim que fer abans de usar un punter es reservar memòria per a ell. Ho farem amb la funció "malloc", que espera com a paràmetre el nombre de bytes a reservar i torna, com a resultat, l'adreça a la zona de memòria on ha reservat memòria:

peiv2 = (int*)malloc(sizeof(int));

Primer: Per què el "(int*)" eixe? Pos mira, malloc sempre retorna una punter a char. Com el que volem es un punter a enter, tenim que fer un casting. En C, un casting es fà ficant, davant de la expressió, i entre parentesi, el tipus al que volem transformar. I el que volem es un punter a enter.
Segon: "sizeof" ens dona el tamany, en bytes, de un tipus. Així no ens tenim que preocupar de quant ocupa un int.

Be, al reservar memòria per al punter, el sistema ha buscat una zona lliure de memòria, l'ha reservat (ell ja no la usarà per a res més fins que no la alliberem) i ens ha tornat la seua adreça. La cosa quedaría així:

img5.png

I si fem el següent:

*peiv2 = 6;

El que obtenim es el següent:

img6.png

Ara si mirem qué conté la variable "peiv2" vorem que conte "2". Si el que volem es el valor enter al que apunta, tenim que mirar qué conté la variable "*peiv2", que serà "6".

Per últim, un punter sempre s'ha d'alliberar a mà. Si no ho fem, la memòria es quedarà pillada, donant lloc als tipics "memory leaks". Un punter s'allibera usant la funció "free()":

free(peiv2);

A tot açò l'anomenarem memòria dinàmica.

I que es aixó del "&"?

Fins ara el que havem vist dels punters es la inferencia. O siga, tenim una caixeta que guarda l'adreça a altra caixeta. L'operador "&", o operador de referencia el que fa es el contrari. Si recordem el primer exemple, en el que declaravem la variable "peiv" i haviem vist con quedava en la memòria, si fem el següent:

&peiv;

El que obtenim es "1", o siga, l'adreça d'eixa variable. Per tant, podem fer coses com:

int *peiv2 = &peiv;

Amb lo qual li donem a "peiv2" l'adreça de "peiv". Fixat que aleshores no fa falta reservar ni alliberar memòria, ja que el punter apuntarà a l'adreça de memòria de "peiv", que el sistema ja ha reservat automaticament i que també alliberarà automàticament. El mateix passaria de la següent forma:

int *peiv2;
int *peiv3;
peiv2 = (int*)malloc(sizeof(int)); //reservem memòria per a peiv2
*peiv2 = 4; // ara *peiv2 val 4
peiv3 = peiv2; // ara peiv3 apunta al mateix lloc que peiv2, per tant *peiv3 també val 4
*peiv3 = 6; // com els dos apunten al mateix lloc, ara *peiv2 també val 6
free(peiv3); // i amb alliberar uno dels dos ja hi ha prou, ja que realment nomes hi ha un lloc reservat.

Si se t'ha fet lios, no et preocupes, l'important es entendre el següent resum:

  • Un punter nomes apunta a un valor, pero no el manté.
  • Si la memòria necesaria per a mantindre eixe valor no està ja reservada anteriorment, tenim que reservala i, posteriorment, alliberarla.
  • Podem obtindre l'adreça en memòria de qualsevol variable amb l'operador "&"
  • Un valor pot estar referenciat per molts punters.
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License