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 :

[CodeBlocks - Ubuntu 8.10] Bug à l'exécution en mode "Release"


Sujet :

C

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 5
    Points : 2
    Points
    2
    Par défaut [CodeBlocks - Ubuntu 8.10] Bug à l'exécution en mode "Release"
    Bonjour,

    dans le cadre de plusieurs projets, afin de faciliter l'implémentation de certaines données on a eu l'idée d'utiliser une structure de données de type HashTable. Vu que la bibliothèque standard du langage C ne propose rien de tel, j'ai commencé à coder une HashTable générique. Ce qui a été commencé est fourni en pièces jointes :
    Code main.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
    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
     
    #include <stdio.h>
    #include <stdlib.h>
    #include "HashTable.h"
     
    struct personne {
        char* nom;
        char* prenom;
    };
     
    int main()
    {
        HashTable dico = NULL;
     
        int nb = 47;
        long nb2 = 5432424;
        double reel = 4.5789;
        struct personne chuck;
     
        chuck.nom = "Norris";
        chuck.prenom = "Chuck";
     
        dico = new_HashTable("Test1", "Ceci est une chaine", sizeof("Ceci est une chaine"));
        addEntry(dico, "Entier", &nb, sizeof(int));
        addEntry(dico, "Reel", &reel, sizeof(double));
        addEntry(dico, "Entier long", &nb2, sizeof(long));
        addEntry(dico, "Structure", &chuck, sizeof(struct personne));
     
        printf("Clef : %s - Valeur : %s\n", dico->key, (char*)dico->value);
     
        dico = dico->next;
     
        printf("Clef : %s - Valeur : %d\n", dico->key, *(int*)dico->value);
     
        dico = dico->next;
     
        printf("Clef : %s - Valeur : %f\n", dico->key, *(double*)dico->value);
     
        dico = dico->next;
     
        printf("Clef : %s - Valeur : %ld\n", dico->key, *(long*)dico->value);
     
        dico = dico->next;
     
        printf("Clef : %s - Valeur : %s %s\n", dico->key, ((struct personne*)dico->value)->prenom, ((struct personne*)dico->value)->nom);
     
        return 0;
    }
    Code HastTable.h : 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
     
    #ifndef HASHTABLE_H_INCLUDED
    #define HASHTABLE_H_INCLUDED
     
    struct keyvalue {
        char* key;
        void* value;
        size_t size;
        struct keyvalue* next;
    };
     
    typedef struct keyvalue* HashTable;
     
    HashTable new_HashTable(char* key, void* value, size_t size);
     
    int addEntry(HashTable hashtable, char* key, void* value, size_t size);
     
    #endif // HASHTABLE_H_INCLUDED
    Code HashTable.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
    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
    81
    82
    83
    84
    85
    86
    87
    88
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "HashTable.h"
     
    /* Constructeur d'une HashTable
       But        : Permet d'instancier un dictionnaire
       Paramètres : clef [char*], associé [void*], taille de l'associé [size_t] (Généralement sizeof(associe))
       Retour     : Dictionnaire nouvellement créé
    */
    HashTable new_HashTable(char* key, void* value, size_t size){
     
        // Vérifier la conformité des paramètres formels
        if (key == NULL || value == NULL || size <= 0)
            return NULL;
     
        // Allouer dynamiquement et créer des copies de la clef
        // et de l'associé
        char* newKey = (char*)malloc(sizeof(key));
        void* newValue = malloc(size);
     
        if (newKey == NULL || newValue == NULL)
            return NULL;
     
        strcpy(newKey, key);
        memcpy(newValue, value, size);
     
        // Créer un nouveau dictionnaire
        HashTable newHashTable = (HashTable)malloc(sizeof(struct keyvalue));
     
        if (newHashTable == NULL)
            return NULL;
     
        newHashTable->key = newKey;
        newHashTable->value = newValue;
        newHashTable->size = size;
        newHashTable->next = NULL;
     
        return newHashTable;
    }
     
    /* Fonction addEntry
       But        : Ajouter une nouvelle entrée au dictionnaire passé en paramètre
       Paramètres : dictionnaire [HashTable], clef [char*], associé [void*], taille de l'associé [size_t] (Généralement sizeof(associe))
       Retour     : 1 si tout s'est bien déroulé, 0 sinon
    */
     
    int addEntry(HashTable hashtable, char* key, void* value, size_t size){
     
        // Vérifier la conformité des paramètres formels
        if (hashtable == NULL || key == NULL || value == NULL || size <= 0)
            return 0;
     
        // Créer une copie du dictionnaire et accéder au dernier
        // élément du dictionnaire
        HashTable copy = hashtable;
     
        while (copy->next != NULL)
            copy = copy->next;
     
        // Allouer dynamiquement et créer des copies de la clef
        // et de l'associé
        char* newKey = (char*)malloc(sizeof(key));
        void* newValue = malloc(size);
     
        if (newKey == NULL || newValue == NULL)
            return 0;
     
        strcpy(newKey, key);
        memcpy(newValue, value, size);
     
        // Créer une nouvelle entrée dans le dictionnaire
        struct keyvalue* newKeyvalue = (struct keyvalue*)malloc(sizeof(struct keyvalue));
     
        if (newKeyvalue == NULL)
            return 0;
     
        newKeyvalue->key = newKey;
        newKeyvalue->value = newValue;
        newKeyvalue->size = size;
        newKeyvalue->next = NULL;
     
        // Ajouter l'entrée au dictionnaire
        copy->next = newKeyvalue;
     
        return 1;
    }

    Je compile donc le code en "Debug" sous CodeBlocks sous Ubuntu 8.10 (Compilateur gcc), tout se passe bien :

    Clef : Test1 - Valeur : Ceci est une chaine
    Clef : Entier - Valeur : 47
    Clef : Reel - Valeur : 4.578900
    Clef : Entier long - Valeur : 5432424
    Clef : Structure - Valeur : Chuck Norris
    pourtant quand je compile en "Release", j'ai plein d'erreurs qui s'affichent à l'exécution (en l'occurrence un buffer overflow) :



    J'essaie aussi de compiler "à la main" avec gcc, pas d'erreur apparente :

    erosquare@mvk-desktop:~/Documents/HashTable$ gcc *.c -I . -o test
    erosquare@mvk-desktop:~/Documents/HashTable$ ./test
    Clef : Test1 - Valeur : Ceci est une chaine
    Clef : Entier - Valeur : 47
    Clef : Reel - Valeur : 4.578900
    Clef : Entier long - Valeur : 5432424
    Clef : Structure - Valeur : Chuck Norris
    erosquare@mvk-desktop:~/Documents/HashTable$
    Quelqu'un saurait d'où pourrait venir ce "bug" svp? Merci d'avance.

  2. #2
    Membre éprouvé Avatar de orfix
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    707
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2007
    Messages : 707
    Points : 1 132
    Points
    1 132
    Par défaut
    Salut,

    Je ne vois aucun free ...c'est normal ?
    Je n'ai pas tout regarder, mais quand tu écrits :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    char* newKey = malloc(sizeof(key));
    <...>
    strcpy(newKey, key);
    sais-tu que sizeof retourneras la taille de key un pointeur sur char qui dans les arcitectures 32bit est égale à 4 ?

    EDIT : Essaie de mettre ton code entre les balises
    To start press any key. (reading screen) Where's the "any" key? I see Esc, Catarl, and Pig Up. There doesn't seem to be any "any" key. Wo! All this computer hacking is making me thirsty. I think I'll order a Tab. (presses TAB key). -- HOMER --

  3. #3
    Candidat au Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    Pour les free c'est normal, comme je l'ai précisé je viens de commencer à coder ce TAD. J'ai juste fait une fonction permettant d'instancier l'HashTable et une fonction addEntry pour ajouter une entrée, je n'ai pas encore codé les fonctions permettant de libérer la mémoire. Quand je fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    char* newKey = (char*)malloc(sizeof(key));
    <...>
    strcpy(newKey, key);
    Je veux allouer autant d'octets dans la mémoire que key en contient. Vois ça comme :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char* newKey = (char*)malloc((strlen(key) + 1) * sizeof char);

  4. #4
    Membre éclairé Avatar de crocodilex
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    697
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 697
    Points : 858
    Points
    858
    Par défaut
    Essayes d'ajouter ça dans ton code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    printf("SIZE OF KEY = %d\n", sizeof(key));
    Tu risques d'être surpris...
    Software Failure. Press left mouse button to continue.
    Guru Meditation #0100000C.000FE800

  5. #5
    Candidat au Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    En effet, j'ai recompilé le code en effectuant quelques modifications dans le code, à savoir :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    char* newKey = (char*)malloc((strlen(key)+1) * sizeof(char));
    memcpy(newKey, key, (strlen(key)+1)*sizeof(char));
    Tout en mettant dans le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    printf("SIZE OF KEY = %d\n", sizeof(key));
    printf("SIZE OF KEY = %d\n", (strlen(key)+1)*sizeof(char));
    Et le code s'exécute parfaitement maintenant en mode "Release" :

    erosquare@mvk-desktop:~/Documents/HashTable/bin/Release$ ./HashTable
    SIZE OF KEY = 4
    SIZE OF KEY = 6
    Clef : Test1 - Valeur : Ceci est une chaine
    Clef : Entier - Valeur : 47
    Clef : Reel - Valeur : 4.578900
    Clef : Entier long - Valeur : 5432424
    Clef : Structure - Valeur : Chuck Norris
    J'étais persuadé que sizeof(key) me donnerait la même chose que strlen(key)+1) * sizeof(char). Enfin bref, merci beaucoup de votre efficacité

  6. #6
    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 : 61
    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
    Points : 50 367
    Points
    50 367
    Par défaut
    Juste une info,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    char* newKey = (char*)malloc((strlen(key)+1) * sizeof(char));
    memcpy(newKey, key, (strlen(key)+1)*sizeof(char));
    peut se remplacer par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char* newKey = strdup(key);
    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
    .

  7. #7
    Candidat au Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    Je ne connaissais pas strdup et effectivement c'est très utile, merci beaucoup.

  8. #8
    Expert éminent sénior
    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
    Points : 13 926
    Points
    13 926
    Par défaut
    J'étais persuadé que sizeof(key) me donnerait la même chose que strlen(key)+1) * sizeof(char).
    Il faut quand même comprendre pourquoi :
    sizeof donne la taille en byte de l'opérande (ou d'un objet du même type que l'opérande). key étant un pointeur sur char,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ....new_HashTable(char* key, ......)
    il donnera la taille d'un pointeur sur char, ce qui n'a rien à voir avec la taille d'un tableau dont l'adresse serait key.

    En règle générale, une fonction n'a comme seuls moyens pour connaître la taille d'un tableau
    - qu'on la lui indique en argument
    - ou que le tableau soit constitué de telle façon que sa taille puisse se déduire de son contenu (cas des chaînes de caractères en C par la présence du zéro terminal, ce que détecte la fonction strlen())

    Dans la fonction new_HashTable, il reste du travail à faire pour gérer correctement les erreurs d'allocation.
    Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        if (newKey == NULL || newValue == NULL)
            return NULL;
    Et si l'un des deux n'est pas NULL, comment récupérer la mémoire allouée ?
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  9. #9
    Candidat au Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    Ah oui, je n'avais pensé à ce cas en effet. Ca pourrait conduire à une fuite de mémoire si l'un des deux n'était pas libéré de la mémoire qu'il occupe, merci

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

Discussions similaires

  1. [Ubuntu 11.04] Bug interface graphique
    Par derek corhs dans le forum Ubuntu
    Réponses: 27
    Dernier message: 30/09/2011, 17h11
  2. Bug à l'exécution d'un programme VB6
    Par tibes dans le forum VB 6 et antérieur
    Réponses: 1
    Dernier message: 22/06/2010, 21h27
  3. Codeblocks Ubuntu 6.10 64 bit
    Par Korak dans le forum Linux
    Réponses: 5
    Dernier message: 26/11/2006, 15h37
  4. [Dev-cpp]bug à l'exécution
    Par lex_2005 dans le forum C
    Réponses: 3
    Dernier message: 08/01/2006, 23h22

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