Tableau de chaînes de caractères dynamique [Langage C]
Répondre à la discussion
Affichage des résultats 1 à 9 sur 9

Tableau de chaînes de caractères dynamique [Langage C]



  1. #1
    theodutt

    Tableau de chaînes de caractères dynamique [Langage C]


    ------

    EDIT : Title : Tableau de chaines de caractères dynamique [Langage C]
    Bonsoir,

    J'ai un problème, j'aimerais créer un tableau de chaines de caractères dynamique contenant 5 chaine de 3 caractères chacune.
    J'ai donc fais cela mais j'obtient une Segmentation fault: 11 à cause du scanf("%s", tab_chaine[1]);

    Code:
    #include <stdlib.h>
    #include <stdio.h>
     
    int main ()
    {
       char **tab_chaine = NULL;
     
       tab_chaine = malloc(5*sizeof(*tab_chaine));
       *tab_chaine = (char*)malloc(3*sizeof(char));
    
       scanf("%s", tab_chaine[0]);
       scanf("%s", tab_chaine[1]);
    
       printf("%s\n", tab_chaine[0]);
    }
    De plus si je ne met que scanf("%s", tab_chaine[0]); je peux mettre une chaine plus grande que 3 caractères dedans et elle s'affichera sans être coupée.

    Merci d'avance pour votre réponse

    -----
    Dernière modification par theodutt ; 23/12/2018 à 22h29.

  2. #2
    PA5CAL

    Re : Tableau de chaines de caractères dynamique

    Bonsoir

    En langage C, il est nécessaire de gérer correctement l'utilisation de la mémoire, et notamment :
    - il vaut veiller à ne pas écrire de données en dehors des espaces réservés (variables ou zones allouées),
    - il faut libérer les zones de mémoire allouées avant de quitter le programme.

    Regardons ton code de plus près :
    Code:
    01 #include <stdlib.h>
    02 #include <stdio.h>
    03 
    04 int main ()
    05 {
    06    char **tab_chaine = NULL;
    07  
    08    tab_chaine = malloc(5*sizeof(*tab_chaine));
    09    *tab_chaine = (char*)malloc(3*sizeof(char));
    10 
    11    scanf("%s", tab_chaine[0]);
    12    scanf("%s", tab_chaine[1]);
    13 
    14    printf("%s\n", tab_chaine[0]);
    15 }
    • À la ligne 08, on alloue sur le tas (heap) l'espace nécessaire pour 5 pointeurs de caractères, et on enregistre son adresse dans le pointeur tab_chaine.

    • À la ligne 09, on alloue sur le tas l'espace nécessaire pour 3 caractères, et son adresse est enregistrée dans le premier des pointeurs alloués à la ligne 08 (puisque *tab_chaine est équivalent à tab_chaine[0]).

    • À la ligne 11, on attend la saisie d'une chaîne de caractères (sans caractère « espace »), et le résultat est enregistré dans l'espace alloué à la ligne 09, suivi d'un caractère nul. Si l'on saisit une chaîne plus de 2 caractères, alors l'espace mémoire situé immédiatement après l'espace alloué (dont la taille n'est que de 3 caractères) est écrasé, ce qui risque de détruire des données, de rendre le fonctionnement de l'ordinateur instable ou de générer une exception.

    • À la ligne 12, on attend la saisie d'une chaîne de caractères (sans caractère « espace »), et on tente d'enregistrer le résultat dans un espace dont l'adresse correspond au contenu du deuxième pointeur alloué à la ligne 08, lequel n'a jamais été initialisé et contient donc a priori une valeur aléatoire. Quelle que soit la taille de la chaîne saisie, l'espace mémoire situé à cette adresse aléatoire risque de détruire des données, de rendre le fonctionnement de l'ordinateur instable ou de générer une exception.

    • À la ligne 14, on affiche la première chaîne de caractères saisie.

    • Le programme se termine sans qu'on ait libéré les espaces alloués aux lignes 08 et 09. Ces espaces ne peuvent plus être réutilisés par les autres programmes.


    Il faut par conséquent :
    - allouer tous les espaces qui seront effectivement utilisés,
    - limiter le nombre de caractères dans les chaînes saisis afin de ne pas déborder des espaces alloués dans lesquels on les enregistre,
    - libérer tous les espaces alloués avant de quitter le programme.

    Pour saisir puis afficher 3 chaînes de caractères limitées à 10 caractères, on peut par exemple procéder de la façon suivante :

    Code:
    // Déclaration de scanf et printf :
    #include <stdio.h>
    // Déclaration de malloc et free :
    #include <stdlib.h>
    
    int main ()
    {
       int i;
    
    // Allocation des espaces mémoire nécessaires sur le tas :
       // allocation de 3 pointeurs
       char **tab_chaine = (char **)malloc(3*sizeof(char*));
       for (i=0 ; i<3 ; i++)
          // allocation pour 10 caractères + 1 caractère nul final
          tab_chaine[i] = (char*)malloc(11);
    
    // Saisie des chaînes de caractères :
       for (i=0 ; i<3 ; i++)
          // saisie d'une  chaîne de 10 caractères maximum
          scanf("%10s", tab_chaine[i]);
    
    // Affichage des chaînes de caractères :
       for (i=0 ; i<3 ; i++)
          printf("%s\n", tab_chaine[i]);
    
    // Libération des espaces alloués :
       for (i=0 ; i<3 ; i++)
          free(tab_chaine[i]);
       free(tab_chaine);
    
       return 0;
    }
    Ce code est donné à titre d'illustration. Il est fonctionnel, mais pas rigoureusement sûr : en pratique, il faudrait également vérifier que les allocations de mémoire sont correctement effectuées (ce qui n'est pas forcément le cas, si la mémoire est pleine), puis traiter les erreurs éventuelles.

    Par ailleurs, lorsque plus de 10 caractères sont entrés lors de la saisie d'une chaîne, la saisie suivante prend systématiquement et exclusivement les caractères en trop. Un programme un peu plus complexe permettrait de régler cet inconvénient.
    Dernière modification par PA5CAL ; 23/12/2018 à 23h59.

  3. #3
    Jack
    Modérateur

    Re : Tableau de chaines de caractères dynamique

    Citation Envoyé par theodutt Voir le message
    J'ai donc fais cela mais j'obtient une Segmentation fault: 11 à cause du scanf("%s", tab_chaine[1]);[CODE]
    C'est normal que ça plante puisque tu n'as pas réservé de place pour stocker la chaine pointée par tab_chaine[1].
    De plus si je ne met que scanf("%s", tab_chaine[0]); je peux mettre une chaine plus grande que 3 caractères dedans et elle s'affichera sans être coupée.
    scanf ne peut pas savoir que ce que tu entres dépasse la taille de la mémoire allouée.

    Remarque: tes chaines ne pourront pas dépasser 2 caractères en rason du zéro terminal des cstrings

    Edit: grillé pas PA5CAL
    Dernière modification par Jack ; 24/12/2018 à 00h06.

  4. #4
    PA5CAL

    Re : Tableau de chaines de caractères dynamique

    Oups... il faut lire « Quelle que soit la taille de la chaîne saisie, l'enregistrement de cette dernière dans l'espace mémoire situé à cette adresse aléatoire risque de... »

  5. A voir en vidéo sur Futura
  6. #5
    Jack
    Modérateur

    Re : Tableau de chaines de caractères dynamique

    • Le programme se termine sans qu'on ait libéré les espaces alloués aux lignes 08 et 09. Ces espaces ne peuvent plus être réutilisés par les autres programmes.
    D'accord sur le fond, on doit libérer ce qu'on a alloué, mais sur un PC (ce qui doit sûrement être le cas ici), fin de programme = fin de processus et toute sa mémoire est restituée par l'OS.

  7. #6
    PA5CAL

    Re : Tableau de chaines de caractères dynamique

    Certes. J'aurais peut-être dû présenter les conséquences de ces fuites de mémoire d'une façon moins catégorique, sous une forme conditionnelle.

    Mais a priori, il pourrait s'agir de n'importe quel matériel faisant tourner n'importe quel OS. N'oublions pas que le langage C est très largement utilisé dans des environnements de petite taille dans lesquels les mécanismes de protection et de gestion avancée de la mémoire ne sont pas disponibles ou seraient trop coûteux en ressources (notamment les environnements temps-réel).

    Par ailleurs, j'utilise encore des PC sur lesquels les fuites de mémoire ne sont visiblement pas restituées. Et sur d'autres ordinateurs personnels, les applications sont prévues pour être ré-exécutée de bout en bout sans qu'on les quitte jamais vraiment.

    Alors tant mieux si l'OS arrive à rattraper les erreurs du développeur, mais à la base ce dernier est quand même censé coder correctement. S'il prend l'habitude de ne pas libérer la mémoire qu'il alloue, et même s'il n'utilise que des systèmes qui restituent pour lui la mémoire perdue, il est probable que certains de ses programmes finiront par planter la machine avant de se terminer, et qu'il serait très risqué de réutiliser le code des autres pour écrire des programmes plus gros.

    Quoi qu'il en soit, même dans le cas où l'on peut garantir que l'OS restituera toute la mémoire du programme à la fin, comme il n'y a pas de « garbage collector » en C il est a priori nécessaire de déterminer à quels moments les zones de mémoire allouées peuvent et doivent être libérées. S'abstenir de libérer certaines zones mémoire apparait alors comme un choix délibéré et raisonné, et non pas comme une pratique de développement par défaut. Le maître mot en langage C doit donc être « on libère ce qu'on a alloué », et puis après on peut toujours réfléchir pour faire des exceptions.

  8. #7
    Jack
    Modérateur

    Re : Tableau de chaines de caractères dynamique

    Oui, comme je le disais en préambule tu as raison sur le fond. C'était juste, je l'avoue, du pinaillage destiné à ajuster ce que tu avais dit pour rappeler ce qui se passe concrètement avec un OS de PC.

  9. #8
    JPL
    Responsable des forums

    Re : Tableau de chaînes de caractères dynamique [Langage C]

    J’ai modifié le titre de la discussion selon le vœu de theodutt.
    Rien ne sert de penser, il faut réfléchir avant - Pierre Dac

  10. #9
    theodutt

    Thumbs up Re : Tableau de chaînes de caractères dynamique [Langage C]

    Merci à tous pour vos réponses, effectivement j'avais oublié de libérer la mémoire !

    J'ai donc bien compris qu'il faut allouer de la mémoire pour chaque éléments du tableau (ce qui est logique )

Discussions similaires

  1. [Langage C] Tableau dynamique
    Par invitee9f21c56 dans le forum Programmation et langages, Algorithmique
    Réponses: 7
    Dernier message: 14/07/2014, 00h02
  2. Manipulation de chaines de caractères
    Par inviteede40645 dans le forum Programmation et langages, Algorithmique
    Réponses: 1
    Dernier message: 04/06/2013, 20h05
  3. langage C, utiliser des chaines de caractères
    Par invite49289c75 dans le forum Programmation et langages, Algorithmique
    Réponses: 12
    Dernier message: 15/01/2013, 13h25
  4. concaténation de chaînes de caractères, langage C
    Par aureo91 dans le forum Programmation et langages, Algorithmique
    Réponses: 7
    Dernier message: 14/12/2012, 06h37
  5. Algorithmes et chaines de caractères
    Par invite3f493caf dans le forum Mathématiques du supérieur
    Réponses: 0
    Dernier message: 31/10/2010, 19h03