- Quan definim una variable d'un cert tipus, es reserva espai a memòria per contenir el valor de la variable, en funció del tipus. El nom de la variable queda associat a l'adreça de memòria on comença aquest espai reservat:
- Quan actualitzem una variable, canvia el valor de les posicions de memòria assignades a aquella variable. Si no inicialitzem una variable abans de llegir el seu contingut, el seu valor serà indeterminat.
- Per fer referència al valor d'una variable escribim el seu nom. Per fer referència a l'adreça d'una variable disposem de l'operador d'adreça `&' col.locat davant del nom de la variable. Per exemple, si vull escriure l'adreça i el contingut de la variable c, ho puc fer amb printf() de la següent forma (el codi de printf per escriure punters és `%p'):
printf("Variable c\tadreça: %p\tvalor: %c\n", &c, c);
- Les variables de tipus punter són aquelles que el seu valor és l'adreça d'una altra variable. Per tant, una variable de tipus punter té una adreça i unes posicions de memòria assignades, però el seu valor "apunta" a un altre lloc de la memòria.
- Per definir una variable punter cal especificar el tipus de les variables on apuntarà, més el nom de la variable punter precedit per un asterisc `*'. Per exemple, es pot definir un punter a variables de tipus enter de la següent forma: "int *pa;". Un punter a int no pot apuntar a un char, per exemple. És a dir, el compilador fa verificació de tipus sobre els apuntadors (cosa que no passa amb el llenguatge assemblador).
ex 3.1: PUNTER.C és un programa que mostra com declarar una variable punter, com assignar-li una adreça d'una altra variable, i com escriure les adreces i el contingut de variables "normals" i de variables punter (el valor d'una variable punter és una adreça):
#include <stdio.h> void main(void) { int a, b; int *pa; a = 160; b = 30; pa = &a; /* pa pren per valor l'adreça d' a */ printf("Variable a\tadreça: %p\tvalor: %d\n",&a,a); printf("Variable b\tadreça: %ptvalor: %d\n",&b,b); printf("Variable pa\tadreça: %ptvalor: %p\n",&pa,pa); }
- A partir del moment en què una variable punter està apuntant a algun lloc concret de la memòria, es pot accedir a aquella posició a través del punter com si accedíssim a una variable (del tipus que s'apunta). Es tracta de l'accés indirecte. S'hi accedeix escrivint el nom de la variable punter precedit de l'asterisc. Conceptualment, si definim la variable int *pa; tindrem la següent informació:
&pa : adreça variable pa pa : contingut variable pa = punter a variable int *pa : contingut de la variable int apuntada per pa = valor enter
D'alguna forma, si he definit "int *pa; " podem considerar que "*pa " és una variable de tipus int i, per tant, podem operar de la mateixa manera (llegir el seu valor, actualitzar-la, incrementar-la, etc.). Cal tenir present, però, que la variable pa sempre ha d'estar apuntant a alguna variable entera, i que modificant *pa estarem modificant el contingut de la variable entera referenciada.
ex 3.2: PUNTER2.C mostra diverses operacions fent servir l'accés a través d'un punter (accés indirecte). Fixar-s'hi que el punter pot referènciar a qualsevol variable (prèvia inicialització):
#include <stdio.h> void main(void) { int a,b; int *pa; a = 160; /* inicialitzem a */ b = 30; /* inicialitzem b */ pa = &a; /* pa apuntarà a a */ b = *pa; /* b pren per valor el contingut d' a, a través de pa */ *pa += 10; /* sumo 10 a a, a través de pa */ pa = &b; /* pa apuntarà a b */ ++(*pa); /* autoincremento b, a través de pa */ printf("Valor a: %d\n",a); printf("Valor b: %d\n",b); printf("Valor *pa: %d\n",*pa); /* imprimirà el valor de b!!! */ }
- Si una variable no s'inicialitza, el seu valor és indeterminat. Si un punter no s'inicialitza, apunta a un lloc indeterminat de memòria. Cal inicialitzar sempre els punters abans de fer-los servir. Per treballar amb punters buits (que temporalment no apuntin enlloc), es poden inicialitzar a un valor especial anomenat NULL (punter nul). NULL és una constant simbòlica que està definida a la majoria de Headers estàndard (STDLIB.H, STDIO.H, STRING.H, etc.).
cex 3.1: Com a contraexemple provar de posar la inicialització de pa sobre a entre comentaris. L'accés on apunta una variable punter no inicialitzada és totalment imprevissible (es pot "penjar" l'ordinador):
#include <stdio.h> void main(void) { int a,b; int *pa; a = 160; b = 30; /* pa = &a; */ b = *pa; *pa += 10; pa = &b; ++(*pa); printf("Valor a: %d\n",a); printf("Valor b: %d\n",b); printf("Valor *pa: %d\n",*pa); }
- Si un punter ha d'estar assignat sempre a una única variable, el podem inicialitzar quan el declarem, tot i que sempre el podrem canviar posteriorment:
void main(void) { int a = 160, b = 30; int *pa = &a; b = *pa; *pa += 10; pa = &b; ++(*pa); etc.
- Editeu el fitxer EXERCI_1.C i substituïu els interrogants per les instruccions que implementin el que es demana en els comentaris adjunts. El resultat ha de ser:
x = 16 y = 4 z = 7