Tableau à double dimension [Résolu/Fermé]

Signaler
Messages postés
863
Date d'inscription
dimanche 1 novembre 2015
Statut
Membre
Dernière intervention
19 mai 2020
-
Messages postés
863
Date d'inscription
dimanche 1 novembre 2015
Statut
Membre
Dernière intervention
19 mai 2020
-
Bonjour,

Mon programme n'a pas de grand intérêt mais c'était pour m'exercer sur les tableaux.
D'après le shell j'ai une erreur

Test.c:23:11: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
printf("%s",mot[i][j]);

Pourtant j'ai bien initialisé mot [ligne] [colonne] en char et je n'ai crée aucun pointeur..

Voici le code :

#include <stdio.h>
#define ligne 2
#define colonne 3

void main()
{
 int i,j;
 char vide; 
 char mot[ligne][colonne];
 for(i=0;i<ligne;i++)
 {
  for(j=0;j<colonne;j++)
  {
   printf("\n Rentre la valeur %d,%d \n",i,j); 
   scanf("%s",&mot[i][j]);
   scanf("%c",&vide);
  }
 }
 for(i=0;i<ligne;i++)
 {
  for(j=0;j<colonne;j++)
  {
   printf("%s",mot[i][j]);
  }
 }
} 


Merci pour votre aide!

2 réponses

Messages postés
5333
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
7 mai 2020
875
Salut CrazyGeekMan,

char
représente un caractère et non une chaîne de caractères

en déclarant
char mot[ligne][colonne];
tu ne fais que réserver de l'espace pour un seul caractère dans chaque case de ton tableau bidimensionnel (un char étant en fait un type entier, l'entier étant normalement la représentation ASCII du caractère)

une chaîne de caractères en C est un emplacement en mémoire où sont stockés des
char
et terminée par le caractère "null", soit
'\0'
:

https://www.commentcamarche.net/contents/118-langage-c-les-chaines-de-caracteres#qu-est-ce-qu-une-chaine-de-caracteres

ton tableau est donc mal déclaré et ta mémoire mal allouée si tu veux stocker autre chose que un
char
par case (et ton
scanf("%s",&mot[i][j]);
va certainement écrire dans des zones mémoires non allouées, occasionnant une corruption de la mémoire, des core dumps,...)

pour faire un tableau bidimensionnel de chaînes de caractères, tu dois mettre dans chaque case les pointeurs sur
char
, pointant vers la zone mémoire allouée à chaque chaîne que tu veux stocker. Si tu le fais au moyen de
malloc()
, tu devras gérer aussi la libération de l'espace avec
free()
...

à ce moment là, ton
printf("%s",mot[i][j]);
sera également content et ne t'enverra plus de warning.


Dal
Messages postés
863
Date d'inscription
dimanche 1 novembre 2015
Statut
Membre
Dernière intervention
19 mai 2020
81
D'accord merci pour la réponse.
Et moi comme un con j'ai essayé de compiler avec l'option
-fno-stack-protector
...

