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 :

Erreur de segmentation lors de manipulation de chaine


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    56
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 56
    Par défaut Erreur de segmentation lors de manipulation de chaine
    Bonjour,

    Je suis en train de passez au C sans trop de soucis. actuellement j'ai réussi a retranscrire une partie d'un vieux programme pascal (lazarus) sans trop de soucis.

    Mais j'ai une erreur de segmentation sur une partie de mon programme. que j'ai réussi a isoler. Voici le code en question.


    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
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
     
     
     
    int main(void) {
        int k = 3;
        int lg;
        char *img = "";
        char *tmp = "";
        sprintf(tmp, "%d", k);
        lg=strlen(tmp);
        switch (lg)
        {
            case 1 : sprintf(img,"000000%s",tmp);
            break;
            case 2 : sprintf(img,"00000%s",tmp);
            break;
            case 3 : sprintf(img,"0000%s",tmp);
            break;
            case 4 : sprintf(img,"000%s",tmp);
            break;
            case 5 : sprintf(img,"00%s",tmp);
            break;
            case 6 : sprintf(img,"0%s",tmp);
            break;
            case 7 : img = tmp;
            break;        
        }
        printf("nombre %s ",img);
    }
    J'ai donc tenter de le compiler avec les options suivantes et le debugger avec GDB. Voici les commande utiliser

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    gcc -g test.c -o test
    gdb test
    le résultat donne ceci. On retrouve bien l'erreur mais une autre aussi !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    Program received signal SIGSEGV, Segmentation fault.
    0xb7e80464 in __GI__IO_default_xsputn (f=0xbfffed80, data=0xbfffed3f, n=1) at genops.c:475
    475     genops.c: Aucun fichier ou dossier de ce type.
    Je travail sous ubuntu 14.04.
    Je suis débutant en C. Il y a t il une erreur de débutant que je ne vois pas ??

    Merci de votre aide

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 835
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par christophe D Voir le message
    Je suis débutant en C. Il y a t il une erreur de débutant que je ne vois pas ??
    Bonjour

    Oui, une grosse erreur
    Déjà quand tu écris char *tmp="" tu affectes au pointeur tmp l'adresse d'une chaine statique "", laquelle est invariante. Tu ne peux tonc pas ensuite y mettre quoi que ce soit comme avec ton sprintf().

    Ensuite, quand on remplit une zone mémoire, il faut alors que la zone ait la place pour recevoir ce qu'on y met. Et ça il me semble que c'est pareil en Pascal. Donc soit tmp est un tableau d'une taille définie à l'avance, soit tmp devra recevoir l'adresse que renvoie la fonction malloc(), fonction allouant en live x octets de mémoire (à toi de définir "x" qui est généralement un nombre qu'on ne connait pas au départ sinon vaut mieux le cas n° 1). Dans ce cas, tu ne devras jamais perdre cette adresse et la libérer via free() quand tu n'en as plus besoin. C'est une notion qui est généralement un peu au dessus du niveau de "débutant" car elle nécessite la connaissance des pointeurs.

    Donc si c'est juste pour t'amuser tu peux écrire char tmp[20] et char img[20] et ton code fonctionnera (20 chiffres pour un nombre je pense que c'est suffisant). Si ensuite tu veux écrire un code plus robuste, tu devras alors te livrer à un savant calcul pour découvrir la taille max de tmp et img puis écrire char *tmp puis tmp=malloc((taille_max + 1) * sizeof(char)) et pareil pour img. Et en fin de code tu devras écrire free(tmp) et pareil pour img.
    Et pourquoi ce "+1" ? Pour laisser aussi la place au '\0' qui termine systémétiquement toute chaine. D'ailleurs, pour vraiment bien faire, tu devrais alors écrire char tmp[20 + 1] et char img[20 + 1] pour bien montrer aux lecteurs de ton code (voire à toi-même quand tu te reliras dans 6 mois) que t'as bien pensé à ce '\0'....
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Modérateur

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

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    Bonjour,

    Tu devrais rajouter les options -Wall et -Wextra lors de l'appel à gcc. Tu auras plus de warnings générés et détecteras plus de potentiels bugs.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        char *tmp = "";
        sprintf(tmp, "%d", k);
    Tu ne peux pas faire ça. Pour deux raisons :

    1) La première émet un warning normalement :
    initialization discards 'const' qualifier from pointer target type [enabled by default]
    La chaine "" est placée en mémoire constante et tu ne peux donc pas écrire à l'emplacement pointé par tmp. Ainsi, lors de ton appel à sprintf(), tu obtiens probablement l'erreur de segmentation car il n'est pas possible d'ecrire à cet emplacement.

    2) Tu ne réserves pas de place en faisant ça : juste un caractère pour stocker le caractère de fin de chaine. Or, en voulant écrire 3, tu as besoin de 2 caractères (3 et \0). Donc ton espace est trop petit. Cela peut aussi causer des erreurs (mais le cas 1 est sans doute bloquant en premier). Ces erreurs peuvent être plus vicieuses car tu n'auras peut-être pas d'erreur de segmentation brutale et visible, mais plutôt des écrasements des données adjacentes en mémoire.

    EDIT : devancé par Sve@r !

  4. #4
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 835
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Bktero Voir le message
    EDIT : devancé par Sve@r !
    De tellement longtemps qu'on se demande si tu dormais

    Citation Envoyé par Bktero Voir le message
    La chaine "" est placée en mémoire constante et tu ne peux donc pas écrire à l'emplacement pointé par tmp.
    Je réfléchissais justerment à ce sujet et me demandais si écrire char *tmp="bonjour" puis tmp[0]='x' n'était pas quand-même autorisé... Bah, je testerai tout à l'heure...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    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
    Citation Envoyé par Sve@r Voir le message
    Je réfléchissais justerment à ce sujet et me demandais si écrire char *tmp="bonjour" puis tmp[0]='x' n'était pas quand-même autorisé... Bah, je testerai tout à l'heure...
    Quel que soit le résultat du test, ce n'est pas autorisé :
    Citation Envoyé par n1256
    6.4.5 String literals
    ...
    6 It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.

  6. #6
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Le pire, c'est que (à moins que ça ait changé dans une version récente de gcc) -Wall -Wextra n'inclut pas -Wwrite-strings, il faut le rajouter manuellement.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    56
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 56
    Par défaut
    Merci à tous pour vos commentaires.

    Je vais laisser de coté pour le moment les pointeurs, je me pencherais plus tard dessus.
    Enfin de compte je sais la longueur maximal de la chaîne stocker.

    Donc ceci est correct. Je défini la taille de la chaîne stocker à 10 caractères .

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    char img[10];
    char tmp[10];
    par contre ceci retourne une erreur.
    que j'ai donc remplacer par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    sprintf(img,"%s",tmp);

    donc pour ceux que cela intéresse le code corrigé .
    C'est une partie de mon code pour numéroter des images.
    Je sais pas si c'est bien propre. Mais c'est fonctionnel.

    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
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
     
     
     
    int main(void) {
        int k = 3;
        int lg;
        char img[10];
        char tmp[10];
        sprintf(tmp, "%d", k);
        lg=strlen(tmp);
        switch (lg)
        {
            case 1 : sprintf(img,"000000%s",tmp);
            break;
            case 2 : sprintf(img,"00000%s",tmp);
            break;
            case 3 : sprintf(img,"0000%s",tmp);
            break;
            case 4 : sprintf(img,"000%s",tmp);
            break;
            case 5 : sprintf(img,"00%s",tmp);
            break;
            case 6 : sprintf(img,"0%s",tmp);
            break;
            case 7 : sprintf(img,"%s",tmp);
            break;        
        }
        printf("nombre %s ",img);
        return 0;
    }
    PS : en pascal il y a pas vraiment de contrainte dans les variable chaîne. Mais je retrouve la "problématique" quand on créer une base de donnée.

    Merci encore de votre patience.

  8. #8
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    sprintf() est plus évoluée que ça. Un appel à sprintf(buffer, %08d, valeur) écrira la valeur sur huit chiffres alignés à droite, en comblant avec des zéros si nécessaire.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  9. #9
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 835
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par christophe D Voir le message
    Donc ceci est correct. Je défini la taille de la chaîne stocker à 10 caractères .

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    char img[10];
    char tmp[10];
    10 caractères oui mais as-tu pensé au '\0' ???

    Citation Envoyé par christophe D Voir le message
    par contre ceci retourne une erreur.
    Normal, le C n'est pas assez évolué pour savoir recopier des tableaux de cette façon. C'est à toi de les copier caractère par caractère... ou bien d'appeler la fonction memcpy() faite pour ça...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

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

Discussions similaires

  1. Réponses: 11
    Dernier message: 29/11/2011, 14h15
  2. Erreur de segmentation lors de la compilation
    Par touzack dans le forum Débuter
    Réponses: 2
    Dernier message: 21/07/2010, 12h17
  3. Réponses: 7
    Dernier message: 12/05/2010, 15h33
  4. Erreur de segmentation lors du rafraichissement d'un ListStore
    Par Difool dans le forum GTK+ avec Python
    Réponses: 1
    Dernier message: 23/02/2010, 16h09
  5. Réponses: 1
    Dernier message: 22/03/2009, 19h44

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