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 arrète mon programme alors qu'à priori de la mémoire est disponible.


Sujet :

C

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    19
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2007
    Messages : 19
    Points : 13
    Points
    13
    Par défaut malloc arrète mon programme alors qu'à priori de la mémoire est disponible.
    Bonjour

    Je pensais avoir compris le fonctionnement du malloc, mais quelque chose doit je le crains m'échapper, si quelqu'un pouvait m'expliquer là où j'ai faut, je lui en serais très reconnaissant.

    Tout d'abord, sachez que pour le débuggage j'utilise une variable globale, une fonction "inline" et une macro:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    #define FREE(n) {mal--;free(n);n=NULL;}
    int mal=0;
     
    inline void *MALLOC(size_t n){
         mal++;
         return malloc(n);
    }
    que j'utilise à la place de malloc et de free, ce qui me permet de connaître le nombre de bloc mémoire alloué à un moment donné et de mettre automatiquement à NULL les pointeurs qui ne pointent plus vers rien.

    J'ai une fonction récursive "interprete" qui, si l'on est dans le cas final ne fait rien, sinon commence par allouer de la mémoire, fait des effets de bords sur d'autre variable globale (uniquement des entiers), puis désalloue la mémoire.
    Avant chaque appel d'interprete je stock dans une variable tmp la valeur de mal, et je vérifie que mal==tmp après l'exécution.

    Une fonction "precompiler" possède un vecteur de pointeur de caractère (un vecteur de chaîne en fait). Ensuite elle boucle sur ce qui suit:on initialise avec des chaînes contenant l'unique caractère null.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    char* fonction[27];
         for(i=0;i<27;i++){
                            fonction[i]=(char*) MALLOC(sizeof(char));
                            *(fonction[i])='\0';
         }
    dans certaines conditions on exécute
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
                              FREE(fonction[lettre_deb]);
                              fonction[lettre_deb]=ligne;
    où lettre_deb est un entier entre 0 et 26 et ligne une chaîne de caractère allouée.
    On appelle interprete, puis l'on désalloue le vecteur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
                    for(i=0;i<27;i++){
                                      FREE(fonction[i]);
                    }
    A la fin du main j'ai placé un scanf afin que la fenêtre ne se ferme pas.
    J'ai placé aux endroits stratégiques de printf afin qu'au fur et à mesure que le programme s'exécute je sache où je suis et la valeur des variables importantes.

    A la deuxième itération de la boucle, le programme s'arrête au moment où j'alloue le vecteur fonction avec des pointeurs sur un caractère nul. En général entre là 15ème et la 17ème allocation. (Pour le savoir, il faut que je lance le programme via la console, si je lance le programme via l'option Executer de Dev-C++ la fenêtre se ferme.
    Et ceci alors que à priori la quantité de mémoire alloué est exactement la même à la première et à la deuxième itération.

    Si quelqu'un est capable de m'expliquer ce que j'ai mal compris, où est mon erreur, je lui en serais très reconnaissant.
    Je suis sur Win XP SP2, j'utilise dev C++4.9.9.2 avec l'installation par défaut, donc comme compilateur gcc. Mon processeur est un intel centrino duo,1,60 GHz, 2Go de ram.

  2. #2
    Membre du Club
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    52
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 52
    Points : 62
    Points
    62
    Par défaut
    Pas tout compris.

    Si tu veut un peu d'aide, poste le code complet.
    Bon courage

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

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par Arthur Rainbow Voir le message
    Tout d'abord, sachez que pour le débuggage j'utilise une variable globale, une fonction "inline" et une macro:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    #define FREE(n) {mal--;free(n);n=NULL;}
    int mal=0;
     
    inline void *MALLOC(size_t n){
         mal++;
         return malloc(n);
    }
    que j'utilise à la place de malloc et de free, ce qui me permet de connaître le nombre de bloc mémoire alloué à un moment donné et de mettre automatiquement à NULL les pointeurs qui ne pointent plus vers rien.
    Oui, mais le compteur est décrémenté même si le pointeur est à NULL...
    Ensuite elle boucle sur ce qui suit:on initialise avec des chaînes contenant l'unique caractère null.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    char* fonction[27];
         for(i=0;i<27;i++){
                            fonction[i]=(char*) MALLOC(sizeof(char));
                            *(fonction[i])='\0';
         }
    Une allocation par caractère ? C'est du luxe. Tu es sûr que tu veux faire ça ?
    • Le cast est inutile (MALLOC() retourne void *)
    • sizeof (char) vaut 1 par définition
    • Avant d'utiliser un bloc alloué, il faut vérifier si il est valide (<> NULL)

    dans certaines conditions on exécute
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
                              FREE(fonction[lettre_deb]);
                              fonction[lettre_deb]=ligne;
    où lettre_deb est un entier entre 0 et 26 et ligne une chaîne de caractère allouée.
    Le rôle de 'ligne' n'est pas clair. C'est l'adresse d'un bloc alloué ?
    On appelle interprete, puis l'on désalloue le vecteur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
                    for(i=0;i<27;i++){
                                      FREE(fonction[i]);
                    }
    OK.

    J'ai supprimé l'usage de 'ligne'. Ceci fonctionne correctement :
    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
     
    #include <stdio.h>
    #include <stdlib.h>
     
    #define FREE(n)\
    do\
    {\
       if (n != NULL)\
       {\
          mal--;\
          free (n);\
          n = NULL;\
       }\
    }\
    while (0)
     
    int mal = 0;
     
    #define PRT_MALLOC() printf ("mal = %d\n", mal)
     
    void *MALLOC (size_t n)
    {
       mal++;
       return malloc (n);
    }
     
    int main (void)
    {
     
       char *fonction[27];
       int i;
       for (i = 0; i < 27; i++)
       {
          fonction[i] = MALLOC (sizeof *fonction);
          if (fonction[i] != NULL)
          {
             *(fonction[i]) = '\0';
          }
       }
       PRT_MALLOC ();
     
       {
          int lettre_deb = 10;
     
          FREE (fonction[lettre_deb]);
       }
       PRT_MALLOC ();
     
       for (i = 0; i < 27; i++)
       {
          FREE (fonction[i]);
       }
       PRT_MALLOC ();
     
       return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    mal = 27
    mal = 26
    mal = 0
     
    Press ENTER to continue.
    Pas de Wi-Fi à la maison : CPL

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    19
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2007
    Messages : 19
    Points : 13
    Points
    13
    Par défaut
    Tout d'abord merci pour la prompte réponse.
    Fred83, mon code entier faisant actuellement 824 lignes, je doute qu'il soit pertinant de le poster.

    A Mr Delahaye
    ne allocation par caractère ? C'est du luxe. Tu es sûr que tu veux faire ça ?

    * Le cast est inutile (MALLOC() retourne void *)
    * sizeof (char) vaut 1 par définition
    * Avant d'utiliser un bloc alloué, il faut vérifier si il est valide (<> NULL)
    Du luxe? C'est si couteux que ça une allocation?
    Ma fonction interprete est récursive, et sa profondeur est de 10 000 000, avec des mallocs pour des chaînes de 10 caractères en gros. Donc j'ai jugé ces 27 mallocs comme étant quantité négligeable.
    (Par ailleurs, jusqu'à présent, la fonction interpreter m'a toujours rendu des résultats qui se sont averé être juste.)
    Pour les deux premières remarques, c'est vrai que c'est surtout une habitude que mes professeurs m'ont dit de prendre, et puisque le compilateur sait remplacer "sizeof(type)" par la taille du type, au moins dans le cas où le type est char, je m'étais dit que ça ne changeait rien à la vitesse d'éxecution.

    En tout cas je me suis passé de ces 27 allocations en changeant un peu le programme dans divers endroit (de manière à ce qu'on ne tente pas de libérer ces caractère nul qui ne viennent plus de malloc)
    Et depuis mon problème semble être réparé.
    Ce qui m'ennuye, c'est que je n'ai pas compris pourquoi le problème était là!

    Par rapport à la troisième remarque et pour free, ma nouvelle version est devenu 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
    int mal=0;
    #define FREE(n) {\
                    if(n!=NULL){\
                         mal--;\
                         free(n);\
                         n=NULL;\
                    }else{\
                           printf("\a\nOn cherche à libérer de la mémoire déjà libérée");\
                           exit(1);\
                    }\
            }
     
    inline void *MALLOC (size_t n)
    {
       mal++;
       void* pointeur=malloc (n);
       if(pointeur==NULL){
                          printf("\a\nOn ne peut pas donner de mémoire");
                          exit(1);
       }
       return pointeur;
    }
    Et FREE n'a jamis affiché le message d'alerte.
    Par contre, pour le risque de recevoir un pointeur NULL merci de m'avoir prévenu.
    Je ne vois pas l'intéret du do{...}while(0), {....} n'aurait il pas le même effet.
    Et même si après la précompilation on a {...};, ce n'est pas grave car le point-virgule correspond simplement à l'instruction vide. Et l'on économise un test, non?


    Effectivement 'ligne' est l'adresse d'un bloc alloué.


    MAJ:
    Rectification, il y a toujours des problèmes, je ne sais d'ailleurs toujours pas pourquoi.
    Mais cette fois, la console ne se ferme pas automatiquement, j'ai:
    herbert.exe a rencontré un problème est doit fermer, etc... Le message que tout les utilisateurs de windows connaisse.
    Avant de bogger, la fonction interprete a été appellé 137 fois de l'extérieure, et comme sa profondeur par récursion est de 10 000 000, cela signifie que j'ai eu au moins 136 000 000 malloc, donc je pense encore que j'ai bien du libérer les mémoires quand il fallait, sans ça, MALLOC m'aurait affiché "On ne peut pas donner de mémoire" bien plus tôt.
    Je reste d'ailleurs perplexe, vu que je n'arrive pas à recréer simplement l'erreur, et puisque mon programme avait tourné pendant une demi heure avant de bogger, tester en tatonnant semble hors de question.

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

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par Arthur Rainbow Voir le message
    Tout d'abord merci pour la prompte réponse.
    Fred83, mon code entier faisant actuellement 824 lignes, je doute qu'il soit pertinant de le poster.
    Si c'est du code portable, tu donnes une url et c'est OK.
    Du luxe? C'est si couteux que ça une allocation?
    Oui. De plus, pour stocker un char, tu mobilises un pointeur + un char, soit 5 char sur mon architecture... Pas très rentable. Pourquoi pas ne pas allouer un tableau de 26 char directement ?
    Ma fonction interprete est récursive, et sa profondeur est de 10 000 000, avec des mallocs pour des chaînes de 10 caractères en gros.
    10 000 000 ? Tu es certain que tu as la mémoire automatique nécessaire ? Tu as essayé de compiler en mettant en œuvre la surveillance de la mémoire automatique (souvent appelée 'pile' ou 'stack').
    Pour les deux premières remarques, c'est vrai que c'est surtout une habitude que mes professeurs m'ont dit de prendre, et puisque le compilateur sait remplacer "sizeof(type)" par la taille du type, au moins dans le cas où le type est char, je m'étais dit que ça ne changeait rien à la vitesse d'éxecution.
    C'est vrai. C'est juste inutilement compliqué.

    Je ne vois pas l'intéret du do{...}while(0), {....}
    C'est la seule manière connue de simuler la syntaxe 'function-like', c'est à dire en obligeant l'utilisateur à placer un ';' après "l'appel de fonction". C'est un vieux truc de vieux routier du C... Rien de nouveau et utilisé partout...
    Pas de Wi-Fi à la maison : CPL

  6. #6
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    19
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2007
    Messages : 19
    Points : 13
    Points
    13
    Par défaut
    Citation Envoyé par Emmanuel Delahaye Voir le message
    Si c'est du code portable, tu donnes une url et c'est OK.
    http://www.milchior.fr/herbert.c
    Il s'utilise avec http://www.milchior.fr/level20.txt qui doit être placé dans un dossier nommé 3 placé dans le même dossier que herbert. (encore qu'il puisse être utilisé avec n'importe quel fichier, il suffit de changer une variable du programme).

    Ce programme est un intérpréteur de h, cf www.wildnoodle.com

    Oui. de plis, pour stocker un char, tu mobilises un pointeur + un char, soit 5 char sur mon architecture... Pas très rentable. Pourquoi pas ne pas allouer un tableau de 26 char directement ?
    Car à la fin de interprete, je libérais toutes les chaines, ce qui m'économisais des conditions.
    Mais je l'ai maintenant remplacé par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     for(i=0;i<27;i++){
      if(*fonction[i]!='\0'){
        FREE(fonction[i]);
        fonction[i]="";
    }
    et j'avais peur que le rajout de cette condition me prenne plus de temps que exécuter 27 malloc et 27 free, même si une majorité est inutile.


    10 000 000 ? Tu es certain que tu as la mémoire automatique nécessaire ?
    J'ai honte. Je me suis très mal exprimé, la fonction est de type
    f(N) si N<=0 ne rien faire, sinon x f(N-a) y f(N-b) z et l'appel est fait par f(c), où x,y,z sont des instructions, et a, b et c des chiffres entre 1 et 255.
    La fonction f est effectivement appellé 10 000 000 de fois (information connu par une variable static), mais sa profondeur est de 62.

    (Pour information, f produit des effets de bord, sinon il va de soit que je ne la lancerai pas plusieurs fois avec un même paramètre.)

    Tu as essayé de compiler en mettant en œuvre la surveillance de la mémoire automatique (souvent appelée 'pile' ou 'stack').
    Non. Je sais ce qu'est une pile, mais "surveillance de la mémoire automatique", ne me parle pas. Si il y a des moyens d'avoir des informations sur la mémoire, je serais intéressé. (C'était justement le sens de mon premier message, puisque je disais que quelque chose devait suremnet m'échapper au sujet de l'utilisation de la mémoire)

    C'est la seule manière connue de simuler la syntaxe 'function-like', c'est à dire en obligeant l'utilisateur à placer un ';' après "l'appel de fonction". C'est un vieux truc de vieux routier du C... Rien de nouveau et utilisé partout...
    Merci pour l'information. Effectivement, j'avais bien vu que ça justifiait le ;, mais pas réalisé qu'au contraire, ma méthode premettait de ne pas le mettre. Ce qui sera cause d'erreur quand je remplacerais FREE par free.

Discussions similaires

  1. [Turbo Pascal] Mon programme s'arrête tout seul
    Par kenny94 dans le forum Turbo Pascal
    Réponses: 2
    Dernier message: 10/09/2011, 07h46
  2. Arrêter mon programme si un autre s'arrête
    Par Patrick Seuret dans le forum C++Builder
    Réponses: 3
    Dernier message: 24/04/2010, 00h48
  3. Réponses: 3
    Dernier message: 27/04/2007, 19h39
  4. Mon programme empêche l'arrêt de Windows
    Par forzalec dans le forum C++Builder
    Réponses: 4
    Dernier message: 16/11/2006, 14h27
  5. Réponses: 4
    Dernier message: 13/08/2005, 10h20

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