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 :

Exploiter tableaux dynamiques


Sujet :

C

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2012
    Messages : 12
    Par défaut Exploiter tableaux dynamiques
    Bonjour, suite au message que j'ai posé hier je tente de comprendre les tableaux dynamiques (bien qu'au final c'est un tableau de taille fixe que j'utilise, mais ne compliquons pas les choses plus qu'elles ne le sont!).

    L'objectif est simuler ce qui suit avec une boucle:
    Code c : 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
    int main(int argc, char **argv)
    {
        char str[6] = "abcde"; // 6 car \0 à la fin
        char copy[6];
     
        copy[0]=str[0];
        copy[1]=str[1];
        copy[2]=str[2];
        copy[3]=str[3];
        copy[4]=str[4];
        copy[5]=str[5];
     
       /*
        * Le code qui suit n'est pas autorisé (sauf en C99 je pense)
        int i;
        for(i=0; i<6; i++){
    	copy[i] = str[i];
        }   
        */
     
        printf("%s\n", copy); // affiche bien abcde
        return 0;
    }
    Je tente ma chance avec malloc():
    Code c : 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
    int main(int argc, char **argv)
    {
        char str[6] = "abcde"; // 6 car \0 à la fin
        char *copy;
     
        copy = malloc(6 * sizeof(int)); // On alloue de la mémoire pour le tableau copy
     
        int i;
        for(i=0; i<6; i++){
    	copy[i] = str[i];
        }
     
        printf("%s\n", copy);
        free(copy);
        return 0;
    }
    Est-ce la bonne méthode ( malloc() vs calloc() )? Existe-t-il quelque chose de plus simple?

    Merci pour le temps que vous me consacrerez.

  2. #2
    Membre chevronné

    Profil pro
    Inscrit en
    Août 2007
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 179
    Par défaut
    Ben c'est pas trop mal comme ça, c'est bien malloc() (puis c'est important d'apprendre à s'en servir), calloc() ne me semble pas très utile vu que tu définies tout de suite les valeurs (donc pas indispensable de les initialiser à 0)
    Une petite remarque tu utilises la taille la taille d'un "int" pour allouer des char. Fais plutôt
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    copy = (char*)malloc(6 * sizeof(char));
    (le (char*) ne sert à rien mais il augmente la lisibilité de ton code)

    enfin, on peut pas faire beaucoup plus simple si ce n'est en laissant "copy" sous forme de tableau (char copy[6];) comme dans le code que tu simules, du coup plus besoin de malloc (et de free) mais si tu ne l'as pas fait j'imagine qu'il y a une raison...

    edit : dernière petite remarque autant éviter les valeurs en dur par exemple dans ta boucle plutôt que d'aller jusqu'à 6, mieux vaux mettre strlen(str), ça fait plus sérieux et ça évite de devoir changer tout ton code si par exemple tu modifies la tailles des tableaux

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2012
    Messages : 12
    Par défaut
    enfin, on peut pas faire beaucoup plus simple si ce n'est en laissant "copy" sous forme de tableau (char copy[6] comme dans le code que tu simules, du coup plus besoin de malloc (et de free) mais si tu ne l'as pas fait j'imagine qu'il y a une raison...
    oui, il y a une raison, comme écrit plus haut:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    /*
        * Le code qui suit n'est pas autorisé (sauf en C99 je pense)
        int i;
        for(i=0; i<6; i++){
    	copy[i] = str[i];
        }   
        */
    Ne vaut mieux-t-il pas coder en C89 pour une raison de portabilité?

  4. #4
    Membre chevronné

    Profil pro
    Inscrit en
    Août 2007
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 179
    Par défaut
    Citation Envoyé par programmeur.debutant Voir le message
    Ne vaut mieux-t-il pas coder en C89 pour une raison de portabilité?
    Mouais sans doute, encore qu'il y a moyen de tester que le compilateur est ou non compatible avec C99 et de coder en fonction (notament en testant si "__STDC_IEC_559__" est défini) mais là on rentre peut être dans des choses un peu compliquées.
    Par contre je ne vois pas ce qu'il y a de si incompatible avec C89 dans le code que tu présentes. Mets la déclaration de "i" avec les autres, les vieux compilateurs n'aiment pas trop que l'on déclare les variables n'importe où mais si tu arrives à avoir encore une erreur après ça, je suis curieux de la voir.

  5. #5
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 496
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 496
    Billets dans le blog
    1
    Par défaut
    Mettons certaines choses au clair

    Le terme de tableau dynamique est bizarre. En C, je pense qu'on peut dire qu'il y a d'un côté les tableaux, déclarées avec des [] et qui alloue une zone mémoire de taille fixe ou statique. ll y a de l'autre côté des pointeurs qui pointent sur une zone allouée dynamiquement avec malloc ou calloc et libérer par free. Dynamique car on peut faire des realloc, un free puis un nouveau malloc. Statique car on ne peut pas redimensionner. C'est bien l'allocation mémoire qui est statique ou dynamique, plus que le tableau (qui, à un instant donné est toujours de taille fixe).


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    /*
        * Le code qui suit n'est pas autorisé (sauf en C99 je pense)
        int i;
        for(i=0; i<6; i++){
    	copy[i] = str[i];
        }   
        */
    Pourquoi dis-tu cela ? Ca marche très bien en C89/90 et C99.


    Malloc vs calloc ? A part la mise à zéro et l'écriture, pas grand chose de différent.


    dernière petite remarque autant éviter les valeurs en dur par exemple dans ta boucle plutôt que d'aller jusqu'à 6, mieux vaux mettre strlen(str), ça fait plus sérieux et ça évite de devoir changer tout ton code si par exemple tu modifies la tailles des tableaux
    C'est vrai qu'il faut mieux ne pas écrire 6 partout, car le jour où tu souhaites que ce soit 8, il faut le changer partout. Mais la solution du strlen dans le for est une mauvaise idée pour le coup car la fonction sera appelée à chaque itération. Il faut mieux utiliser une variable pour stocker le résultat strlen et utiliser cette variable comme condition d'arrêt.

    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
    int main(int argc, char **argv)
    {
        char str[] = "une chaine. Je ne specifie pas la taille de "
        "'str' entre [] si je n'ai rien a rajouter a la fin.\n"
        "Si je veux une taille determinee du tableau, il faut le faire.\n";
     
        size_t longueur = strlen(str);
     
        char copy[longueur + 1]; /* Cette ecriture genere un warning en C89/90
                                    qui n'accepte pas les tableaux a taille variable
                                    (comprendre donnee par une variable).
                                    +1 pour '\0' final */
     
        size_t i;
     
        for(i=0; i<longueur; i++)
        {
            copy[i] = str[i];
        }
     
        printf("%s\n", copy);
        return longueur;
    }

    Quand à la question de la portabilité, j'ai envie de répondre : @#!?** $%#[!?@ on est au C11, stop le C89 ! Codons en C89 si pour mettre à jour une application en C89 ; pour une nouvelle application, codons en C99 (et C11 prochainement).

    Et comme dit par Pythéas, s'il y a besoin, il est possible de vérifier si le compilateur utilisé supporte le C99 ou seulement le C89/90. Donc s'il y a vraiment besoin de compatibilité (d'ailleurs, c'est plus de la compatibilité que de la portabilité), on peut faire ça

  6. #6
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2012
    Messages : 12
    Par défaut
    Citation Envoyé par Bktero
    Pourquoi dis-tu cela ? Ca marche très bien en C89/90 et C99.
    Pas si j'en crois ceci :

    Le langage C existe en plusieurs versions.
    Une version récente, appelée le C99, autorise la création de tableaux à taille dynamique, c'est-à-dire de tableaux dont la taille est définie par une variable :
    ...

    ? Mais alors… il est interdit de créer un tableau dont la taille dépend d'une variable ?

    Non, rassurez-vous : c'est possible, même en C89. Mais pour faire cela, nous utiliserons une autre technique (plus sûre et qui marche partout) appelée l'allocation dynamique. Nous verrons cela bien plus loin dans ce cours.
    et ça se vérifie sur Wikipédia où on peut lire:
    Citation Envoyé par Wikipédia
    En 1999, une nouvelle évolution du langage est normalisée par l'ISO : C99 (formellement ISO/CEI 9899:1999). Parmi les ajouts, on notera les tableaux dynamiques, ainsi que des fonctionnalités (types complexes, mot-clef « restrict », directives agissant sur la simplification des instructions arithmétiques) souhaitables pour les calculs numériques intensifs, domaine habituel de FORTRAN.
    Et vu que vous me tendez la perche, faut-il spécifier quelque part dans le code source quelle version du C on utilise. Pour informer le compilateur (ça peut être bête comme question) ou tout simplement pour celui qui reprendra le code source par après moi.

    Ok, donc je ne me focalise pas sur le C89, je peux me laisser tenter par le c99.
    Vous avez quelques liens à me fournir pour me documenter sur les différences notables.

    Encore merci les gars.

  7. #7
    Membre Expert Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Par défaut
    Bonjour,

    Vous mélangez un peu tout. On va préciser quelques trucs. Tout d'abord ceci :

    n'est pas un tableau dynamique (au sens alloué sur le tas) !
    Par conséquent c'est du code totalement valide en C89. Par contre faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int taille;
    scanf("%d", &taille);
    char str[taille];
    n'est pas valide en C89 car la taille de str n'est pas connue à la compilation.

    Pour revenir à ton problème, pour faire ta copie, tu ne sauras généralement jamais la taille du tableau que tu vas copier, et c'est pour ça que tu utiliseras l'allocation dynamique (ce qui veut dire que tu ne connais pas la taille du tableau à la compilation). Par conséquent ce que tu cherches à faire c'est le code de la fonction strcpy :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    char* strcpy(char* dst, const char* src)
    {
      int i;
      for(i = 0; src[i] != '\0'; ++i)
        dst[i] = src[i];
      dst[i] = '\0';
      return dst;
    }
    Comme tu vois ce code n'alloue rien, il faut donc l'utiliser comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    int main()
    {
      char machaine[100];
      scanf("%99s", machaine); // on ne veut pas que l'utilisateur rentre plus de caractère que le buffer...
     
      char* macopie = malloc(strlen(machaine) + 1); // copie exacte du nombre de caractère entré.
      strcpy(macopie, machaine);
    }

  8. #8
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2012
    Messages : 12
    Par défaut
    Citation Envoyé par Trademark
    Vous mélangez un peu tout. On va préciser quelques trucs. Tout d'abord ceci :n'est pas un tableau dynamique (au sens alloué sur le tas) !
    Par conséquent c'est du code totalement valide en C89.
    Tout à fait d'accord vu que la taille du tableau est fournie lors de l'initialisation. "Vous", c'est moi ou également Bktero et Phytéas

    Citation Envoyé par Trademark
    Par contre faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int taille;
    scanf("%d", &taille);
    char str[taille];
    n'est pas valide en C89 car la taille de str n'est pas connue à la compilation.
    Encore d'accord et ça confirme ce que j'ai lu; Et d'où l'intérêt d'utiliser malloc().

    Citation Envoyé par Trademark
    Par conséquent ce que tu cherches à faire c'est le code de la fonction strcpy
    Si tu veux mais, le code que j'ai fourni n'était qu'un exemple parmi tant d'autres. Ce que je cherchais à savoir (et j'ai eu ma réponse), c'était si j'étais obligé d'utiliser malloc() pour pouvoir utiliser une variable à la place d'un index "en dur" pour assigner une valeur à la position fournie par la variable dans un tableau, par exemple tableau[variable]="A"; (ou n'importe quoi d'autre).

    La réponse est oui (si j'ai bien compris) si je me réfère au C99 et supérieur et à condition que mon compilateur m'y autorise. Mais du coup, j'ai une nouvelle question. Comment je sais sur quelle version se base mon compilateur. Je compile avec gcc, je vais jeter un oeil dans le man.

  9. #9
    Membre Expert Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Par défaut
    Tu dois compiler avec l'option -std=c99.

  10. #10
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 496
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 496
    Billets dans le blog
    1
    Par défaut
    Je ne savais pas que l'écriture int tab[a]; s'appelait un tableau dynamique. Je trouve ce terme un peu bâtard quand même. Ce n'est effectivement pas autorisé en C89/90, comme je l'ai précisé dans mon code exemple. Mais c'est uniquement ça qui n'est pas autorisé, la boucle elle est tout à fait valable !


    En C89, tu devais donc passer par une allocation dynamique avec malloc / free pour créer un tableau dont la taille n'est pas connue à la compilation. En C99, tu peux passer par une allocation statique bien qu'avec une taille variable (je crois manquer un peu de rigueur sur ces termes...). Ca allège le code pour des variables locales à une fonction et limite les risques de fuite mémoire en oubliant les free (pas bien !).


    gcc supporte C99 depuis des années. Je pense d'ailleurs que le support de C11 ne devrait pas tarder. L'option est effectivement -std=c99, bien que sans cette option, il fait une compilation où il ne met que des warning et non des erreurs sur les écritures interdites en C89/90 mais valables en C99.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Ok, donc je ne me focalise pas sur le C89, je peux me laisser tenter par le c99.
    C'est mon avis. Mince, le C99 a quand même 13 ans, il serait temps de l'utiliser.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Vous avez quelques liens à me fournir pour me documenter sur les différences notables.
    Euh.... Attend je vais me renseigner sur Wikipedia, je ne suis pas capable de te les citer ! http://en.wikipedia.org/wiki/C99#Design
    En vrac si tu ne parles pas anglais :
    • les commentaires avec // ... et non /* ... */
    • les tableaux à taille variable (je trouve ce terme mieux adapté que tableau dynamique en fait)
    • les fonctions inline
    • un type booléen
    • snprintf !
    • un type complexe
    • des macros a nombre variables d'arguments
    • la possibilité de mixer déclarations et codes "réel" dans une fonction (en C89, toutes les déclarations doivent être au début)

    Je vais rajouter deux trucs pour me faire de la pub :


  11. #11
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2012
    Messages : 12
    Par défaut
    En tout cas, merci encore, vos conseilles sont précieux. Quand on débute, ce n'est pas toujours évident de trouver les "bonnes informations" sachant que sur internet on trouve tout et son contraire (j'exagère peut-être).

    Après, faut peaufiner ses rechercher dans des lieux plus spécialisés, tels que les docs officielles ou les très bons cours et tutoriels pour apprendre le C présents sur developpez.com. Mais bon, après tout, c'est comme ça qu'on apprend, en cherchant.

    Merci pour la lecture, je vais travailler tout ça.

  12. #12
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    Autant pour moi, je ne savais pas que l'écriture int tab[a]; s'appelait un tableau dynamique.
    Moi non plus et ce n'en est pas un. Le qualificatif "dynamique" s'applique à une méthode d'allocation (par malloc() ou apparentée) d'une variable comme les termes "automatique" (variables locales non static) et "statique" (variables globales ou déclarées static)

    En C99, tu peux passer par une allocation statique bien qu'avec une taille variable (je crois manquer un peu de rigueur sur ces termes...).
    Pour les VLA du C99, tableaux du genre int tab[a], où a est une variable, l'allocation est toujours automatique (donc pas de VLA en global). Leur utilisation a d'autres restrictions (par exemple ils ne peuvent faire partie d'une structure ou d'une union).
    La taille n'est pas variable mais définie par la valeur d'une variable au moment de la création du tableau. La taille du tableau est fixe et déterminée, comme d'habitude, au moment de la création et ne peut changer (même realloc(), par principe, crée un nouveau tableau, copie l'ancien dans le nouveau et détruit l'ancien. Bien sûr, il est possible que ce processus soit fait parfois, de façon équivalente, "sur place").

    A noter que les VLA sont devenus optionnels dans C11, donc leur utilisation n'est-elle pas devenue un peu obsolete de fait ?

    Sur les différences C89/C99, voir aussi le tutoriel Les nouveautés du C99

    Sur C11 voir la discussion C11 : la normalisation est achevée

  13. #13
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 496
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 496
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par diogene Voir le message
    Moi non plus et ce n'en est pas un
    Bon, ça me rassure


    Citation Envoyé par diogene Voir le message
    Pour les VLA du C99, tableaux du genre int tab[a], où a est une variable, l'allocation est toujours automatique (donc pas de VLA en global). [...]
    La taille n'est pas variable mais définie par la valeur d'une variable au moment de la création du tableau
    Ah ! Voilà (en gras) la formulation que je cherchais !


    Citation Envoyé par diogene Voir le message
    A noter que les VLA sont devenus optionnels dans C11, donc leur utilisation n'est-elle pas devenue un peu obsolete de fait ?
    Cela veut-dire que les compilateurs sont libres de l'implémenter ou non ? Remarque, je ne voyais pas trop l'intérêt. C'était juste un moyen de pas faire malloc / free dans la même fonction ?

Discussions similaires

  1. Tableaux dynamiques
    Par sebduth dans le forum Fortran
    Réponses: 5
    Dernier message: 05/07/2005, 15h36
  2. tableaux dynamiques
    Par Mynautor dans le forum C++
    Réponses: 23
    Dernier message: 12/02/2005, 02h45
  3. [D7] Tableaux dynamiques dans un record
    Par bobby-b dans le forum Langage
    Réponses: 2
    Dernier message: 30/06/2004, 23h23
  4. Article sur les tableaux dynamiques
    Par Eric Sigoillot dans le forum Langage
    Réponses: 2
    Dernier message: 16/04/2004, 22h00
  5. [Kylix] Tableaux dynamiques sour Kylix2
    Par Krän dans le forum EDI
    Réponses: 6
    Dernier message: 07/10/2003, 14h31

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