I puntatori in linguaggio C

Che cos’è un puntatore ?

Un indirizzo di memoria pari alla dimensione del tipo di valore che da memorizzare, serve per gestire i dati in memoria dinamica.
L’uso dei puntatori è richiesto quando occorre utilizzare strutture dati dinamiche astratte che implementano al loro interno delle operazioni quali le liste, le code, le Pile, gli alberi e i grafi molto utilizzati in molti programmi di informatica avanzati e software di uso comune.
Il puntatore è un indirizzo di un’area di memoria che ha una dimensione pari al tipo di dati che viene allocato; ad esempio un puntatore ad int è identificato ad un’area di memoria di 4 byte, un puntatore a char alloca un byte, un puntatore a double 8 byte.
I puntatori sono usati anche per allocare aree di memoria che sono utilizzate per accogliere un array, una matrice, una struct o un array di record.

La notazione di un puntatore è fatta con l’operatore «*»; ad esempio int *x puntatore a intero, char *c puntatore a carattere.

Inizialmente il puntatore non è riferito a nulla alla sua dichiarazione

Attraverso l’operatore di de-refernziazione «&» è associato ad un dato specifico ad esempio int x; int *p; p=&x;
p contiene l’indirizzo di memoria associata alla cella di memoria di «x»

Quanto esposto è valido per l puntatori a dati di tipo semplice, per i dati strutturati quali vettori e matrici occorre utilizzare delle istruzioni specifiche delle libreria stdlib.h.
Per allocare un vettore ad esempio:
Il puntatore punta sempre alla prima locazione di memoria dati della struttura ad esempio:
int x[10]; int *p; p=&x[0]  
Il puntatore punta sempre alla prima locazione di memoria dati della struttura ad esempio:
int x[10]; int *p; p=&x[0];
Per un array è possibile utilizzare anche l’istruzione malloc con la sintassi
int *v;
v=(int)malloc(dimensione*sizeof(int));
ove dimensione è la variabile o il valore intero positivo che definisce il numero degli elementi dell’array.
In sintesi:
malloc è usata per allocare  memoria ad esempio
int *x = malloc(10*sizeof(int));.
Con l’istruzione sopra menzionata è allocato un array di interi di 10 interi.
L’istruzione free(puntatore) libera la memoria dopo è opportuno azzerare il puntatore a NULL.

E’ necessaria la liberia stdlib.h per l’uso delle funzioni malloc e free.
E’ qui mostrato un codice di esempio per gestire una matrice in modo dinamico di nr righe e nc colonne. L’allocazione qui esposta non è contigua poiché ogni riga composta da celle è un elemento puntatore di un array di puntatori e quindi non necessariamente contigua in memoria HEAP.
L’allocazione contigua prevede per esempio per una matrice 10 x 20 elementi:
int nr=10, nc=20;
int **mat=(int**)malloc(nr*sizeof(int*));
mat[0]=(int*)malloc(nr*nc*sizeof(int));
per il caricamento o stampa degli elementi cambia il ciclo for, è lasciato al lettore per esercizio.

Codice di esempio per caricamento e stampa di matrice con allocazione dinamica non contigua della memoria.

#include <stdio.h>
#include <stdlib.h>
main()
{
	int **mat;
	int nr, nc;
	int i,j;
	printf("\n Inserisci il numero delle righe della matrice:");
	scanf("%d",&nr);
	printf("\n Inserisci il numero delle colonne della matrice:");
	scanf("%d",&nc);
	mat=(int**)malloc(nr*sizeof(int *));
	for (i=0;i<nr;i++)
		mat[i]=(int *)malloc(nc*sizeof(int));
	for (i=0;i<nr;i++)
		for (j=0;j<nc;j++)
			{
				printf("\n Inserisci elemento di riga, colonna: %d, %d:",i+1,j+1);
				scanf("%d",&mat[i][j]);
			}
	printf("\n Stampa della matrice:\n");
	for (i=0;i<nr;i++)
		for (j=0;j<nc;j++)
			{
				printf("\n Elemento di riga, colonna: %d, %d:-->",i+1,j+1);
				printf("%d",mat[i][j]);
			}
	for (i=0;i<nr;i++)
		free(mat[i]);
	free(mat);
	mat=NULL;
	return;
}

Video della lezione n.14 – Linguaggio C