Je ne vois pas ce que tu veut dire par "tu dois mettre dans chaque case les pointeurs sur char, pointant vers la zone mémoire allouée à chaque chaîne que tu veux stocker." :(
Je dois créer 6 pointeurs pointant vers 6 chaînes de caractères? (6 char?)
Désolé pour le boulet que je suis.
Messages postés
5333
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
7 mai 2020
875
pour stocker des chaînes de caractères dans un tableau à deux dimensions, tu peux faire comme cela :

#include <stdio.h>
#include <stdlib.h>
#define ligne 2
#define colonne 3

int main(void) {
    int i,j;
    char * mot[ligne][colonne];
    /* à ce stade, mot contient assez d'espace pour stocker 2x3=6
     * pointeurs sur des char
     */

    /* allocation d'espace pour des chaînes de 10 caractères
     * (y compris le '\0' terminal) pointées par ces
     * pointeurs, ou une taille variable, si tu veux
     */
    for(i=0;i<ligne;i++)
        for(j=0;j<colonne;j++)
            mot[i][j] = malloc(sizeof(char) * 10);

    /* mettre des chaînes dedans et faire ce qu'on a à faire
     * avec
     */
    int c;

    for(i=0;i<ligne;i++) {
        for(j=0;j<colonne;j++) {
            printf("\nRentre le mot à la position %d,%d (9 lettres au plus)\n",i,j); 
            while (scanf("%9[^\n]", mot[i][j]) != 1)
                /* we want non empty things */ ;
            while ((c = getchar()) != '\n' && c != EOF)
                /* discard what remains in stdin */ ;
        }
    }

    printf("\n\n");

    for(i=0;i<ligne;i++)
        for(j=0;j<colonne;j++)
            printf("%s\n",mot[i][j]);

    /* libération de l'espace occupé par les chaînes
     */
    for(i=0;i<ligne;i++)
        for(j=0;j<colonne;j++)
            free(mot[i][j]);

    return 0;
}

il y a plusieurs façons de faire

par exemple, alternativement, tu peux tout faire avec des pointeurs et des allocations dynamiques, en déclarant ta structure de données comme étant un
char *** mot
(c'est utile si le nombre de lignes et de colonnes, outre la taille des chaînes, sont indéterminés à l'avance ou peuvent varier en cours d'exécution)

si tu n'as pas besoin de tailles variables, tu peux aussi te passer des mallocs / free en déclarant un truc comme
char mot[ligne][colonne][10];
et c'est tout


Dal

P.S. :
malloc(sizeof(char) * 10);
peut s'écrire
malloc(10);
aussi en C, car le type
char
a, par définition, une taille de 1 byte
Messages postés
863
Date d'inscription
dimanche 1 novembre 2015
Statut
Membre
Dernière intervention
19 mai 2020
81 >
Messages postés
5333
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
7 mai 2020

D'accord je vois maintenant une belle utilité du malloc (j'utilisais toujours l'allocation dynamique jusqu'ici).
Je vais encore étudié cette partie du code :

 while (scanf("%9[^\n]", mot[i][j]) != 1)
                /* we want non empty things */ ;
            while ((c = getchar()) != '\n' && c != EOF)
                /* discard what remains in stdin */ ;


Il y a deux boucles while sans aucune instructions, je n'ai jamais vu ça ^^

Merci !
Messages postés
5333
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
7 mai 2020
875
(j'utilisais toujours l'allocation dynamique jusqu'ici)

si tu n'utilisais pas de malloc, je pense que tu veux dire "allocation statique"

pour :

            while (scanf("%9[^\n]", mot[i][j]) != 1)
                /* we want non empty things */ ;
            while ((c = getchar()) != '\n' && c != EOF)
                /* discard what remains in stdin */ ;


1.

le premier while s'assure que scanf renvoie 1 (c'est à dire qu'il a pu capturer un élément provenant de stdin correspondant au masque demandé), le scanf étant dans le test du while, il n'y a rien d'autre à mettre à la suite, et le point virgule reporté en 2ème ligne (après le commentaire) est une façon de montrer à un lecteur du code que c'est intentionnel

pour le masque
"%9[^\n]"
, il :

- consomme dans stdin tous les caractères jusqu'au retour à la ligne exclu (y compris les espaces ou tabulations)
- en ignorant les caractères au delà du 9ème

si vraiment tu ne prends en compte que des mots et que si l'utilisateur saisit des espaces, cela signifie qu'il a terminé son mot, tu peux faire
"%9s"
et les espaces et les caractères qui suivent éventuellement ne seront pas capturés par scanf qui limitera sa capture à 9 caractères où les espaces ou tabulations sont interdits et en laissant dans le flux stdin le reste

2.

le 2ème while est une façon répandue de vider le flux stdin en C (contenue dans le test du while sur le même principe), pour retirer les caractères qui peuvent y être laissés par scanf (notamment '\n' et/ou dans notre cas tous caractères saisis dépassant la taille de 9 caractères), de façon à ce qu'ils ne viennent pas à être consommés par le prochain appel à scanf (ou une autre fonction exploitant le flux stdin)
Messages postés
863
Date d'inscription
dimanche 1 novembre 2015
Statut
Membre
Dernière intervention
19 mai 2020
81 >
Messages postés
5333
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
7 mai 2020

Eh bien merci beaucoup!
Ces bases m'aideront par la suite :)
Bonne soirée :)
Messages postés
3644
Date d'inscription
dimanche 18 mars 2001
Statut
Modérateur
Dernière intervention
15 janvier 2017
879
Ceci fonctionnera mieux et se rapprochera des standards:
#include <stdlib.h>
#include <stdio.h>

const unsigned int  lignes =  2;
const unsigned int  colonnes = 3;

int main(int argc, char *argv[])
{
  int i,j;
//  char vide; 
  char mot[lignes][colonnes];
  for(i = 0; i < lignes; i++)
    {
      for(j = 0; j < colonnes; j++)
 {
   printf("\n Rentre la valeur mot[%2d,%2d] \n",i,j); 
   scanf("%c", &mot[i][j]);

/*
  scanf("%c", &vide);
 */
 }
    }
  for(i = 0; i < lignes; i++)
    {
      for(j = 0; j < colonnes; j++)
 {
   printf("%c", mot[i][j]);
 }
    }
  return EXIT_SUCCESS;
}


Remarquons le caractère de formatage en ligne 29
123abcjohand@bata:~/src/Cgcc -Wall -o fill_tab fill_tab.cll_tab 
johand@bata:~/src/CCM/C$ echo 123abc | ./fill_tab

Rentre la valeur mot[ 0, 0]

Rentre la valeur mot[ 0, 1]

Rentre la valeur mot[ 0, 2]

Rentre la valeur mot[ 1, 0]

Rentre la valeur mot[ 1, 1]

Rentre la valeur mot[ 1, 2]
123abc

-
Gates gave ^W  sold  you the windows.
GNU gave us the whole house.(Alexandrin)
Messages postés
5333
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
7 mai 2020
875
salut jisisv,

Il me semble que notre ami veut stocker des chaînes de caractères dans son tableau à deux dimensions, et non un seul char.


Dal
Messages postés
863
Date d'inscription
dimanche 1 novembre 2015
Statut
Membre
Dernière intervention
19 mai 2020
81 >
Messages postés
5333
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
7 mai 2020

Oui c'est vrai.
Mais merci à vous, ces codes me permettent de mieux comprendre la structure du c ;)