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 dans strtol


Sujet :

C

  1. #1
    Candidat au Club
    Inscrit en
    Novembre 2011
    Messages
    3
    Détails du profil
    Informations forums :
    Inscription : Novembre 2011
    Messages : 3
    Points : 2
    Points
    2
    Par défaut Erreur de segmentation dans strtol
    Bonjour,

    J'ai une erreur de segmentation que je n'arrive pas à comprendre. Mon code est le suivant

    Code Erreur de segmentation : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <stdio.h>
    #include <stdlib.h>
     
    int main(int argc, char *argv[])
    {
      int n;                
      char **endp;
     
      n = (int) strtol(argv[1], endp, 10);
     
      printf("%d \t %d \t %d \n", n, 4, 4);
     
      return 0;
    }

    Quand je compile ce code avec gcc puis que je l'exécute par exemple avec ./main 4 si main est le nom de mon programme compilé, j'obtiens une erreur de segmentation. Voici le rapport de valgrind :

    Code Valgrind : 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
    ==9888== Memcheck, a memory error detector
    ==9888== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
    ==9888== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
    ==9888== Command: ./main 4
    ==9888==
    ==9888== Conditional jump or move depends on uninitialised value(s)
    ==9888==    at 0x4077A42: ____strtol_l_internal (strtol_l.c:489)
    ==9888==    by 0x407761F: strtol (strtol.c:110)
    ==9888==    by 0x804841C: main (in /home/tlaffarg/Documents/Simulations/A/main)
    ==9888==
    ==9888== Use of uninitialised value of size 4
    ==9888==    at 0x4077A47: ____strtol_l_internal (strtol_l.c:490)
    ==9888==    by 0x407761F: strtol (strtol.c:110)
    ==9888==    by 0x804841C: main (in /home/tlaffarg/Documents/Simulations/A/main)
    ==9888==
    ==9888==
    ==9888== Process terminating with default action of signal 11 (SIGSEGV)
    ==9888==  Bad permissions for mapped region at address 0x4188FF4
    ==9888==    at 0x4077A47: ____strtol_l_internal (strtol_l.c:490)
    ==9888==    by 0x407761F: strtol (strtol.c:110)
    ==9888==    by 0x804841C: main (in /home/tlaffarg/Documents/Simulations/A/main)
    ==9888==
    ==9888== HEAP SUMMARY:
    ==9888==     in use at exit: 0 bytes in 0 blocks
    ==9888==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
    ==9888==
    ==9888== All heap blocks were freed -- no leaks are possible
    ==9888==
    ==9888== For counts of detected and suppressed errors, rerun with: -v
    ==9888== Use --track-origins=yes to see where uninitialised values come from
    ==9888== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 12 from 7)

    Ce qui m'étonne particulièrement est que les trois codes sources suivant, qui viennent du précédent légèrement modifié, fonctionnent :

    Code Afficher un 4 en moins : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <stdio.h>
    #include <stdlib.h>
     
    int main(int argc, char *argv[])
    {
      int n;                
      char **endp;               // Buffer used to read the input variables
     
      n = (int) strtol(argv[1], endp, 10);
     
      printf("%d \t %d \n", n, 4);
     
      return 0;
    }


    Code Ne pas rentrer l'entrée depuis l'extérieur du programme : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <stdio.h>
    #include <stdlib.h>
     
    int main(int argc, char *argv[])
    {
      int n;                
      char **endp;               // Buffer used to read the input variables
     
      n = 4;
     
      printf("%d \t %d \t %d \n", n, 4, 4);
     
      return 0;
    }


    Code Utiliser &endp sur *endp au lieu de endp sur **endp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <stdio.h>
    #include <stdlib.h>
     
    int main(int argc, char *argv[])
    {
      int n;                
      char *endp;
     
      n = (int) strtol(argv[1], &endp, 10);
     
      printf("%d \t %d \t %d \n", n, 4, 4);
     
      return 0;
    }

    Quelqu'un pourrait-il m'expliquer ce qui ne va pas dans le premier code?

    Merci d'avance!

  2. #2
    Membre émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

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

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Points : 2 505
    Points
    2 505
    Par défaut
    Il faut déclarer "char *endp", puis passer "&endp" à strtol.

    Edit : je n'avais pas vu le suite de ton message. Pour l'explication, sache que si strtol est défini de la façon suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    long int strtol(const char *nptr, char **endptr, int base) {
    ...
    }
    alors strtol va écrire dans *endptr, comme ceci :
    Donc, si tu déclares "char **endp" et que tu passes endp à strtol, alors strtol va écrire à l'adresse contenue dans endp... Qui n'est pas initialisée. Donc segfault.

    Par contre, si tu déclares "char *endp" et que tu passes &endp à strtol, alors strtol va écrire à l'adresse qui est passée, c'est à dire l'adresse de endp. Donc ca modifie endp.

  3. #3
    Candidat au Club
    Inscrit en
    Novembre 2011
    Messages
    3
    Détails du profil
    Informations forums :
    Inscription : Novembre 2011
    Messages : 3
    Points : 2
    Points
    2
    Par défaut
    C'est bien ce que j'ai fait dans le quatrième code. Mais pourquoi le premier n'est-il pas correct? Surtout que cela marche dans les codes 2 et 3.

  4. #4
    Membre émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

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

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Points : 2 505
    Points
    2 505
    Par défaut
    Le code 2 n'est pas correct. Il fonctionne parce que tu as de la "chance", mais strtol va stocker son endptr à un endroit où tu n'es pas sensé écrire.

  5. #5
    Candidat au Club
    Inscrit en
    Novembre 2011
    Messages
    3
    Détails du profil
    Informations forums :
    Inscription : Novembre 2011
    Messages : 3
    Points : 2
    Points
    2
    Par défaut
    Je n'avais pas vu l'edit avant de répondre. Merci beaucoup pour la réponse détaillée!

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

Discussions similaires

  1. erreur de segmentation dans jeu en C/SDL
    Par talonneur56 dans le forum C
    Réponses: 12
    Dernier message: 09/11/2011, 21h06
  2. Réponses: 1
    Dernier message: 14/05/2010, 08h00
  3. Réponses: 1
    Dernier message: 21/10/2009, 10h36
  4. Réponses: 1
    Dernier message: 11/03/2009, 15h09
  5. Erreur de segmentation dans un thread
    Par Littlepea dans le forum wxWidgets
    Réponses: 3
    Dernier message: 27/06/2008, 19h18

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