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 :

malloc() et char**


Sujet :

C

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Avril 2013
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2013
    Messages : 21
    Par défaut malloc() et char**
    Bonjour,

    Je fais appelle à vous car j'ai besoin d'aide pour un bout de code C qui récupère et stock les arguments de la LDC dans un tableau de strings.

    Clairement ce qu'il me faut c'est :

    - je tape des "trucs" sur la ligne de commande :
    ./recupldc minou le gros chat

    - et le programme construit un tableau de ces "trucs" du type :
    arglist = ["minou", "le", "gros", "chat"]

    Le but étant bien sûr d'utiliser chaque élément passé sur la LDC dans la suite du programme. Admettons ici qu'on veuille juste les imprimer à l'écran pour avoir :

    minou
    le
    gros
    chat

    Voici ce que j'ai :

    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
    int main(int argc, char *argv[])
    {
    	int i = 0;
    	char **arglist;
     
    	if (argc < 2)
    	{
    		printf("pas d'arguments sur la LDC\n");
    		return(EXIT_FAILURE);
    	}
     
    	arglist = malloc(argc * sizeof(char*));
    	if (arglist != NULL)
    		for (i=1 ; i<argc ; i++)        // i=1 : pas prendre le nom du prog
    		{
    			arglist[i-1] = malloc(sizeof(char*));        // oui je sais y'a déjà un malloc au-dessus.
    			arglist[i-1] = strdup(argv[i]);
    		}
     
    	for (i=0 ; i<argc-1 ; i++)
    		printf("%s\n", arglist[i]);
     
    	return EXIT_SUCCESS;
    }
    J'ai mis deux malloc() qui sûrement scandaleusement mal utilisés, je voudrais justement savoir comment les utiliser, est-ce qu'il faut faire un seul malloc() du type : malloc(argc * (char*)) ou bien un malloc() pour la taille du tableau puis un autre pour la taille de chaque chaîne qu'on ajoutera au tableau ?

    J'apprends le C par moi-même et j'ai beaucoup appris en suivant les tutos et les forums de ce site. Toutefois si jusque là je n'avais pas de problème pour l'allocation dynamique c'est parce que je me contentais de l'appliquer à des tableaux d'entier, pas à des tableaux de chaines.

    Merci d'avance pour votre aide :-) !!

  2. #2
    Membre Expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Par défaut
    Bonjour,

    Commençons par les paramètres donnés à la fonction main :
    • argc est toujours positif ou nul
    • argv est un tableau de chaîne de caractères qui contient argc+1 éléments avec la contrainte argv[argc]=NULL
    • si argc>0, alors argv[0] contient le nom du programme ou "" s'il n'est pas disponible
    • si argc>1, alors argv[1] à argv[argc-1] contiennent les paramètres du programme
    • quand ils existent, les éléments de argv sont modifiables

    C'est ce qu'on retrouve au §5.1.2.2.1.2 de la norme C11.
    Première remarque la liste des paramètres si il y en a (donc si argc>1) est de longueur argc-1.

    Passons à malloc. Quand tu veux allouer une zone mémoire contigüe pouvant contenir nb_element d'éléments de même type type_element tu peux utiliser malloc ainsi : type_element *ma_variable=malloc( nb_element * sizeof *ma_variable );.

    Cela étant dit, la ligne 12 de ton programme devrait-être
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    arglist = malloc( (argc-1) * sizeof *arglist );
    On alloue un tableau de argc-1 éléments (cf ma première remarque) dont le type des éléments est celui utilisé lors de la déclaration de la variable arglist.
    En utilisant malloc la mémoire allouée n'est pas intialisée et contient ce qu'on appelle du garbage = n'importe quoi.
    Il arrive que les éléments du conteneur doivent être également dynamiquement allouées. Dans ce cas il faut faire une boucle pour les allouer l'un après l'autre.
    Lors de la libération de la mémoire, il va falloir le faire en sens inverse -> d'abord libérer les éléments les uns après les autres, puis une fois cela fait, libérer le conteneur.


    Passons au problème de la duplication des chaînes. Dans la suite on va dupliquer la chaîne src dans dst, Il y a plusieurs façons de faire :
    • on fait tout soi-même
      1. on détermine la longueur de src
      2. on alloue une nouvelle chaîne de la bonne longueur = la longueur de src + 1 pour le caractère \0 qui marquera la fin de la chaîne
      3. on copie le contenu de src vers dst

      ce qui se traduit en C par :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      char* dst;
      size_t src_length=strlen(src);                  // 1.
      dst=malloc( ( src_length + 1) * sizeof(*dst) ); // 2.
      strcpy(dst,src);                                // 3.
    • on laisse faire tout ça par une fonction de la bibliothèque
      strdup fait tout : elle calcule l'espace requis, l'alloue, le remplit et te le renvoie ... tu n'as rien à faire


    La première méthode est classique, portable, pas forcément secure c'est vrai.
    La seconde utilise une fonction qui n'est pas forcément disponible sur toutes les plateformes ...
    Dans les deux cas de figures tu devras libérer la mémoire allouée avec un free par allocation.

    Cela dit ta boucle en lignes 14-18 devient :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for(i=1; i<argc; ++i)
      arglist[i-1] = strdup( argv[i] );
    Les frees maintenant. À chaque allocation doit correspondre une libération. Pour libérer arglist on commence par libérer les éléments car on a utilisé strdup (malloc caché) pour les créer. Il faut faire une boucle est les libérer un par un :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for(i=0; i<argc-1; ++i)
      free(arglist[i]);
    Une fois que tout le contenu est libéré, on peut libérer le conteneur :
    Et le tour est joué.

    Les références que tu peux consulter :
    man pages de malloc, free, strcpy, strdup.

    La norme C11 (draft) en version pdf.

    Évidemment les cours c, la FAQ c de developpez.net

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Avril 2013
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2013
    Messages : 21
    Par défaut
    Merci pour ta réponse, vraiment très claire et rapide !

    C'est ce que je pensais faire, allouer l'espace pour chaque chaine du tableau mais je n'aurais pas pensé à faire une boucle pour les free().

    Maintenant je souhaite ajouter un élément en plus dans arglist, qu'importe les chaines passées sur la LDC. Je peux donc allouer argc plutôt que argc-1 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    arglist = malloc( (argc) * sizeof *arglist );
    et en suite libérer argc plutôt que argc-1 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for (i=0; i<argc; ++i)
        free(arglist[i]);
    Il n'y a pas de soucis ?

    Merci encore pour ta réponse !!!!!

  4. #4
    Membre Expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Par défaut
    Il n'y aura pas de soucis si l'élément que tu ajoutes a été auparavant alloué avec malloc (explicitement ou par une autre fonction comme strdup).

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

Discussions similaires

  1. malloc sur char* (avec le sizeof d'un char[])
    Par fcjunic dans le forum Débuter
    Réponses: 2
    Dernier message: 01/02/2011, 08h32
  2. Malloc d'un char ** du maillon d'une liste chainee
    Par student_ dans le forum Débuter
    Réponses: 4
    Dernier message: 03/01/2010, 12h56
  3. Initialisation, const char *, malloc
    Par kromartien dans le forum C
    Réponses: 8
    Dernier message: 17/06/2007, 23h53
  4. Réponses: 6
    Dernier message: 07/05/2006, 21h42
  5. Réponses: 6
    Dernier message: 06/12/2005, 09h41

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