Se dici che funziona non perdo tempo a controllarlo, anche perché non ho capito il senso di alcune variabili (tipo "s" o "mode"...) e funzioni (azzera() e soluzione())

Comunque in tutta sincerità questa funzione

codice:
char** nuova(int l, int h, char **p){
   int i, j;

   p=(char **) malloc( h * sizeof(char *));

   for (i=0; i<h; i++){
      p[i]=(char *) malloc( l * sizeof(char));
   }

   return p;
}
scritta così non mi piace molto, perché quando un parametro è sia di input che di output è "carino" passarlo per riferimento... ora poiché il parametro in questione è già un puntatore a puntatore, passarlo per riferimento significa passare un puntatore a puntatore a puntatore, e se non si fa attenzione si rischia di invecchiare presto

codice:
#include <stdio.h>
#include <stdlib.h>

void my_alloc(int ***x)
{
	int i;
	*x = (int **) malloc ( 10 * sizeof(int *) );

	for ( i = 0; i < 10; i++ )
		*(*x+i) = (int *) malloc( 10 * sizeof(int) );
}

void my_free(int ***x)
{
	int i;

	for ( i = 0; i < 10; i++ ) {
		free(*(*x+i));
		*(*x+i) = NULL;
	}

	free(*x);

	*x = NULL;
}

int main(void)
{
	int **x, i, j;

	my_alloc(&x);

	for ( i = 0; i < 10; i++ )
		for ( j = 0; j < 10; j++ )
			x[i][j] = rand()%10;

	for ( i = 0; i < 10; i++ ) {
		for ( j = 0; j < 10; j++ )
			printf("%d ", x[i][j]);
		putchar('\n');
	}

	my_free(&x);

	return 0;
}
(è chiaro che sia l'esempio di sopra che il prossimo ricorrono a dimensioni fisse della matrice - 10x10 - ma non ci vuole nulla a generalizzarli...)

Il modo più "cristiano" di operare in questo caso sarebbe quello di ricordare che, almeno in C (e ovviamente non è così per tutti i linguaggi) una matrice non è nient'altro che un array costituito dalle colonne della matrice stessa una dopo l'altra, quindi la matrice

1 2 3
4 5 6
7 8 9

in memoria viene salvata come

1
2
3
4
5
6
7
8
9

quindi a questo punto la matrice x di cui sopra si può dichiarare come un semplice puntatore e poi utilizzare la mappa di memorizzazione per accedere ai suoi elementi. Il programma di sopra diventa quindi

codice:
#include <stdio.h>
#include <stdlib.h>

void my_alloc(int **x)
{
	*x = (int *) malloc ( 10 * 10 * sizeof(int) );
}

void my_free(int **x)
{
	free(*x);
	*x = NULL;
}

int main(void)
{
	int *x, i, j;

	my_alloc(&x);

	for ( i = 0; i < 10; i++ )
		for ( j = 0; j < 10; j++ )
			*(x + i*10 + j) = rand() % 10;

	for ( i = 0; i < 10; i++ ) {
		for ( j = 0; j < 10; j++ )
			printf("%d ", *(x + i*10 + j));
		putchar('\n');
	}

	my_free(&x);

	return 0;
}
dove la mappa di memorizzazione (che si può vedere in entrambi i for) in generale è la seguente:

codice:
*(indirizzo_base_array + indice_di_riga * n_colonne + indice_di_colonna)