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


Sujet :

C

  1. #1
    Inactif   Avatar de Deallyra
    Profil pro
    Étudiant
    Inscrit en
    Février 2007
    Messages
    1 997
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2007
    Messages : 1 997
    Par défaut Erreur de segmentation
    Bonjour,

    J'ai un code simple comme suit :
    Code 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
     
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <time.h>
    #include <ctype.h>
     
    int main (int argc, char **argv){
    	if(argc != 3){
    		printf("%d",argc);
    		printf("Please, relauch program with the length of the two words\n");
    		return 1;
    	}
      else{
        char alphabet[28] = " abcdefghijklmnopqrstuvwxyz";
        srand(time(NULL));
    			int integer;
    			int i;
     
    		// For the first word
        int lengthFirstWord = atoi(argv[1]);
    		char firstWord[lengthFirstWord];
        	for (i = 0; i < lengthFirstWord; i++){
    				integer = rand() % (26) + 1;
    				firstWord[i] = alphabet[integer];
    			}
    			firstWord[i] = '\0';
     
    		// For the second word
        int lengthSecondWord = atoi(argv[2]);
        char secondWord[lengthSecondWord];
    			for (i = 0; i < lengthSecondWord; i++){
    				integer = rand() % (26) + 1;
    				secondWord[i] = alphabet[integer];
    			}
    			secondWord[i] = '\0';
     
        printf("\nWords :");
        printf("\n\t%s\n\t%s\n\n",firstWord, secondWord);
      	return 0;
      }
    }

    Ce code sert à générer deux mots dont la taille est passée en paramètres.
    Ce programme sert à alimenter un programme de comparaisons de chaînes de caractères pour tester la complexité réelle de trois algos...
    Bref, toujours est-il que je dois laisser tourner les algos au plus 5 minutes.

    Mais j'ai l'impression qu'une erreur de mon code ci dessus se répercute ensuite dans le programme qui sera lancé en dépendance.
    Je ne peux générer que des mots plus courts... Et pour le premier algo qui est très rapide, j'atteins rapidement la limite.

    ___

    Si vous exécutez le code ci dessus, vous verrez qu'il compile bien...
    Et qu'il se lance sans problème jusqu'à une certaine limite !

    deallyra@deal:/media/Lapinator/Complexite/_Sources/sandbox$ time ./sandbox 5238806 5238806
    -- il va me générer correctement les deux mots
    deallyra@deal:/media/Lapinator/Complexite/_Sources/sandbox$ time ./sandbox 5238807 5238807
    Erreur de segmentation

    real 0m0.285s
    user 0m0.252s
    sys 0m0.004s
    Enfin les bornes "varient".

    En ce qui me concerne, je me demande si c'est une erreur de code (probabilité 4/5) ou alors une limite de la machine (3/5)

    Qu'en pensez vous ?
    Comment changeriez vous ce code ?

    Merci à vous

    PS : ce post est un élément de réponse qui me permettra de répondre à un autre posé antérieurement...
    Oui, je suis toujours sur ce problème -_-"
    *Si la réponse vous convient, n'oubliez pas le tag
    *Exprimez vous dans un français correct; on prend le temps de vous lire, prenez le temps de bien écrire.
    *Et comment on interprète votre code? N'oubliez pas la balise!

    *Pour une mise en page simple avec des divs.
    *Pour faire des formulaires xHTML CSS.

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    107
    Détails du profil
    Informations personnelles :
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Avril 2006
    Messages : 107
    Par défaut
    Bonjour,

    avec Tu écris en dehors de ton tableau firstWord, car i=lengthFirstWord.
    Pareil pour le second mot !

    Sinon avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    integer = rand() % (26) + 1;
    				firstWord[i] = alphabet[integer];
    tu n'auras jamais la lettre espace puisque integer ne peut pas valoir 0.
    [edit :] D'ailleurs, integer vaudra au maximum 26, et tu n'auras donc pas non plus la lettre z [edit]

  3. #3
    Inactif   Avatar de Deallyra
    Profil pro
    Étudiant
    Inscrit en
    Février 2007
    Messages
    1 997
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2007
    Messages : 1 997
    Par défaut
    Pour le coup de la taille du tableau, mea culpa.

    A la base, c'est pas un seul morceau de code comme celui ci mais une mini librairie de fonction que j'ai fait...
    Et en recollant tous les morceaux me suis trompée...

    J'ai corrigé mon message en conséquence.

    Malgré cette faute de recopie, ce n'était pas l'origine de mon problème (sur mes autres sources c'était bon)
    J'ai toujours ce problème de segmentation

    (pour l'espace, c'est normal que je ne puisse pas l'avoir. J'ai juste rajouté un espace afin de pouvoir -fonction de ma librairie- récupérer une lettre en fonction de sa position ou en fonction d'une position récupérer la lettre.
    Par contre, bien vu pour le Z )
    *Si la réponse vous convient, n'oubliez pas le tag
    *Exprimez vous dans un français correct; on prend le temps de vous lire, prenez le temps de bien écrire.
    *Et comment on interprète votre code? N'oubliez pas la balise!

    *Pour une mise en page simple avec des divs.
    *Pour faire des formulaires xHTML CSS.

  4. #4
    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
    Mais as-tu corrigé les erreurs signalées par apesle :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    firstWord[i] = '\0';
    //et
    secondWord[i] = '\0';
    en modifiant la taille des tableaux ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    char firstWord[lengthFirstWord+1];
    char secondWord[lengthSecondWord+1];

  5. #5
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 485
    Par défaut
    Ta segfault est probablement, en réalité, un stack overflow. Il n'y a pas de message particulier car, à ce niveau (compilé en langage machine), il n'y a rien qui nous permette d'affirmer que l'accès mémoire effectué au delà de la mémoire allouée au processus était censé l'être dans la pile plutôt qu'ailleurs. C'est un MOV qui a été fait en utilisant le registre de pile comme index, mais pas un PUSH, POP ou autre instruction réputée travailler directement sur la pile.

    Tu n'obtiens pas non plus de message à la compilation parce que la taille de la pile est définie par le système, et à l'exécution.

    En l'occurence, 5238806 + 5238806 ÷ 1024 = 10232 kibi-octets, et sur mon système (Linux 32 bits), la taille de ma pile est fixée à :

    … seulement 8192 kilo-octets.

    Essaie ulimit -s 16384 par exemple, ça devrait te permettre d'aller plus loin. Veille toutefois à ne pas dépasser une trop grande taille pour ta pile, si tu dois utiliser ce programme fréquemment ou si tu dois en lancer plusieurs instances. L'utilisation de malloc() est plus propre pour les allocations de grands espaces.

  6. #6
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    107
    Détails du profil
    Informations personnelles :
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Avril 2006
    Messages : 107
    Par défaut
    Je pense qu'il te faut utiliser l'allocation dynamique pour tes tableaux de caractères.
    Là ils sont en statiques : tu demandes donc 2* 5238807 octets soit environ 10,4Mo ce qui doit exploser la pile.

    Le code suivant fonctionne correctement sur mon pc, avec de très grandes valeurs : ./sandbox 523880700 523880700

    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
    #include <stdlib.h>
    #include <stdio.h>
    #include <assert.h>
    #include <string.h>
     
    int main (int argc, char **argv){
    	if(argc != 3){
    		printf("%d",argc);
    		printf("Please, relauch program with the length of the two words\n");
    		return 1;
    	}
      else{
        	char alphabet[] = " abcdefghijklmnopqrstuvwxyz";
        	unsigned int lengthFirstWord;
    	unsigned char integer;
    	unsigned int i;
    	srand(time(NULL));
     
    		/* For the first word*/
        		lengthFirstWord = atoi(argv[1]);
        		printf("atoi(argv[1]) = %u\n", lengthFirstWord );
    		char *firstWord = malloc( lengthFirstWord+1 );
    		/* verifier mieux le malloc*/assert(firstWord);
     
        		for (i = 0; i < lengthFirstWord; i++){
    				integer = rand() % (26) + 1;
    				*(firstWord+i) = alphabet[integer];
    			}
    			firstWord[i] = '\0';
    		printf("i = %u, strlen(firstword) = %u\n", i, strlen(firstWord) );
     
     
        free( firstWord );
     
      	return 0;
      }
    }
    PS : il faut bien faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     integer = rand() % (26) + 1;
    car cela implique integer inclut dans [1; 26] et acceder à alphabet[26] correspond à la 27ieme case, soit Z. Désolé.

  7. #7
    Inactif   Avatar de Deallyra
    Profil pro
    Étudiant
    Inscrit en
    Février 2007
    Messages
    1 997
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2007
    Messages : 1 997
    Par défaut
    Merci à tous pour votre aide,

    Citation Envoyé par diogene Voir le message
    Mais as-tu corrigé les erreurs signalées par apesle :
    en modifiant la taille des tableaux ?
    Oui Diogene. En fait, c'est un problème que j'ai depuis quelques jours et cet après midi j'ai refait la source pour voir si je n'avais pas oublié un truc... Et c'est là que je me suis trompée.
    Ca a été corrigé

    Citation Envoyé par Obsidian Voir le message
    Essaie ulimit -s 16384 par exemple, ça devrait te permettre d'aller plus loin. Veille toutefois à ne pas dépasser une trop grande taille pour ta pile, si tu dois utiliser ce programme fréquemment ou si tu dois en lancer plusieurs instances. L'utilisation de malloc() est plus propre pour les allocations de grands espaces.
    La taille de la pile semble être la même pour tout le monde si l'on a pas fait de changement dessus... puisque j'obtiens égalmeent 8192 avec un ulimit -s

    Par rapport au malloc, ce serait allouer un espace de plus à chaque passage de la boucle ?
    edit : réponse donnée par apesle dans son exemple

    Citation Envoyé par apesle Voir le message
    Je pense qu'il te faut utiliser l'allocation dynamique pour tes tableaux de caractères.
    Là ils sont en statiques : tu demandes donc 2* 5238807 octets soit environ 10,4Mo ce qui doit exploser la pile.

    Le code suivant fonctionne correctement sur mon pc, avec de très grandes valeurs : ./sandbox 523880700 523880700
    J'avais fait le test, lorsque je ne génère qu'un mot, il peut être beaucoup plus grand que si j'en fais deux.
    Cependant, je suis en dessous de ce que tu produis (peut être de part tes unsigned)
    _________
    Paissad vient de me faire découvrir gdb.
    Et j'obtiens ceci :
    (gdb) run 9999999 9999999
    Starting program: /media/Lapinator/Complexite/_Sources/sandbox/sandbox 9999999 9999999

    Program received signal SIGSEGV, Segmentation fault.
    main (argc=<value optimized out>, argv=<value optimized out>) at sandbox.c:32
    32 integer = rand() % (26) + 1;
    *Si la réponse vous convient, n'oubliez pas le tag
    *Exprimez vous dans un français correct; on prend le temps de vous lire, prenez le temps de bien écrire.
    *Et comment on interprète votre code? N'oubliez pas la balise!

    *Pour une mise en page simple avec des divs.
    *Pour faire des formulaires xHTML CSS.

  8. #8
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 485
    Par défaut
    Citation Envoyé par Deallyra Voir le message
    La taille de la pile semble être la même pour tout le monde si l'on a pas fait de changement dessus... puisque j'obtiens égalmeent 8192 avec un ulimit -s
    Si tu passes un argument à ulimit -s, tu fixes une nouvelle taille de pile pour les processus que tu lanceras depuis le shell.

    Par rapport au malloc, ce serait allouer un espace de plus à chaque passage de la boucle ?
    Non.

    Ça dépend de ce que tu veux faire exactement. Si tu veux toujours que ton programme se comporte comme il le fait actuellement, tu calcules la taille dont tu as besoin une fois pour toutes en évaluant tes arguments et en passant cette taille à malloc() plutôt qu'à tes VLAs. Tu vérifies ensuite si malloc() a réussi. Si c'est le cas, tu es sûr que tu pourras générer les mots de la taille que tu veux sans crash, chose qui n'est absolument pas garanti avec la pile. Bien sûr, tu penses à faire un free() après la fin de ton traitement.

    Mais d'une manière générale, tu n'as pas besoin d'allouer de mémoire pour faire ce que tu fais : tu peux écrire les caractères un à un directement sur la sortie standard avec fputc() ou putchar().

    J'avais fait le test, lorsque je ne génère qu'un mot, il peut être beaucoup plus grand que si j'en fais deux.
    C'est normal : ta pile a une taille fixe, et elle doit suffire à tout contenir, c'est-à-dire tes cadres de pile, les adresses de retour, les registres empilés à chaque étape et toutes les variables locales qui existent à un moment donné. Si tu ne génères qu'un seul mot, il peut prendre la place occupée en temps normal par le second. Tant que tu ne dépasses pas la « limite », tu ne risques rien. Il demeure quand même qu'en principe, la pile n'est pas faite pour stocker de grandes quantités de données.

    Paissad vient de me faire découvrir gdb. Et j'obtiens ceci :
    N'oublie pas que chaque appel de fonction utilise la pile, y compris les les fonctions déclarées dans les bibliothèques tierces. Une fois le tout compilé, elles font partie de ton programme, comme si tu les avais saisies toi-même. Si tu remplis la pile à ras-bord sans dépasser, ton programme fonctionnera, mais l'appel suivant provoquera le crash, te laissant croire que le problème se trouve ailleurs. À ce stade même gdb n'est que peu de secours puisque le débordement peut se produire à n'importe quel endroit de ton programme.

Discussions similaires

  1. Erreurs de segmentation !
    Par anti-conformiste dans le forum Applications et environnements graphiques
    Réponses: 16
    Dernier message: 18/10/2005, 11h11
  2. Erreur de segmentation
    Par Trunks dans le forum C
    Réponses: 3
    Dernier message: 06/10/2005, 18h28
  3. Erreur de segmentation (Inconnue)
    Par Dark-Meteor dans le forum C
    Réponses: 5
    Dernier message: 08/09/2005, 13h42
  4. [Dev-C++] Erreur de segmentation...
    Par sas dans le forum Dev-C++
    Réponses: 11
    Dernier message: 26/03/2005, 14h25
  5. erreur de segmentation
    Par transistor49 dans le forum C++
    Réponses: 10
    Dernier message: 15/03/2005, 11h18

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