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 :

Probleme de concatenation


Sujet :

C

  1. #1
    Membre confirmé
    Inscrit en
    Octobre 2007
    Messages
    28
    Détails du profil
    Informations forums :
    Inscription : Octobre 2007
    Messages : 28
    Par défaut Probleme de concatenation
    Bonjour,
    Alors voila, après avoir chercher de longues heures sur le net, c'est en désespoir de cause que je viens ici, car je ne sais plus trop quoi tenter.

    Donc, je dois réaliser un programme qui va lire, ligne par ligne, tous les fichiers d'un repertoire (nommé test dans mon code). Je récupère donc les noms de fichier, et je les concatene avec le chemin du répertoire. Ensuite, ma méthode readVote(filename) va s'occuper de la lecture.

    Actuellement le programme fonctionne, mais je rencontre des problèmes que je n'arrive pas à résoudre: Si je supprime la ligne "char * newname = "";", qui ne sert à rien du tout(c'était un ancien test), le compitaleur(gcc sous cygwin) me renvoie une segmentation fault. Idem, si je supprime "printf("%d \n",strlen(long_s));", à nouveau, erreur de segmentation.

    J'ai pensé que cela devait venir d'overflow au niveau de mes tableaux de caractères, et j'ai tenté de regler ca avec un malloc, ou en attribuant une taille fixe à mon tableau long_s, mais j'obtenais le même genre de problème qu'expliqué ci-dessus.

    Ensuite, j'ai remarqué un autre problème: Si je créais une variable char test[10] au tout debut de ma main, et que je regardais la taille, j'obtenais 11(normal). Mais si je la créais juste après "char * newname = "";", j'obtenais 5, et si je la créais entre "int size;" et "char * newname = "", j'obtenais une segmentation fault! Bref, je commence à ne plus rien y comprendre...

    Donc voila, si quelqu'un a déjà eu ce genre de problème, ou sait d'où vient le mien, ca m'aiderait fortement, parque la je ne vois plus trop quoi faire:/.



    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
    38
    39
    40
    41
    int main(int argc, char* argv[]){
      int i;
      int x;
      int size;
      char const * dirPath = "./test/";
     
      DIR * rep = opendir("./test");
     
        if (rep != NULL) {
            struct dirent * ent;
            while ((ent = readdir(rep)) != NULL) {
     
               char * name = (*ent).d_name;
               if(strcmp(".",name) && strcmp("..",name)){
     
                  size = strlen(name) + strlen(dirPath) +1;
                  char * long_s = malloc(size*sizeof(char));
     
                  printf("%d \n",strlen(long_s)); //PROBLEME SI ON SUPPRIME CETTE LIGNE
                  i=0;
                  x=0;
     
                  while (dirPath[i]){
                    long_s[i] = dirPath[i];
                    ++i;
                  }
                  while (name[x]){
                    long_s[i] = name[x];
                    ++i;
                    ++x;
                  }
     
                 long_s[i] = '\0';
                 readVote(long_s);
                 free(long_s);
                }
            }
            closedir(rep);
        }
        return 0;
    }

  2. #2
    Membre émérite
    Avatar de Pouet_forever
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    671
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 671
    Par défaut
    Fais très attention avec les déclarations char *. Je te conseille de mettre const parce que la chaîne pointée n'est pas modifiable :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    char const * dirPath = "./test/";
    char const * newname = "";
    En faisant ça, tu ne copies pas la chaîne mais tu fais juste pointer 'name' sur 'ent->d_name'.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char * name = (*ent).d_name;
    Ton problème se situe au niveau du char * long_s ;, il faut bien que tu alloues avec malloc ou alors que tu déclares un tableau statique.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    char * long_s = malloc(size * sizeof *long_s));
    /* Ou */
    char long_s[100] = "";

  3. #3
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 487
    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 487
    Par défaut
    Citation Envoyé par Slash10 Voir le message
    Mais si je la créais juste après "char * newname = "";", j'obtenais 5, et si je la créais entre "int size;" et "char * newname = "", j'obtenais une segmentation fault! Bref, je commence à ne plus rien y comprendre...
    Et, à mon avis, il n'y a rien à comprendre car il s'agit d'un comportement indéterminé.

    À première vue, quand tu écris :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
                  char * long_s ;//= malloc(size*sizeof(char));
    Tu crées un pointeur qui ne pointe vers nulle part. Hauts risques de plantage. Si tu l'initialises soit avec ton malloc(), soit en déclarant comme un tableau, il pointe vers une zone valable mais vide à priori (comprendre : aux données non initialisées). Ton appel à strlen(long_s) a toutes les chances d'échouer s'il ne rencontre pas un '\0' à temps (et renverra de toutes façons une valeur farfelue).

    D'autre part, lorsque tu fais ton malloc(), tu alloues une zone de taille multiple de size, qui est déclarée mais n'est pas initialisée non plus.

  4. #4
    Membre confirmé
    Inscrit en
    Octobre 2007
    Messages
    28
    Détails du profil
    Informations forums :
    Inscription : Octobre 2007
    Messages : 28
    Par défaut
    Alors premièrement, merci de te pencher sur mon problème.

    Ensuite, j'ai testé les modifications que tu m'a conseillées.
    J'ai édité le code afin de le mettre à jour, mais même avec malloc/free, si je supprime la ligne printf("%d \n",strlen(long_s));, il lit bien le premier fichier, appelé f1.txt, mais lorsqu'il veut lire le 2ème, il ne parvient pas à l'ouvrir. Ma methode de lecture renvoie le nom du fichier lorsqu'il y a une erreur, et le nom est en réalité f2.txt, alors qu'il devrait normalement être ./test/f2.txt, d'où l'impossibilité d'ouvrir le fichier. Donc le problème survient pendant la 2eme itération de boucle, où la chaine dirPath n'est pas pris en compte, mais je vois pas trop pourquoi:/.
    A noter que lorsque je laisse mon printf("%d \n",strlen(long_s));, la première fois qu'il passe dans la boucle, il imprime 0, et la seconde fois, il imprime 13...

    J'ai regardé ta 2ème solution également, qui marche si je laisse le printf("%d \n",strlen(long_s));, mais qui renvoie une segmentation fault si je l'enleve.

    Enfin, ta 2ème remarque, concernant la ligne char * name = (*ent).d_name;, je ne dois rien modifier non?

  5. #5
    Membre confirmé
    Inscrit en
    Octobre 2007
    Messages
    28
    Détails du profil
    Informations forums :
    Inscription : Octobre 2007
    Messages : 28
    Par défaut
    @Obsidian: Merci également pour ton aide.
    Effectivement, declarer le pointeur pointant vers nulle part est dangereux, je m'en souviens maintenant. Cependant, même enfaisant un malloc, si je supprime le printf("%d \n",strlen(long_s)); j'ai un problème, comme j'ai expliqué en réponse à pouet_forever.
    Tu me dis que la taille de size, lors que mon malloc, est declarée mais non initialisée, mais la ligne juste au dessus du malloc, size = strlen(name) + strlen(dirPath) +1;, initialise size (à 14 si je l'imprime), donc normalmeent cela ne devrait pas poser problème, non?

  6. #6
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 487
    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 487
    Par défaut
    Citation Envoyé par Slash10 Voir le message
    Tu me dis que la taille de size, lors que mon malloc, est declarée mais non initialisée, mais la ligne juste au dessus du malloc, size = strlen(name) + strlen(dirPath) +1;, initialise size (à 14 si je l'imprime), donc normalmeent cela ne devrait pas poser problème, non?
    Effectivement, j'ai fait un copier-coller de ton code dans un éditeur pour y voir plus clair et cette ligne a disparu. Mauvaise manip'

  7. #7
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Pourrais-tu poster le corps de la fonction readVote() également

  8. #8
    Membre émérite
    Avatar de Pouet_forever
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    671
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 671
    Par défaut
    Citation Envoyé par Slash10 Voir le message
    Enfin, ta 2ème remarque, concernant la ligne char * name = (*ent).d_name;, je ne dois rien modifier non?
    Non, mais c'est pour être sûr que tu sais ce que tu fais.

    J'ai remarqué que ton closedir(rep); était mal placé aussi (une accolade trop loin).

    Comme l'a dit obsidian, tu fais un strlen sur quelque chose qui n'est pas initialisé donc tu as toutes les chances que ton programme plante. Enlève purement et simplement cette ligne (même si ton programme plante), ou alors mets la après 'long_s[i] = '\0';'.

  9. #9
    Membre confirmé
    Inscrit en
    Octobre 2007
    Messages
    28
    Détails du profil
    Informations forums :
    Inscription : Octobre 2007
    Messages : 28
    Par défaut
    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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    char *get_next_line (FILE *stream, char **pp_line);
    int readVote(char * filename);
     
    /* lecture d'un fichier filename */
    int readVote(char * filename){
      FILE* fileID;
     
       /* ouverture du fichier .vote */
      if ((fileID = fopen(filename,"r")) == NULL) {
        fprintf(stderr,"Error: cannot open the file ""%s"" in flux mode \n",filename);
      }
     
      /* lecture ligne par ligne */
      char ** pp_line;
      char * test2 = get_next_line(fileID,pp_line);
      while (test2!=NULL){
        printf(" %s \n",test2);
        test2 = get_next_line(fileID,pp_line);
      }
     
    }
     
    /* lecture d'une ligne. Le pointeur passé en argument pointe alors vers l'adresse de
    la ligne stockée en mémoire */
    char *get_next_line (FILE *stream, char **pp_line){
      if (stream != NULL && pp_line != NULL){
        void *line = NULL;
        char tmp[BUFSIZ] = "";
        size_t size = 1;
     
        *pp_line = NULL;
        while (fgets (tmp, BUFSIZ, stream) != NULL){
          size += BUFSIZ; //Incremente size de BUFSIZ
          line = realloc (*pp_line, sizeof (**pp_line) * size);
          if (line != NULL){
            if (*pp_line == NULL){
              ((char *)line)[0] = '\0';
            }
            *pp_line = line;
            line = NULL;
            strcat (*pp_line, tmp);
            if ((*pp_line)[strlen (*pp_line)-1] == '\n'){
              (*pp_line)[strlen (*pp_line)-1] = '\0';
              break;
            }
          }else{
            free (*pp_line), *pp_line = NULL;
          }
        }
      }
      return *pp_line;
    }
    Voila tout le reste du programme. A noter que la fonction pour lire une ligne n'est pas de moi, la source étant ce site.

    Edit: Si je remplace printf("%d \n",strlen(long_s)); par printf("%d \n",strlen(dirPath));, à la première itération il imprime 7(longueur de ./test/, normal), et à la 2ème, 0. D'où le fait que ma méthode readVote ne parvient pas à ouvrir le fichier, vu qu'elle n'a plus le chemin du dossier. Cependant, la chaine dirPath étant déclarée comme constante, elle ne devrait pas être modifiée normalement...

  10. #10
    Membre émérite
    Avatar de Pouet_forever
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    671
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 671
    Par défaut
    J'ai pas tout regardé mais je pense que ton erreur se situe à ce niveau là :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    char ** pp_line;
      char * test2 = get_next_line(fileID,pp_line);
    [...]
        test2 = get_next_line(fileID,pp_line);
    En fait il ne faut pas que tu déclares un pointeur de pointeur, mais tout simplement un pionteur et ensuite que tu passes l'adresse de ce pointeur à ta fonction.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    char * pp_line;
      char * test2 = get_next_line(fileID,&pp_line);
    [...]
        test2 = get_next_line(fileID,&pp_line);
    Est-ce que c'est nécessaire d'avoir un pointeur générique ici ?


  11. #11
    Membre confirmé
    Inscrit en
    Octobre 2007
    Messages
    28
    Détails du profil
    Informations forums :
    Inscription : Octobre 2007
    Messages : 28
    Par défaut
    wow, effectivement ca marche! Je vous remercie fortement en tout cas!
    Mais tu saurais m'expliquer un peu pourquoi le fait de déclarer un double pointeur à cet endroit faisait que le contenu pointé par dirPath soit effacé?

  12. #12
    Membre émérite
    Avatar de Pouet_forever
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    671
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 671
    Par défaut
    Quand tu déclares un pointeur, il a une adresse et il pointe vers quelque chose. Quand tu passes ce pointeur à une fonction tu passes en réalité ce qu'il pointe et tu récupères dans ta fonction une copie de ce que pointe ton pointeur. Si tu veux pouvoir modifier ce pointeur dans une fonction il ne faut pas passer le contenu de ton pointeur, mais bien ton pointeur lui-même.

    Toi tu déclarais un pointeur de pointeur et tu passais celui-là tel quel. Ta fonction n'attendait pas un pointeur de pointeur mais un pointeur sur un pointeur (bon je joue sur les mots, mais c'est pour expliquer).

    Je ne sais pas si c'est bien expliqué, j'ai toujours eu du mal à expliquer ce 'phénomène'.

  13. #13
    Membre confirmé
    Inscrit en
    Octobre 2007
    Messages
    28
    Détails du profil
    Informations forums :
    Inscription : Octobre 2007
    Messages : 28
    Par défaut
    Donc si je comprend bien:
    En passant un pointeur de pointeur(ce que je faisais), le système crée une copie de ce pointeur de pointeur, et va la modifier. Donc le pointeur de pointeur passé en argument lui ne sera pas modifié, et pointera vers un endroit aléatoire de ma mémoire.

    Tandis que si je passe l'adresse de mon pointeur, je vais modifier le contenu de cette adresse, c'est à dire mon pointeur, et donc je n'aurais pas de pointeur pointant vers nulle part.

    C'est bien ca, ou j'ai pas saisi correctement le comportement?

  14. #14
    Membre émérite
    Avatar de Pouet_forever
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    671
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 671
    Par défaut
    En faisant ce que tu faisais (super la phrase xD) tu envoyais seulement ce que pointait ce que tu avais décalré dans ta fonction (c'est-à-dire n'importe quoi). Du coup ça ne pouvait que segfault (à moins d'un coup de chance).

    Sinon pour bien visualiser, fais un schéma.

  15. #15
    Membre confirmé
    Inscrit en
    Octobre 2007
    Messages
    28
    Détails du profil
    Informations forums :
    Inscription : Octobre 2007
    Messages : 28
    Par défaut
    Ok, je vois dèjà plus clair, merci beaucoup en tout cas

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

Discussions similaires

  1. Probleme pour concatener 2 objets Set
    Par PORTES dans le forum C++
    Réponses: 13
    Dernier message: 16/04/2007, 15h02
  2. Probleme de concatenation dans une requete
    Par toddy_101 dans le forum Requêtes
    Réponses: 4
    Dernier message: 12/01/2007, 14h43
  3. Réponses: 4
    Dernier message: 03/11/2006, 17h11
  4. [FLASH 8] Probleme de concatenation
    Par kubito dans le forum ActionScript 1 & ActionScript 2
    Réponses: 4
    Dernier message: 14/04/2006, 14h31
  5. probleme de concatenation
    Par cyna dans le forum C
    Réponses: 2
    Dernier message: 23/08/2002, 10h41

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