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 :

fonction découpage d'un char* : problèmes (pointeur null + segmentation fault)


Sujet :

C

  1. #1
    Nouveau Candidat au Club
    Homme Profil pro
    Boss
    Inscrit en
    Avril 2017
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Boss
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2017
    Messages : 1
    Points : 1
    Points
    1
    Par défaut fonction découpage d'un char* : problèmes (pointeur null + segmentation fault)
    Bonjour !

    j'essaye de réaliser une fonction classique : le but est de découper un char* selon un certain délimiteur. La fonction renvoie le nombre de mots obtenus.

    data : le pointeur vers le char** où les mots sont rangés
    message : le message à découper
    delim : le délimiteur
    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
     
    int cut(char*** data, char* message, const char delim){
    	int compteur_mots = 0;
    	int i = 0;
    	while(*(message+i)){
    		if(*(message+i) == delim){
    			**(data+compteur_mots) = giveS(message,0,i-1);
    			compteur_mots++;
    			message+=i+1;
    			i=-1;
    			*data = realloc(*data,sizeof(char**)*(compteur_mots+1));
    		}
    		i++;
    	}
    	**(data+compteur_mots) = giveS(message,0,strlen(message));
    	compteur_mots++;
    	return compteur_mots;
    }
    récupère un mot de codemess (du caractère n° begin au caractère n° end)
    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
     
    char* giveS(char* codemess, int begin, int end){
      if (codemess != NULL){
        char* thing = malloc(strlen(codemess));
        strcpy(thing,codemess+b);
        if(b < e){
          thing[e-b+1] = '\0';
          thing = realloc(thing,strlen(thing));
          return thing;
        }else{
          fprintf (stderr, "Error begin > end\n");
          free(thing);
          return NULL;
        }
      }else{
        return NULL;
      }
    }
    et le main pour tester tout ça

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    #define test "hello world ..." //à modifier pour tester sur différentes phrases
    int main(){
     
    	char* c = malloc(strlen(test)+1);
    	strcpy(c,test);
    	*(c+strlen(test)) = '\0';
    	char** data = malloc(sizeof(char**));
    	int t = cut(&data,c,' ');
    	int i;
    	for(i=0;i<t;i++){ printf("%d : %s\n",t,*(data+i)); fflush(stdout);}
    }
    Problèmes :
    -> je n'arrive à récupérer que le 1er mot (pour le coup, tout va bien pour lui)
    -> pour ce qui est du 2eme et 3eme mot, en l'affichant dans la fonction cut je vois qu'il sont bien en 2eme et 3emeposition de *data, mais lorsque je veux l'afficher dans le main, je vois (NULL)
    -> si j' ajoute un mot de plus à ma phrase : segmentation fault.

    (j'ai enlevé les printf de test ici)

    Avez-vous des avis sur ça ?
    Merci à vous !

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Je ne comprends pas grand chose à ton code tout pourri : Ils sont où les free ? ils sont où les tests NULL après un realloc ? ...

    Tu es sérieux en 1 boucle et 2 tests tu as déjà 2 realloc et 2 malloc ?

    Édit: c'est un algo encore plus tordu que je ne l'avais vu :
    1. L'algo préfère y aller aux realloc que faire une double passe. Et en plus, l'algo va toujours créer une case de plus, "il anticipe". Conséquence - précondition qui faut savoir: il faut avoir 1 case.
    2. L'algo préfère créer l'emplacement mémoire et ensuite tester la cohérence des bornes


    Et ton problème semble être ici :
    1) char* thing = malloc(strlen(codemess));: tu crées ton emplacement mémoire
    2) thing[e-b+1] = '\0';: tu penses au '\0'. Manque de bol 1) tu as mallocé pile-poil sans te soucier du '\0' 2) tu n'as pas vérifié que e-b = strlen(codemess)
    3) thing = realloc(thing,strlen(thing)); <- Là je ne sais pas: tu agrandis ta chaîne avec la même longueur

  3. #3
    Expert éminent sénior
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 214
    Points : 10 140
    Points
    10 140
    Par défaut
    Le code est pourri je confirme mais moi je vois encore une autre erreur.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char** data = malloc(sizeof(char**));
    cool , tu alloue 4 ou 8 octets (ça dépend si on est en 32 ,64 bits).
    ça sent le segfault a plein nez si tu l’utilise

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int cut(char*** data, char* message, const char delim){
    Je ne vois pas ou tu as besoin d' un triple pointeur dans ton code (et donnait le pointeur d'un double pointeur en paramètre c'est vraiment chelou), si on maîtrise pas les pointeurs on évite leur utilisation au stricte minimum , alors un triple pointeur c'est la casse assuré.
    En faite de toute ma carrière de dev je ne l'ai jamais utilisé (le triple pointeur) pourtant j'ai fait du bas niveau en C du jeux vidéo 2D/3D avec et des concepts plus complexe que "découper une chaine de caractere".

    Pour moi le souci vient de deux choses principalement :
    1) ton algo est mal pensé , je veux dire découpé une chaine de caractere on peut faire beaucoup mais beaucoup plus simple.
    2) tu ne maîtrise pas les pointeurs suffisamment pour partir sur un algo aussi complexe.
    3)Donc le but c'est de savoir simplifié son probleme pas le complexifier (surtout qu'on est débutant).

  4. #4
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Bonjour,

    Il fallait oser utiliser un triple pointeur et des realloc(), et malgré tout ton code est ok à part quelques inattentions.

    Le terminateur n'est pas encore très clair pour toi. Tu oublies de le réserver en faisant char* thing = malloc( strlen(codemess) /*!*/ ); (strlen ne compte pas le terminateur) et deux lignes plus loin tu veux l'écrire, mais c'est inutile car strcpy() copie la chaîne et aussi son terminateur. La ligne suivante qui fait un realloc() est certainement une ligne que tu as oublié d'enlever.
    Dans main() la ligne *(c+strlen( test )) = '\0'; est inutile après un strcpy().

    L'utilisation du triple pointeur nécessite de faire un dessin. Ça ne fait que 30 ans que je fais de l'informatique, je n'ai donc jamais eu l'occasion de les utiliser. Regarde bien les lignes **(data+compteur_mots) = giveS( message , 0 , i-1 );, c'est presque cela.
    Avec ton dessin, peut-être écriras-tu à la place *(*data+compteur_mots) = giveS( message , 0 , i-1 ); et **(data+compteur_mots) = giveS(message,0,strlen(message));.

    Quand tu fais char** data = malloc(sizeof(char**)); et *data = realloc( *data , sizeof( char** )*(compteur_mots+1) );, il y a une étoile de trop. Fais un dessin pour voir pourquoi, bien qu'ici ton code fonctionne car un pointeur de pointeur a la même taille qu'un pointeur.

  5. #5
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Ce morceau de programme est inutilement complexe pour la tâche qui lui incombe. Le découpage de chaînes est habituellement réalisé à base de strchr, strcspn, strpbrk, strtok.. (voir section String examination) selon ce que l'on cherche à accomplir.

    En règle générale, on ne confie pas plusieurs responsabilités à une seule fonction : on ne lui fait pas faire de gestion dynamique de mémoire si on peut l'éviter, par exemple.

    Il existe de nombreuses manières de faire ce découpage, en voici quelques unes accompagnées de conséquences qui leurs sont inhérentes :

    • scinder toute la chaîne à l'avance, en place : le contenu du buffer d'entrée est altéré, aucune allocation dynamique n'est requise ;
    • scinder toute la chaîne à l'avance, en copiant chaque mot : le contenu du buffer d'entrée n'est pas altéré, des allocations totalisant le même ordre de grandeur que la taille de la chaîne d'entrée sont requises ;
    • scinder toute la chaîne à l'avance, en ne conservant pour chaque mot qu'un pointeur vers une position du buffer d'entrée et un size_t (la taille du mot) : le contenu du buffer d'entrée n'est pas altéré, des allocations relativement légères sont requises ;
    • scinder la chaîne au sein de la boucle d'affichage, chaque mot après l'autre : le contenu du buffer d'entrée n'est pas altéré, aucune allocation dynamique n'est requise (le coût d'une allocation sur la pile est négligeable), mais on ne peut plus réutiliser les informations obtenues puisqu'elles sont abandonnées à chaque itération ;
    • etc..


    Tu dois identifier à l'avance les contraintes de ton cas d'utilisation et adopter une stratégie adaptée.

Discussions similaires

  1. Pointeurs et segmentation fault
    Par Jichaels dans le forum Débuter
    Réponses: 4
    Dernier message: 15/10/2016, 23h21
  2. Réponses: 7
    Dernier message: 18/03/2014, 15h48
  3. Problème de compilation segmentation fault
    Par nightfire dans le forum Fortran
    Réponses: 7
    Dernier message: 24/02/2009, 17h02
  4. Problème : pas de segmentation fault ?!
    Par Loïc B. dans le forum C++
    Réponses: 3
    Dernier message: 05/11/2007, 17h08
  5. passage pointeur NULL dans une fonction
    Par reptils dans le forum C
    Réponses: 4
    Dernier message: 11/05/2006, 23h12

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