IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

C - Tableau à taille variable


Sujet :

C

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2012
    Messages : 6
    Points : 6
    Points
    6
    Par défaut C - Tableau à taille variable
    Bonsoir,

    Comme indiqué dans le titre, je souhaite implémenter en C des tableaux de taille variable. Ils fonctionneraient de cette manière : on déclare une variable de type Liste (qui n'est pas vraiment une liste chaînée mais je n'avais pas d'autre nom), qui est en réalité une structure contenant : la taille du tableau (int) et les données (char *).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    typedef struct{
        int longueur; //La taille de la liste
        char *valeur; //Les données dans la liste
    }Liste;
    On l'initialise via la fonction init, qui se contente de mettre la taille à 0 et d'allouer une case de mémoire de la taille d'un char.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void init(Liste *l)
    {
        l->longueur = 0; //On met la taille (= nombre de caractères) à 0
        l->valeur = calloc(1, sizeof(char)); //On utilise calloc pour allouer dynamiquement et mettre à 0
        if (l->valeur == NULL)
            exit(EXIT_FAILURE); //En cas d'erreur, on quitte le programme
    }
    Ensuite, je souhaite modifier la chaîne de caractères via une fonction qui en appelle deux autres :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    void scanListe(Liste *l)
    {
        char c[2] = {0}; //Chaine qui servira a stocker ce qui est entré par l'utilisateur
        changerValeur(l, ""); //On vide la chaine (voir après)
        while(c[0] != '\n')
        {
            c[0] = getchar(); //On récupère le dernier caractère
            if(c[0] != '\n') //Si ce n'est pas un retour à la ligne
                concatener(l, c); //On met à la fin de la chaine
        }
     
    }
    Voici l'implémentation de la fonction changerValeur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void changerValeur(Liste *l, char* str)
    {
        realloc(l->valeur, (strlen(str) + 1) * sizeof(char));
        /*On réalloue le tableau avec la taille de la nouvelle chaine. Pas besoin de réallouer à la fin puisque
     on veut écraser l'ancienne valeur de la chaine */
        if (l->valeur == NULL)
            exit(EXIT_FAILURE); //On quitte en cas d'erreur
        strcpy(l->valeur, str); //Enfin on copie la nouvelle chaine dans l'ancienne...
        l->longueur = strlen(str); //... et on met à jour la taille du tableau
    }
    Et enfin la fonction concatener
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void concatener(Liste *l, char* str)
    {
        realloc(l->valeur, (l->longueur + (strlen(str) + 1)) * sizeof(char));
        /*On réalloue, mais cette fois avec la taille initiale en plus*/
        if (l->valeur + l->longueur + 1 == NULL)
            exit(EXIT_FAILURE); //On quitte en cas d'erreur
        strcpy((l->valeur + l->longueur), str); //On copie la chaine à partir de la fin
        l->longueur += strlen(str); //Et on met à jour la taille de la chaine
    }
    J'ai en plus fait une fonction qui renvoie seulement la chaine de caractère contenue dans une structure Liste :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    char* chaine(Liste *l)
    {
        return l->valeur;
    }
    Enfin, voici ma fonction qui libère la mémoire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void liberer(Liste *l)
    {
        free(l->valeur);
        l->valeur = NULL;
    }
    La totalité du code est donc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    #include <stdio.h>
    #include <stdlib.h>
     
    typedef struct{
        int longueur; //La taille de la liste
        char *valeur; //Les données dans la liste
    }Liste;
     
    void init(Liste *l);
    void changerValeur(Liste *l, char* str);
    void concatener(Liste *l, char* str);
    char* chaine(Liste *l);
    void liberer(Liste *l);
    void scanListe(Liste *l);
     
    int main()
    {
        Liste Chaine;
        init(&Chaine);
        while(strcmp(chaine(&Chaine),"exit") != 0)
        {
            printf("La liste chainee vaut \"%s\".\nModifiez sa valeur : ", chaine(&Chaine));
            scanListe(&Chaine);
        }
        liberer(&Chaine);
        return 0;
    }
     
    void init(Liste *l)
    {
        l->longueur = 0; //On met la taille (= nombre de caractères) à 0
        l->valeur = malloc(sizeof(char)); //On utilise calloc pour allouer dynamiquement et mettre à 0
        *(l->valeur) = '\0';
        if (l->valeur == NULL)
            exit(EXIT_FAILURE); //En cas d'erreur, on quitte le programme
    }
     
    void scanListe(Liste *l)
    {
        char c[2] = {0}; //Chaine qui servira a stocker ce qui est entré par l'utilisateur
        changerValeur(l, ""); //On vide la chaine (voir après)
        while(c[0] != '\n')
        {
            c[0] = getchar(); //On récupère le dernier caractère
            if(c[0] != '\n') //Si ce n'est pas un retour à la ligne
                concatener(l, c); //On met à la fin de la chaine
        }
     
    }
     
    void changerValeur(Liste *l, char* str)
    {
        realloc(l->valeur, (strlen(str) + 1) * sizeof(char));
        /*On réalloue le tableau avec la taille de la nouvelle chaine. Pas besoin de réallouer à la fin puisque
     on veut écraser l'ancienne valeur de la chaine */
        if (l->valeur == NULL)
            exit(EXIT_FAILURE); //On quitte en cas d'erreur
        strcpy(l->valeur, str); //Enfin on copie la nouvelle chaine dans l'ancienne...
        l->longueur = strlen(str); //... et on met à jour la taille du tableau
    }
    void concatener(Liste *l, char* str)
    {
        realloc(l->valeur, (l->longueur + (strlen(str) + 1)) * sizeof(char));
        /*On réalloue, mais cette fois avec la taille initiale en plus*/
        if (l->valeur + l->longueur + 1 == NULL)
            exit(EXIT_FAILURE); //On quitte en cas d'erreur
        strcpy((l->valeur + l->longueur), str); //On copie la chaine à partir de la fin
        l->longueur += strlen(str); //Et on met à jour la taille de la chaine
    }
     
    void liberer(Liste *l)
    {
        free(l->valeur);
        l->valeur = NULL;
    }
     
    char* chaine(Liste *l)
    {
        return l->valeur;
    }
    Ce programme est une boucle qui permet de changer la valeur de Chaine jusqu'a ce qu'on entre "exit", auquel cas l'application se ferme.

    Il réside plusieurs bugs lors de l'éxecution de ce programme que je ne parviens pas à résoudre :
    • Une et une seule fois, lorsque ce que je rentre dépasse les 7 caractères, l'affichage me sors une chose du type "h>ù" (3 caractères spéciaux généralement)
    • Lorsque la liste est de longue taille (plus de deux lignes environ), le programme plante (SEGMENTATION FAULT) lors de la fermeture, pas avant, et ce même si je remodifie la chaîne en quelque chose de plus court.
    • Le problème précédant est observé après le return 0; lorsque j'utilise le debugger de Code::Blocks. Je suppose donc que c'est que la chaîne a mal été libérée de la mémoire, mais la fonction free() ne renvoyant rien, je ne peux pas tester son succès avec la valeur de retour.


    J'ai bien sûr plusieurs fois vérifié et modifié mon code mais sans succès et sans même trouver d'où peuvent venir ces problèmes, surtout que lorsqu'il est dans la boucle principale, ce code semble fonctionner (hormis le 1er bug qui n’apparaît qu'une fois lors de l’exécution).

    Je remercie par avance toute aide et j'espère que vous ferez preuve d'indulgence, je ne suis pas encore très expérimenté.

  2. #2
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 296
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 296
    Points : 4 949
    Points
    4 949
    Billets dans le blog
    5
    Par défaut
    On l'initialise via la fonction init, qui se contente de mettre la taille à 0 et d'allouer une case de mémoire de la taille d'un char.
    Pourquoi alloues-tu un char lors de l'init? Ensuite tu ne lui donnes aucune valeur?

    Je partirai plutôt dans l'idée de le mettre à NULL lors de l'initialisation. Puisque la longueur vaut 0, autant ne pas allouer de mémoire. Non?

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2012
    Messages : 6
    Points : 6
    Points
    6
    Par défaut
    En réalité j'ai fait cela car j'utilise la fonction realloc() dans concatener() et changerValeur() et je ne savais pas si cela fonctionnait sans malloc().

    Je viens de faire des tests : en mettant NULL dans l'initialisation, il met un segmentation fault lors de l'entrée dans la boucle (normal, j'essaie de lire un char * sans le caractère d'échappement à la fin). Je modifie le code et j'éditerai mon message pour dire ce qu'il en est.
    J'ai aussi testé en laissant le calloc mais en testant mes realloc() : ça plante lors d'un realloc() après les 8 fameux caractères...

    J'avoue que j'ai un peu de mal à comprendre..

    EDIT :
    Quand je met mon l->valeur à NULL dans init(), le realloc appelé dans changerValeur() renvoie NULL, donc il y a eu un problème lors de la réallocation.
    -
    Je relis mon code et je me rends compte au cours des modifications que j'ai fais n'importe quoi parfois.
    Dans concatener():
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    if (l->valeur + l->longueur + 1 == NULL)
            exit(EXIT_FAILURE); //On quitte en cas d'erreur
    C'est inutile (c'était pour une version où je pensais qu'il fallait spécifier en premier paramètre la fin de la première zone de mémoire allouée).

  4. #4
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 296
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 296
    Points : 4 949
    Points
    4 949
    Billets dans le blog
    5
    Par défaut
    La fonction realloc() retourne le nouveau pointeur sur le bloc de mémoire alloué. Mais tu ne l'affectes pas!
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    l->valeur = realloc(l->valeur, (strlen(str) + 1) * sizeof(char));

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2012
    Messages : 6
    Points : 6
    Points
    6
    Par défaut
    Merci beaucoup ça fonctionne à merveille maintenant

    EDIT :
    Le code final :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    #include <stdio.h>
    #include <stdlib.h>
     
    typedef struct{
        int longueur; //La taille de la liste
        char *valeur; //Les données dans la liste
    }Liste;
     
    void init(Liste *l);
    void changerValeur(Liste *l, char* str);
    void concatener(Liste *l, char* str);
    char* chaine(Liste *l);
    void liberer(Liste *l);
    void scanListe(Liste *l);
     
    int main()
    {
        Liste Chaine;
        init(&Chaine);
        while(strcmp(chaine(&Chaine),"exit") != 0)
        {
            printf("La liste chainee vaut \"%s\".\nModifiez sa valeur : ", chaine(&Chaine));
            scanListe(&Chaine);
        }
        liberer(&Chaine);
        return 0;
    }
     
    void init(Liste *l)
    {
        l->longueur = 0; //On met la taille (= nombre de caractères) à 0
        l->valeur = calloc(1, sizeof(char)); //On utilise calloc pour allouer dynamiquement et mettre à 0
    }
     
    void scanListe(Liste *l)
    {
        char c[2] = {0}; //Chaine qui servira a stocker ce qui est entré par l'utilisateur
        changerValeur(l, ""); //On vide la chaine (voir après)
        while(c[0] != '\n')
        {
            c[0] = getchar(); //On récupère le dernier caractère
            if(c[0] != '\n') //Si ce n'est pas un retour à la ligne
                concatener(l, c); //On met à la fin de la chaine
        }
     
    }
     
    void changerValeur(Liste *l, char* str)
    {
        l->valeur = realloc(l->valeur, (strlen(str) + 1) * sizeof(char));
        if(l->valeur == NULL)
           exit(EXIT_FAILURE);
        /*On réalloue le tableau avec la taille de la nouvelle chaine. Pas besoin de réallouer à la fin puisque
     on veut écraser l'ancienne valeur de la chaine */
        strcpy(l->valeur, str); //Enfin on copie la nouvelle chaine dans l'ancienne...
        l->longueur = strlen(str); //... et on met à jour la taille du tableau
    }
    void concatener(Liste *l, char* str)
    {
        l->valeur = realloc(l->valeur, (l->longueur + (strlen(str) + 1)) * sizeof(char));
        if(l->valeur == NULL)
            exit(EXIT_FAILURE);
        /*On réalloue, mais cette fois avec la taille initiale en plus*/
        strcpy((l->valeur + l->longueur), str); //On copie la chaine à partir de la fin
        l->longueur += strlen(str); //Et on met à jour la taille de la chaine
    }
     
    void liberer(Liste *l)
    {
        free(l->valeur);
        l->valeur = NULL;
    }
     
    char* chaine(Liste *l)
    {
        return l->valeur;
    }

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 06/01/2012, 10h06
  2. [XL-2007] Seléctionner les 3 dernières colonnes d'un tableau à taille variable
    Par ron13 dans le forum Macros et VBA Excel
    Réponses: 12
    Dernier message: 31/08/2011, 05h14
  3. tableau taille variable
    Par piero53 dans le forum VB.NET
    Réponses: 14
    Dernier message: 13/07/2011, 02h08
  4. [TP] Tableau de taille variable
    Par Ripley dans le forum Turbo Pascal
    Réponses: 4
    Dernier message: 30/01/2006, 15h36
  5. Comment obtenir un tableau à taille variable ?
    Par marsupilami34 dans le forum Langage
    Réponses: 6
    Dernier message: 27/06/2005, 15h03

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo