*
 * Veniamo ora all'utilizzo dei puntatori.
 * Premetto che i puntatori non sono presenti nel Java, quindi non troverete
 * molti esempi... e se usate questo tutorial solo come preparazione al Java,
 * vi consiglio di saltare l'argomento.
 * Un puntatore e' una variabile contenente un indirizzo di memoria.
 * Questo indirizzo puo' essere l'indirizzo dove si trova un'altra variabile,
 * un'array, una funzione o qualsiasi altra cosa.
 * Se una variabile contiene l'indirizzo di un'altra variabile, si dice che
 * la prima punta alla seconda.
 * Occorre a questo punto chiarire cosa e' un indirizzo di memoria.
 * La memoria si misura in byte, per cui un Kb sono 1024 byte e 1MB sono
 * un milione di byte circa. Un Kb sono 1024 byte perche' si basa sulle
 * potenze del 2 (2,4,8,16,32,64,128....): questi numeri si trovano
 * continuamente, infatti ogni bit in piu' o in meno che si ha a disposizione
 * nella notazione binaria (0 o 1 solamente) raddoppia le possibilita'
 * numeriche componibili.
 * Un byte a sua volta e' composto da 8 bit, per cui 2 byte sono 16 bit e
 * 4 byte sono 32bit.
 * La memoria e' organizzata come una serie consecutiva di byte, come fosse
 * un unico grande array monodimensionale di tipo char.
 * In realta' tra processori diversi e modi diversi di operare di questi ci
 * possono essere delle variazioni, come la segmentazione in blocchi di 64k,
 * ma la regola della fila di byte consecutivi e' universale.
 * Quando si usa il sistema operativo (DOS/WIN o altri) non ci accorgiamo di
 * questo, semplicemente possiamo sapere quanta memoria e' libera, e cio'
 * viene espresso in byte.
 * Avendo stabilito che la memoria e' una serie di byte consecutivi, come
 * si fa a distinguere un byte da un'altro?
 * Abbiamo fatto il paragone con un array monodimensionale: se ricordate
 * per accedere ai singoli byte si deve specificare un indice, ossia il
 * numero del byte, considerando il primo come lo 0, il secondo come l'1
 * e cosi' via.
 * Ebbene, la memoria e' organizzata in questo modo: ogni byte ha un
 * indirizzo, come se la memoria fosse una strada con le case tutte uguali
 * e solo da un lato, ognuna delle quali e' un byte: il numero civico di
 * quelle case e' il loro indirizzo.
 * Per esempio, l'indirizzo 0 indica il primo byte della memoria, mentre
 * l'indirizzo 100 indica il 101esimo byte di memoria.
 * Quindi, l'indirizzo 100 dista dal 115 ben 16 byte!
 * E' ovvio che in sistemi con molta memoria, questa puo' non essere un
 * unico blocco da 0 ad x, ma ci possono essere vari blocchi di 1MB o piu'
 * non consecutivi.
 * Abbiamo detto che i puntatori "puntano" ad un indirizzo.
 * Quando compiliamo un programma in C, anche se non ce ne accorgiamo, non
 * facciamo che far scrivere in memoria le istruzioni assembly relative
 * alle funzioni che chiamiamo, assieme a blocchi di dati, ossia le
 * variabili e gli array. Ogni funzione e ogni variabile o array sara'
 * quindi posizionata ad un certo indirizzo preciso in memoria, che noi
 * non conosciamo, perche' tutto avviene automaticamente.
 * Mettiamo che la variabile pippo, di tipo intero, venga posizionata
 * all'indirizzo 1000: in questo caso quando scriviamo o leggiamo pippo,
 * fisicamente si legge e si scrive alla locazione 1000.
 * Quindi un puntatore che "punta" a pippo, conterra' l'indirizzo 1000,
 * ossia l'indirizzo di pippo.
 * In altri termini contiene la sua posizione in memoria.
 * Occorre specificare un'altra cosa: non tutti i tipi di variabile
 * occupano lo stesso spazio in memoria.
 * Per esempio, le variabili char occupano 1 solo byte, mentre gli int ne
 * occupano 2, e i float ben 4.
 * Questo significa che se abbiamo un array composto da 4 elementi di tipo
 * char, l'array in totale sara' lungo 4 byte.
 * Se abbiamo un array composto da 4 elementi di tipo int, occupera' ben
 * 8 byte, ossia 2*4.
 * Se infine l'array fosse composto da 4 elementi di tipo float, la
 * lunghezza complessiva sarebbe di 4*4=16 byte.
 * Supponendo che quest'ultimo array di tipo float si trovi a partire
 * dall'indirizzo 1000, il secondo elemento inizia all'indirizzo 1004, il
 * terzo all'indirizzo 1008, il quarto a 1012. L'array quindi va da 1000
 * a 1016.
 * Quando operiamo con un array, pero', basta mettere il numero di elemento
 * come indice, e il C a seconda del tipo di dato salta 1, 2 o 4 byte per
 * individuare l'elemento successivo.
 * Quando si opera con i puntatori occorre sapere queste cose, perche'
 * al momento della dichiarazione di un puntatore si deve stabilire a che
 * tipo di dato puntera', per cui quando lo incrementeremo saltera'
 * 1,2 o 4 byte a seconda del tipo a cui punta. Ad esempio:
 *
 *	int *conta1;
 *	char *conta2;
 *
 *	*conta1++	* punta al prossimo int (incrementa di 2 bytes)
 *	*conta2++	* punta al prossimo char (incrementa di 1 byte)
 *
 * Inoltre, quando si fanno degli assegnamenti con un puntatore, saranno
 * trasferiti 1,2, 4 o piu' bytes dall'indirizzo a cui punta, a seconda
 * del tipo a cui punta. Se il puntatore e' stato definito come puntatore
 * di tipo char, e si copia in una variabile int, sara' trasferito solo
 * 1 byte (non 2) nella variabile int, dall'indirizzo a cui puntava il
 * puntatore. Se puntava un dato di tipo float avrebbe copiato troppo, 4
 * bytes. Questi errori portano a malfunzionamenti seri dei programmi e
 * di tutto il sistema operativo con pericoli di inchiodamento.
 * Veniamo alla sintassi di dichiarazione di un puntatore:
 *
 *	tipo *nomepunt;
 *
 * Ad esempio:
 *
 *	int *puntapippo;
 *
 * La dichiarazione e' simile a quella delle variabili, ma il nome deve
 * essere preceduto da un asterisco.
 * Ricordiamo che il tipo indica il tipo di dato a cui puo' puntare.
 * Come usiamo un puntatore?
 * Esistono 2 operatori puntatore, che devono precedere le variabili e i
 * puntatori in questo modo:
 *
 *	&pippo
 *	*pippo
 *
 * Vediamoli in dettaglio:
 *
 *	&	Indica l'INDIRIZZO (la posizione) in memoria della variabile
 *
 *  	*	Fa accedere al CONTENUTO della variabile puntata.
 *              Da non confondere con la moltiplicazione.
 *
 * Quindi, una volta definito un puntatore, se vogliamo immetterci
 * l'indirizzo di una variabile, dobbiamo usare &:
 *
 *	int	*puntapippo;	* Definisco un puntatore di interi
 *	int	pippo;		* Definisco una variabile intera
 *
 *	puntapippo = &pippo;	* Immetto nel puntatore puntapippo
 *				* l'indirizzo di pippo, ossia lo faccio
 *				* puntare a pippo.
 *
 * Allo stesso modo, ora che puntapippo punta a pippo, posso accedere
 * indirettamente a pippo tramite *puntapippo:
 *
 *	*puntapippo = 100;	* Scrivo 100 nella variabile pippo tramite
 *				* il puntatore puntapippo.
 *
 *	printf("Pippo vale %d ", pippo);	* Pippo vale 100! *
 *
 * Vediamo funzionare questo programmino di esempio.
 */

