int **a,b=5,c=4;

*a=&b;
**a=&c;
**a è il valore della variabile a cui punta, tu l' hai fatta puntare a b,quindi **a vale b, *a è l' indirizzo di b.
a è l' indirizzo della cella di memoria in cui è contenuto l' indirizzo di b come valore.
L' assegnazione:
codice:
**a=&c;
Non è valida,perchè **a è un valore,un indirizzo è un valore esadecimale, mentre se a è un intero ti segna errore o avviso perchè con questa assegnazione si aspetta un valore intero.

Ti faccio un esempio su come usare il puntatore del puntatore.
Ad esempio scrivo:

codice:
char **array;
Adesso ho un puntatore a puntatore,che per adesso è vuoto.
Per iniziare a fare le assegnazioni devo prima allocargli della memoria,se voglio 5 puntatori posso dichiarare:

codice:
array=(char**)calloc(5,sizeof(char*));
Allora adesso ho lo spazio per contenere 5 puntatori.
Facciamo finta che io ho 5 stringhe già inizializzate:

codice:
char a[]="ciao",b[]="come",c[]="stai",d[]="?",e[]="ciao";
Questi 5 puntatori li posso usare per farli puntare a queste stringhe:

codice:
array[0]=&a;
array[1]=&b;
array[2]=&c;
array[3]=&d;
array[4]=&e;
Oppure posso usarli per creare stringhe dinamiche,della misura che voglio:

codice:
array[0]=(char*)calloc(5,sizeof(char));
strcpy(array[0],"ciao");
......
array[3]=(char*)calloc(2,sizeof(char));
strcpy(array[3],"?");
....
Posso anche riallocare l' array di puntatori,un puntatore a puntatore non è altro che un array di puntatore,una collezione di puntatori che posso usare fìper farli puntare ciascuno a un suo indirizzo a mio piacimento.
Il che equivale a una matrice non regolare di caratteri del tipo:

codice:
ciao
come
stai
?
ciao
Come vedi non è regolare,puoi anche creare il puntatore del puntatore del puntatore se hai fegato