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 :

Embrouille avec les malloc / calloc / realloc


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Août 2008
    Messages
    66
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 66
    Par défaut Embrouille avec les malloc / calloc / realloc
    Bonsoir à tous,
    J'apprends petit à petit, mais je me suis rendu compte que j'avais un problème avec les chaines de caractères et la mémoire alloué avec les malloc / calloc etc.. (je ne connais pas le nom français). Bref j'ai voulu me faire un petit exercice "simple" pour manipuler cela. Mon but : jouer avec ce qui me gène, les pointeurs de pointeurs, la mémoire allouée et non contrainte et les chaines de caractère cela donne ça :

    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
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <strings.h>
    #include <duma.h>
     
    char **inclure ( char **storage, long length, char *newitem )
    {
    	char **resul;
    	if ( ! ( resul=realloc ( ( *storage ), ( length+1 ) *sizeof ( char* ) ) ) ) //je reserve un espace mémoire d'une case en plus
    	{
    		printf ( "Erreur lors de l'allocation mémoire\n" );
    		exit ( -1 );
    	}
    	else
    	{
    		resul[length]=newitem;//je place l'élément à rajouter dans l'espace mémoire à la fin
    		return resul;
    	}
    }
     
    char **supprime ( char **storage, long length, long *num )
    {
    char **resul;
    long n;
     
    if ( ! ( resul=realloc ( ( *storage ), ( length-1 ) *sizeof ( char* ) ) ) ) //je reserve un espace mémoire d'une case en moins
    	{
    		printf ( "Erreur lors de l'allocation mémoire\n" );
    		exit ( -1 );
    	}
    for(n=(*num);n<length-1;n++)
    resul[n]=storage[n+1];
     
    return resul;
    }
     
    void lecture ( char **storage, long length )
    {
    long n;
    for(n=0;n<length;n++)// je me place dans chaque case de mon tableau et je lis le mot associé
    printf("%s ",(*storage)[n]);
    }
     
    int main ( int argc, char *argv[] )
    {
    printf("1");//pour tester si cela bloque avant
    char **storage=0;
    long length=2;
    printf("1");
    long *index; *index=2;
    char *string1="hello";
    char *string2="world";
     
    printf("1");
    storage=inclure(storage, length, string1);
    printf("2");
    storage=inclure(storage, (length+1),string2);
    lecture(storage, 2);
    storage=supprime(storage, length, index);
     
    free(*storage);
     
    	return EXIT_SUCCESS;
    }
    Il se compile sans soucis (kdevelop) mais lors de son exécution, j'ai un toout bête "Erreur de segmentation" sauf que la première ligne de mon main n'est même pas exécuté, je ne comprends pas. Je suppose que j'ai fait de très nombreuses fautes dans mon code, si quelque chose vous choque ou vous intrigue merci de me le dire.

    ps : je ne suis pas sûre d'avoir bien compris le realloc, pour moi cela prend la mémoire qui avait été allouée ici en l'occurrence à "storage" et cela la réalloue pour résul, donc simplement an "coupant" la dernière case, est-ce bien ça ? storage est-elle toujours accessible pour autant ? comme je l'utilise par la suite.. ou bien faut-il que je fasse une case tampon ?

    merci encore

  2. #2
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par titimoi Voir le message
    Il se compile sans soucis (kdevelop)
    Oui, enfin, tu peux déjà corriger ça...
    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
     
     
    -------------- Build: Debug in hello ---------------
     
    Compiling: main.c
    Linking console executable: bin\Debug\hello.exe
    C:\dev\hello\main.c: In function `lecture':
    C:\dev\hello\main.c:41: warning: format argument is not a pointer (arg 2)
    C:\dev\hello\main.c: In function `main':
    C:\dev\hello\main.c:47: warning: ISO C90 forbids mixed declarations and code
    C:\dev\hello\main.c:50: warning: ISO C90 forbids mixed declarations and code
    C:\dev\hello\main.c:51: warning: initialization discards qualifiers from pointer target type
    C:\dev\hello\main.c:51: warning: ISO C90 forbids mixed declarations and code
    C:\dev\hello\main.c:52: warning: initialization discards qualifiers from pointer target type
    C:\dev\hello\main.c: At top level:
    C:\dev\hello\main.c:44: warning: unused parameter 'argc'
    C:\dev\hello\main.c:44: warning: unused parameter 'argv'
    C:\dev\hello\main.c: In function `main':
    C:\dev\hello\main.c:50: warning: 'index' might be used uninitialized in this function
    Output size is 20.31 KB
    Process terminated with status 0 (0 minutes, 0 seconds)
    0 errors, 9 warnings
    Ce qui donne ceci :
    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
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    char const **inclure (char const **storage, long length, char const *newitem)
    {
       char const **resul;
       if (!(resul = realloc (storage, (length + 1) * sizeof (char *)))) /* je reserve un espace mémoire d'une case en plus */
       {
          printf ("Erreur lors de l'allocation mémoire\n");
          exit (-1);
       }
       else
       {
          resul[length] = newitem;  /* je place l'élément à rajouter dans l'espace mémoire à la fin */
          return resul;
       }
    }
     
    char const **supprime (char const **storage, long length, long num)
    {
       char const **resul;
       long n;
     
       if (!(resul = realloc (storage, (length - 1) * sizeof (char *)))) /* je reserve un espace mémoire d'une case en moins */
       {
          printf ("Erreur lors de l'allocation mémoire\n");
          exit (-1);
       }
       for (n = num; n < length - 1; n++)
          resul[n] = storage[n + 1];
     
       return resul;
    }
     
    void lecture (char const *const *storage, long length)
    {
       long n;
       for (n = 0; n < length; n++) /* je me place dans chaque case de mon tableau et je lis le mot associé */
          printf ("%s ", storage[n]);
    }
     
    int main (void)
    {
       char const **storage = 0;
       long length = 2;
       long index;
       char const *string1 = "hello";
       char const *string2 = "world";
     
       index = 2;
     
       storage = inclure (storage, length, string1);
       storage = inclure (storage, (length + 1), string2);
       lecture (storage, 2);
       storage = supprime (storage, length, index);
     
       free (storage);
     
       return EXIT_SUCCESS;
    }

  3. #3
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 122
    Billets dans le blog
    148
    Par défaut
    Bonjour,

    J'ai parcouru très vite, donc je ne pense pas apporté de solution ... :s

    Par contre je connaissais pas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    #include <strings.h>
    Habituellement on inclue <string.h> . Mais bon comme ça compile je pense que tu sais ce que tu fais

    Aussi
    C'est mieux de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    char **storage=NULL;
    Même si bien souvent les deux sont équivalent, un pointeur doit être mis à nul, car il se peut que sous certaine plateforme NULL != 0.

    D'après mon debuggeur, l'erreur est ici ( l9 ):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    if ( ! ( resul=realloc ( ( *storage ), ( length+1 ) *sizeof ( char* ) ) ) )
    Si tu veux plus de précision sur le realloc, tu peux écrire dans un terminal : man realloc ( ou dans ton moteur de recherche préférré ). Tu tombera sur la doc

    Je pense que l'erreur est *storage, car c'est comme si tu ecrivais storage[0]... ( je crois ), ce qui me semble pas ce que tu veux faire. Je conseillerai d'enlever l'étoile :p

    Après cette modification faite, tu aura un bug sur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    printf("%s ",(*storage)[n]);
    Je pense que c'est le même problème pour l'étoile.
    Donc explication :
    char **storage;
    En français équivaut à un pointeur, sur un pointeur de caractère.
    ( Souvent dit un pointeur sur une chaine de caractère ).
    Pour accéder au premier caractère de la première chaine tu fais :
    storage[0][0]; // ( char )
    Soit première chaine de caractères :
    storage[0]; // ( char* )

    Pour en revenir à ton cas, si tu veux afficher la chaine de caractère tu dois faire :
    printf("%s", storage[0]);
    Qui affichera la première chaine de caractère. %s dans le printf s'attend à avoir une chaine de caractère et va faire le parcours lui même du tableau jusqu'à trouver un '\0' ( ou 0 ) qui désigne la fin d'une chaine de caractère.

    Donc en faisant une deuxième modification qui voici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    void lecture ( char **storage, long length )
    {
    //long n;
    //for(n=0;n<length;n++)// je me place dans chaque case de mon tableau et je lis le mot associé
    printf("%s ",storage[0]);
    }
    Ton programme ne plantera plus.

    Par contre j'ai pas dit qu'il allait marcher :p

    D'ailleurs pour que se soit un peu mieux, dans le déroulement du programme, la fonction lecture suivante, est celle que tu voulais faire ( j'avais trop modifié le comportement )
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    void lecture ( char **storage, long length )
    {
    long n;
    for(n=0;n<length;n++)// je me place dans chaque case de mon tableau et je lis le mot associé
    printf("%s ",storage[n]);
    }
    ( Pour length et n tu peux utiliser des unsigned int à la place des long).

    Par contre, dans le main l'utilisation de inclure est un peu fausse.
    il faudrait faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    storage=inclure(storage, 0, string1);
    storage=inclure(storage, 1,string2);
    car après tu demande d'afficher jusqu'à la deuxième chaine, alors que tu as placé les chaines de caractères ( 'hello' et 'world' en 2 et 3 ) soit tu affiche pas :p

    Voilà,

    Si tu as plein de questions n'hésite pas
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Août 2008
    Messages
    66
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 66
    Par défaut
    Merci beaucoup pour ces deux réponses, je vais passer un peu de temps dessus et je me remontre pour expliquer si j'ai tout compris !
    (en fait cette question fait suite à un TP non corrigé, je fais mes études en allemand, ce qui est loin d'être simple pour la compréhension de choses un peu compliqué comme les pointeurs de pointeur ) pour realloc, je ferrais également des recherche bien entendu , merci encore

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Août 2008
    Messages
    66
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 66
    Par défaut
    Une petite réponse Emanuel, au niveau des "const" à rajouter un peu partout, je suppose que cela va te faire grincer des dents, mais comme dis plus haut ce self-exercice est issu d'un TP et on nous impose les déclaration de certaines fonctions, donc avec des "char **storage" sans les const, et je sais que cela ne change pas grand chose (c'est simplement au niveau mémoire n'est-ce pas ?) mais par principe je ne compte pas y toucher.

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Août 2008
    Messages
    66
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 66
    Par défaut
    Bonjour LittleWhite et merci beaucoup pour ton aide détaillée :

    Citation Envoyé par LittleWhite Voir le message
    Habituellement on inclue <string.h> . Mais bon comme ça compile je pense que tu sais ce que tu fais
    En effet, j'ai déjà eu des problèmes, avec ou sans "s" ça compile.. et ça rends la même erreur. Mais en général avec un "s" ça marchait mieux..
    Citation Envoyé par LittleWhite Voir le message
    D'après mon debuggeur, l'erreur est ici ( l9 ):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    if ( ! ( resul=realloc ( ( *storage ), ( length+1 ) *sizeof ( char* ) ) ) )
    [..]
    Je pense que l'erreur est *storage, car c'est comme si tu ecrivais storage[0]... ( je crois ), ce qui me semble pas ce que tu veux faire. Je conseillerai d'enlever l'étoile :p

    Après cette modification faite, tu aura un bug sur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    printf("%s ",(*storage)[n]);
    Je pense que c'est le même problème pour l'étoile.
    En effet ça se tient.. et c'est vrai que je m'embrouille très facilement, les explications premières n'ayant pas été faite dans ma langue.. ça met plus longtemps à imprimer !
    Citation Envoyé par LittleWhite Voir le message
    Par contre j'ai pas dit qu'il allait marcher :p
    [..]
    ( Pour length et n tu peux utiliser des unsigned int à la place des long).

    Par contre, dans le main l'utilisation de inclure est un peu fausse.
    il faudrait faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    storage=inclure(storage, 0, string1);
    storage=inclure(storage, 1,string2);
    car après tu demande d'afficher jusqu'à la deuxième chaine, alors que tu as placé les chaines de caractères ( 'hello' et 'world' en 2 et 3 ) soit tu affiche pas :p

    Voilà,

    Si tu as plein de questions n'hésite pas
    En effet mon length doit partir à 0 tu as raison, pour ce qui est du long ou int,
    ce n'est qu'une histoire de bytes aloués, rien de bien méchant.. ici aussi c'est les directives de l'exo sur lequel je me suis basé.. je suis bien conscient qu'il comporte des imperfection.


    Pour en revenir à mon erreur de base.. elle demeure avec toujours ce "segmentation error".. avant même l'affichage de mon premier printf du main.. je me repenche dessus avec le yeux en face des trous demain. merci pour votre aide.

  7. #7
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par titimoi Voir le message
    Pour en revenir à mon erreur de base.. elle demeure avec toujours ce "segmentation error".. avant même l'affichage de mon premier printf du main.. je me repenche dessus avec le yeux en face des trous demain. merci pour votre aide.
    • tu es conscient que tu fais du C99, là ?

      En dehors de C99, les instructions AVANT les déclarations sont prohibées, or tu en as dans ton main...


    • Plus quelque chose de grave, qui peut expliquer ton segmentation faut :

      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      long *index; *index=2;
      Que crois-tu faire, là ?

      Tu déclares un pointeur.. Et tu lui affectes une valeur... pas bo du tout

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Août 2008
    Messages
    66
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 66
    Par défaut
    Citation Envoyé par souviron34 Voir le message
    [LIST][*]tu es conscient que tu fais du C99, là ?

    En dehors de C99, les instructions AVANT les déclarations sont prohibées, or tu en as dans ton main...
    Je t'avoue ne pas en être conscient en effet, dois-je donc mettre mon main au début et faire les déclaration de fonction avant ? en fait j'ai pas compris

    Citation Envoyé par souviron34 Voir le message
    long* indique que mon pointeur va indiquer un long, donc si je fais *index, je suis censé avec un long, je pensais donc que je puisse faire ça... merci de m'indiquer mon erreur..

  9. #9
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Par défaut
    Non, le problème vient du fait que tu as une variable non initialisée.

    long *index ; ==> index est donc un pointeur sur long ==> pourquoi pas mais index n'a pas de valeur, donc pour l'instant, c'est un pointeur fou.

    *index = 2; ==> à l'adresse pointée par index, on met 2 ==> gros problème, l'adresse pointée par index est folle, non initialisée ==> on va donc écrire 2 n'importe où et cela va très certainement crasher.
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  10. #10
    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
    long* indique que mon pointeur va indiquer un long, donc si je fais *index, je suis censé avec un long, je pensais donc que je puisse tout coller..
    Tu as créé un pointeur (index). Créer un pointeur ne crée pas la variable pointée mais juste une variable prête à recevoir une adresse. Dans ton cas *index n'existe pas; pire, index contient n'importe quelle valeur et *index = 2 va prendre cette valeur comme une adresse et essayer d'écrire à cet endroit. Plantage assuré !
    Ici, c'est tout différent : le pointeur est créé et initialisé avec l'adresse d'une variable. Il peut être utilisé pour accéder à cette variable.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    long nombre;
    long * index;
    index = &nombre; // ici je mets dans le pointeur l'adresse de nombre
    *index = 2 ; // Ce qui revient à faire nombre = 2

  11. #11
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par titimoi Voir le message
    Je t'avoue ne pas en être conscient en effet, dois-je donc mettre mon main au début et faire les déclaration de fonction avant ? en fait j'ai pas compris
    En C99 ceci est correct (au détail mentionné ci-dessus près) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    int main ( int argc, char *argv[] )
    {
    printf("1");//pour tester si cela bloque avant
    char **storage=0;
    long length=2;
    printf("1");
    long *index; *index=2;
    Dans toute autre variation de C (89,90,95) :

    ces instructions en gras sont incorrectes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main ( int argc, char *argv[] )
    {
    printf("1");//pour tester si cela bloque avant
    char **storage=0;
    long length=2;
    printf("1");
    long *index; *index=2;

    Pour être conforme, il faudrait faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main ( int argc, char *argv[] )
    {
    char **storage=0;
    long length=2;
    long *index; *index=2;
    printf("1");
    printf("1");/* pour tester si cela bloque avant */
    et les commentaires sont des /*...*/ et non des // ..


    Au départ toutes les déclarations..

    PUIS les instructions...

Discussions similaires

  1. probleme avec malloc et realloc
    Par zouari.rami dans le forum Débuter
    Réponses: 2
    Dernier message: 12/03/2011, 14h07
  2. probleme avec les malloc snprintf
    Par pinto_armindo dans le forum Réseau
    Réponses: 8
    Dernier message: 30/10/2007, 18h08
  3. malloc calloc realloc free
    Par lia20 dans le forum C
    Réponses: 7
    Dernier message: 26/05/2007, 15h22
  4. PB d'import avec les ActiveX sous BCB6
    Par dergen dans le forum C++Builder
    Réponses: 4
    Dernier message: 29/11/2002, 10h18
  5. Pbm avec les '&'...
    Par AmaX dans le forum Composants VCL
    Réponses: 2
    Dernier message: 19/08/2002, 11h08

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