#include 	/* Includiamo la libreria standard */

/* Funzione principale e inizio del programma */

int main(void)		/* Funzione principale, eseguita per prima */
{			/* Inizio della funzione main() */

	int	*puntapippo;	/* Definisco un puntatore di interi */
	int	pippo;		/* Definisco una variabile intera */

	pippo = 50;		/* Assegno a pippo il valore 50 */

	puntapippo = &pippo;	/* Immetto nel puntatore puntapippo
				 * l'indirizzo di pippo, ossia lo faccio
				 * puntare a pippo. */

/* Allo stesso modo, ora che puntapippo punta a pippo, posso accedere
 * indirettamente a pippo tramite *puntapippo: */

	*puntapippo = 100;	/* Scrivo 100 nella variabile pippo tramite
				 * il puntatore puntapippo. */

	printf("Pippo vale %d ", pippo);	/* Pippo vale 100! */

	return(0);	/* la funzione main restituisce uno 0 intero */
} 			/* Fine della funzione main() */


/* Una nota: avete presente la sintassi dello scanf, in cui la variabile
 * deve essere preceduta da &?
 * Ebbene, la funzione scanf vuole in entrata l'indirizzo della variabile
 * dove salvare il dato introdotto da tastiera.
 * Come vedete i misteri si stanno chiarendo tutti.
 */