Tableau de chaines de caractères dynamique en C

Comment puis-je corriger ce code de manière à ce qu’il affiche les mots dans le tableau ?
Est-ce que c’est la bonne façon d’allouer dynamiquement de la mémoire pour n mots d’une taille maximale de 30 ?

int main() {
    int n, i;
    char *tab;

    printf("Donnez-moi un nombre:");
    scanf("%d", &n);

    tab = malloc(n * 30);

    for (i = 0; i < n; i++)
    {
        printf("Saisissez un mot: ");
        scanf("%s", &tab[i]);
    }

    for (i = 0; i < n; i++)
    {
        printf("%s", tab[i]); //< -- problème ici
    }

    return 0;
}

Votre allocation n’est pas la meilleure, et l’argument printf tab[i] attend un char* mais vous lui passez un int (un char si vous voulez).

Voici comment vous devriez faire, avec des commentaires :

#include <stdio.h>
#include <stdlib.h> //pour malloc

int main(){
    int n, i;
    
    printf("Donnez-moi un nombre:");
    scanf("%d", &n);

    //déclarer une variable de pointeur à pointeur à char
    //allouer de la mémoire pour le tableau de pointeurs sur char, 
    //chacun pouvant pointer sur un tableau de chars
    char **tab = malloc(n * sizeof *tab);

    if(tab == NULL){ //vérifier les erreurs d'allocation
        perror("malloc");
        return EXIT_FAILURE;
    }

    //allouer de la mémoire pour chaque tableau de char
    for(i = 0; i < n; i++){
        tab[i] = malloc(30); //la taille du char est toujours 1 octet

        if(tab == NULL){ //vérifier les erreurs d'allocation
            perror("malloc");
            return EXIT_FAILURE;
        }
    }

    for (i = 0; i < n; i++){
        printf("Saisissez un mot: ");
        //limite la taille de l'entrée lue à 29 caractères pour éviter les débordements, 
        //le caractère nul sera ajouté par scanf
        scanf("%29s", tab[i]);
    }

    for (i = 0; i < n; i++){
        printf("%s\n", tab[i]);
       
    }
     
    for(int i = 0; i < n; i++){ //libérer la mémoire pour chaque tableau de caractères
        free(tab[i]);
    }
    free(tab); //libérer le tableau de pointeurs

    return 0;
}

Sortie:

Donnez-moi un nombre:2
Saisissez un mot: hello
Saisissez un mot: world
hello
world

Vous pouvez également le faire avec moins de code en utilisant un pointeur sur un tableau de 30 caractères, ce qui simplifiera l’allocation et la désallocation de la mémoire :

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

int main(){
    int n, i;

    printf("Donnez-moi un nombre:");
    scanf("%d", &n);

    char (*tab)[30] = malloc(n * sizeof *tab);

    if(tab == NULL){ 
        perror("malloc");
        return EXIT_FAILURE;
    }

    for (i = 0; i < n; i++){
        printf("Saisissez un mot: ");
        scanf("%29s", tab[i]);
    }

    for (i = 0; i < n; i++){
        printf("%s\n", tab[i]);
    }

    free(tab); 

    return 0;
}