Ci sono due problemi:
1. Quando dichiari stringa
codice:
char stringa[N][D];
La dimensione deve essere nota al momento della compilazione, perchè è definito nello stack. Tu N lo valorizzi solo in seguito, di conseguenza lo "spazio" assegnato a stringa è ignoto. Se N è 0 (ad esempio) stringa non ha memoria disponibile per contenere le tue stringhe. Di conseguenza quando vai a scrivere sull'array vai fuori dai limiti ed il programma crasha
Quindi o definisci N come hai fatto per D (e quindi poi vai ad usare solo una parte di questo array),
codice:
#define D 21
#define MAXN 99
int main()
{
int N, i;
char stringa[MAXN][D];
...
oppure "sposti" nell heap stringa:
codice:
int main()
{
int N, i;
char** stringa;
char s[D] ;
printf("Inserisci numero stringhe: ");
scanf("%d", &N);
while ((N<1) || (N>99))
{printf("\nNumero non consentito! Reinserire numero stringhe: ");
scanf ("%d", &N);}
printf("\n\n");
stringa = (char**)malloc(sizeof(char*) * N);
for(i=0;i<N;i++)
{
stringa[i] = (char*)malloc(sizeof(char) * D);
printf("Inserisci stringa %d: ", i+1);
scanf("%s", s);
if (strlen(s)==0)
{ printf("Vuota - ripeti\n");
i--;}
else
{if(strlen(s)>D)
{printf("Troppo lunga! Max %d caratteri\n", D-1) ;
i--;}
else
{strcpy(stringa[i], s);}}
}
printf("\n\nLe stringhe inserite sono: \n");
for(i=0;i<N;i++)
{printf("Stringa %d = %s\n", i+1, stringa[i]);}
return 0;
}
2. Come vedi nel codice qui su ho cambiato s.
Come hai fatto tu, s è un puntatore che "punta" non si sa sa dove. Quando lo passi alla scanf questa tenta di scrivere nella zona di memoria a cui fa riferimento s che però essendo ignota porta al crash del programma (se sei fortunato). Ricorda che un puntatore DEVE far sempre riferimento ad una zona di memoria valida