a propos de char **

a propos de char ** - C - Programmation

Marsh Posté le 28-10-2005 à 11:42:05    

Rebonjour pour ce qui m'ont déjà aidé (  :ange: ). Maintenant je pense bien maitriser les pointeurs et je fait un petit programme qui est chargé de rechercher les fichiers en doubles dans un groupe dossier ( par exemple le dossier personnel ) malgrès tout un problème persiste sur char ** et char *[].
voici le code erroné:
 

Code :
  1. /* DISKCLEAN --[ Trieur/Nettoyeur de dossier personnel ]-- */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <dirent.h>
  5. #include <string.h>
  6. /* DISKCLEAN  
  7.    FONCTION --[ diskc_countfile ]--
  8.    Compte le nombre de fichier / dossier
  9.    dans un dossier spécifié en
  10.    argument.
  11.    Retourne le nombre obtenue.
  12. */
  13. int diskc_countfile(const char *directory)
  14. {
  15.     DIR *dir = NULL;
  16.     struct dirent *entry = NULL;
  17.     int result;
  18.     result = 0;
  19. /* Ouverture du répertoire */
  20.     dir = opendir(directory);
  21.     if (dir == NULL)
  22. return -1;
  23. /* Compter les fichiers / dossiers */
  24.     while ((entry = readdir(dir)) != NULL) {
  25. if (strcmp(entry->d_name, "." ) != 0
  26.     && strcmp(entry->d_name, ".." ) != 0) {
  27.     result++;
  28. }
  29.     }
  30.     closedir(dir);
  31.     return result;
  32. }
  33. /* DISKCLEAN  
  34.    FONCTION --[ diskc_readir ]--
  35.    Lecteur de dossier récursif.
  36.    Retourne un pointeur sur  
  37.    tableau des fichiers présent  
  38.    dans le dossier spécifié
  39.    en argument.
  40. */
  41. /* Nombre de fichier analysé */
  42. int nb_file = 0;
  43. char **diskc_readir(const char *directory)
  44. {
  45.     DIR *dir = NULL;
  46.     struct dirent *entry = NULL;
  47.     char **result = NULL;
  48.     int i;
  49. /* Ouverture du répertoire */
  50.     dir = opendir(directory);
  51.     if (dir == NULL)
  52. return NULL;
  53. /* Lecture du dossier */
  54.     i = 0;
  55.     nb_file = diskc_countfile(directory);
  56.     result = malloc(nb_file * sizeof(*result));
  57.     while ((entry = readdir(dir)) != NULL) {
  58. if (strcmp(entry->d_name, "." ) != 0
  59.     && strcmp(entry->d_name, ".." ) != 0) {
  60.     result[i] = entry->d_name;
  61.     i++;
  62. }
  63.     }
  64.     printf("i: %i\n", i);
  65.     printf("nb_file: %i\n", nb_file);
  66.     closedir(dir);
  67.     return result;
  68. }
  69. /* DISKCLEAN  
  70.    FONCTION --[ main ]--
  71.    Appeler par le systeme
  72.    Aucun arguments
  73. */
  74. int main(void)
  75. {
  76.     int i;
  77.     char **file = NULL;
  78.     file = diskc_readir("/home/pierre/" );
  79.     if (file == NULL)
  80. return EXIT_FAILURE;
  81.     printf("Analyse du dossier /home/pierre/\n" );
  82.     for (i = 0; i < nb_file; i++) {
  83. printf("%s\n", *(file + i));
  84.     }
  85.     if (file != NULL)
  86. free(file);
  87.     return EXIT_SUCCESS;
  88. }


 
Le programme affiche bien les fichiers du dossier /home/pierre ms certain sont coupés ou "collé" à d'autre. Il n'y a aucune erreur de segmentation le problème vient surment au niveau de:

Code :
  1. char **file = NULL;
  2.     file = diskc_readir("/home/pierre/" );


 
puisque quand je met un printf("%s\n", *(result + i)); dans la boucle while de la fonction diskc_readir cela me retourne parfaitement les dossiers et fichiers.
 
Merci bcp de votre aide.

Reply

Marsh Posté le 28-10-2005 à 11:42:05   

Reply

Marsh Posté le 28-10-2005 à 11:55:09    

result[i] = entry->d_name;
 
entry->d_name ne t'appartient pas. tu dois le copier
 
 
 
 
 
 
et pour éviter un double parcours, man realloc

Reply

Marsh Posté le 28-10-2005 à 11:56:36    

Code :
  1. *(file + i)


 
 
peine de mort

Reply

Marsh Posté le 28-10-2005 à 12:01:19    

realloc j'ai essayé ms j'ai absolument rien compris  :( .
*(file+1) on peut aussi faire file[i] ms ca sait pas le plus important.
 
Enfin pour result[i] = entry->d_name tu veux dire que je doit faire un strcpy?

Reply

Marsh Posté le 28-10-2005 à 12:07:58    

entre autres pour le strcpy

Reply

Marsh Posté le 28-10-2005 à 12:09:57    

Un strcpy cause un segment fault dans mon cas  :non: .
Peux-tu m'explique le realloc?

Message cité 1 fois
Message édité par super-tupapau le 28-10-2005 à 12:11:15
Reply

Marsh Posté le 28-10-2005 à 12:10:32    

strdup

Reply

Marsh Posté le 28-10-2005 à 12:12:46    

pas standard.

Reply

Marsh Posté le 28-10-2005 à 12:13:55    

super-tupapau a écrit :

Un strcpy cause un segment fault dans mon cas  :non: .


t'es un marrant, copier oui, mais copier où ...

Reply

Marsh Posté le 28-10-2005 à 12:14:41    

Merci cela fonctionne parfaitement mais j'ai pas compris pourquoi je devais dupliquer la chaine?


Message édité par super-tupapau le 28-10-2005 à 12:16:47
Reply

Marsh Posté le 28-10-2005 à 12:14:41   

Reply

Marsh Posté le 28-10-2005 à 12:19:31    

voila avec un realloc:
 

Code :
  1. /* DISKCLEAN --[ Trieur/Nettoyeur de dossier personnel ]-- */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <dirent.h>
  5. #include <string.h>
  6. /* DISKCLEAN  
  7.    FONCTION --[ diskc_readir ]--
  8.    Lecteur de dossier récursif.
  9.    Retourne un pointeur sur  
  10.    tableau des fichiers présent  
  11.    dans le dossier spécifié
  12.    en argument.
  13. */
  14. /* Nombre de fichier analysé */
  15. int nb_file = 1;
  16. char **diskc_readir(const char *directory)
  17. {
  18.     DIR *dir = NULL;
  19.     struct dirent *entry = NULL;
  20.     char **result = NULL;
  21.     int i;
  22. /* Ouverture du répertoire */
  23.     dir = opendir(directory);
  24.     if (dir == NULL)
  25. return NULL;
  26. /* Lecture du dossier */
  27.     i = 0;
  28.     while ((entry = readdir(dir)) != NULL) {
  29. if (strcmp(entry->d_name, "." ) != 0
  30.     && strcmp(entry->d_name, ".." ) != 0) {
  31.             result = realloc( result, nb_file * sizeof(*result));
  32.     result[i] = strdup(entry->d_name);
  33.             nb_file++;
  34.     i++;
  35. }
  36.     }
  37.     printf("i: %i\n", i);
  38.     printf("nb_file: %i\n", nb_file);
  39.     closedir(dir);
  40.     return result;
  41. }
  42. /* DISKCLEAN  
  43.    FONCTION --[ main ]--
  44.    Appeler par le systeme
  45.    Aucun arguments
  46. */
  47. int main(void)
  48. {
  49.     int i;
  50.     char **file = NULL;
  51.     file = diskc_readir("/home/pierre/" );
  52.     if (file == NULL)
  53. return EXIT_FAILURE;
  54.     printf("Analyse du dossier /home/pierre/\n" );
  55.     for (i = 0; i < nb_file-1; i++) {
  56. printf("%s\n", file[i]);
  57.     }
  58.     if (file != NULL)
  59. free(file);
  60.     return EXIT_SUCCESS;
  61. }

Reply

Marsh Posté le 28-10-2005 à 12:21:48    

voir 1er message.

Reply

Marsh Posté le 28-10-2005 à 12:28:30    

Il ne m'appartient pas?
c'est à dire? explique stp.

Reply

Marsh Posté le 28-10-2005 à 12:44:11    

man 3 readdir

Reply

Marsh Posté le 28-10-2005 à 13:20:52    

Après avoir lu le man sur readdir j'ai pu voir que c'etait un tableau de caractères qui était retourné et pas un pointeur sur un tableau de caractère.

Reply

Marsh Posté le 28-10-2005 à 13:23:03    

et quand bien même : ton entry, il pointe on ne sait où ... encore une fois, voir la doc.

Reply

Marsh Posté le 28-10-2005 à 20:36:14    

[...]
       The data returned by readdir() may be overwritten by  subsequent  calls
       to readdir() for the same directory stream.
[...]

Reply

Marsh Posté le 28-10-2005 à 21:56:33    

Taz a écrit :

pas standard.

spa standard strdup :ouch:
j'ai vérifié t'as raison :jap:
j'ai appris un truc, pourtant je m'en sers souvent et j'aurais mis ma main à couper que c'était standard.
En plus c'est bien utile comme fonction :( dommage.

Reply

Marsh Posté le 28-10-2005 à 23:10:48    

jesus_christ a écrit :

spa standard strdup :ouch:
j'ai vérifié t'as raison :jap:
j'ai appris un truc, pourtant je m'en sers souvent et j'aurais mis ma main à couper que c'était standard.
En plus c'est bien utile comme fonction :( dommage.


 
Pas standard ISO, mais c'est quand même POSIX.2
Et vu qu'il utilise dirent.h (POSIX.1), de toute manière, il peut utiliser strdup(). ;)

Reply

Marsh Posté le 28-10-2005 à 23:12:50    

ouais mais bon c'est l'ISO que je considère comme standard, POSIX c'est gentil mais fork() aussi c'est POSIX et ça marche pas terrible sous win ;)
merci pour l'info :jap:

Reply

Marsh Posté le 28-10-2005 à 23:16:58    

Euh oui si on veut vraiment du code portable, c'est ISO.
Je disais juste que vu qu'il s'était déjà engagé dans du POSIX, un strdup() de plus ou de moins ne faisait pas grande différence. [:petrus75]

Reply

Marsh Posté le 29-10-2005 à 08:39:45    

chrisbk a écrit :

Code :
  1. *(file + i)


 
 
peine de mort


juste pour être aussi HS : sémantiquement c'est l'écriture la + juste :jap:
 
edit
 [:aloy]


Message édité par lkolrn le 29-10-2005 à 08:41:52
Reply

Marsh Posté le 30-10-2005 à 15:04:52    

je voudrais savoir si il etait possible de faire ceci:

Code :
  1. struct ma_struct ** ptr = NULL;


et apres de l'allouer avec malloc ptr en sachat que ma_struct et déclararé avant.

Message cité 1 fois
Message édité par super-tupapau le 30-10-2005 à 15:07:00
Reply

Marsh Posté le 30-10-2005 à 17:04:44    

[:undertaker666]

Reply

Marsh Posté le 30-10-2005 à 17:41:37    

oui tu peux. Je reste perplexe sur la fin de ta phrase.

Reply

Marsh Posté le 30-10-2005 à 18:01:15    

ok ms je n'y arrive pas:

Code :
  1. struct {
  2. char *name;
  3. char *chemin;
  4. struct arch *next;
  5. struct arch *subdir;
  6. } arch;
  7. typedef struct arch * diskc_arch;
  8. ...
  9. diskc_arch **list = NULL;
  10. ...
  11. list = realloc( list, nb_file*sizeof(*list));
  12. ...
  13. list[i]->name = malloc( sizeof( entry->d_name ) );
  14. list[i]->name = strdup( entry->d_name );
  15. ...


 
Le compilateur me retourne erreur: request for member ‘name’ in something not a structure or union

Reply

Marsh Posté le 30-10-2005 à 18:50:33    

c'est moi ou la définition de ta struct est foireuse.
De plus selon toi, quel est le type de *list ?

Reply

Marsh Posté le 30-10-2005 à 18:56:06    

Pour le type *list de toute facon c'un pointeur donc c 4 qui sera retourner koi qu'il arrive.
Pour la definition de ma structure explique stp?

Reply

Marsh Posté le 30-10-2005 à 19:07:41    

arch est une variable globale dans ton programme, je doute que c'est ça que tu voulais obtenir !
(pour t'en convaincre, tu peux très bien faire arch.name = NULL; )
 
J'aurais plutôt écrit struct arch {...};
 
Ensuite, ton list aura come type "struct arch ***"
Donc list[i] n'aura pas "arch*" comme type mais bien "arch**"
Et arch** n'a pas le type d'un pointeur sur une structure, tu ne peux donc pas écrire list[i]->name;
 
remarque : il est très rare de se servir de "pointeurs de pointeurs de pointeurs"


Message édité par leneuf22 le 30-10-2005 à 19:08:48
Reply

Marsh Posté le 30-10-2005 à 19:19:01    

ok ca se complique trop je vais faire autrement c'est pas tres pratique comme ca.

Reply

Marsh Posté le 30-10-2005 à 19:52:44    

je trouve pas d'autre solution  :sweat:  en fait je voulais faire un tableau de pointeur sur des structures.

Reply

Marsh Posté le 30-10-2005 à 20:56:14    

personne ne sait comment faire?

Reply

Marsh Posté le 31-10-2005 à 01:15:05    

super-tupapau a écrit :

je voudrais savoir si il etait possible de faire ceci:

Code :
  1. struct ma_struct ** ptr = NULL;


et apres de l'allouer avec malloc ptr en sachat que ma_struct et déclararé avant.


Oui, et tu peux même utiliser realloc(). Avec NULL c'est pareil que malloc().


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 31-10-2005 à 01:16:39    

super-tupapau a écrit :

je trouve pas d'autre solution  :sweat:  en fait je voulais faire un tableau de pointeur sur des structures.


Comme d'hab :  


T *p = malloc(sizeof *p * n);



---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 31-10-2005 à 12:06:40    

Le problème ne vient pas du malloc voila le code:

Code :
  1. diskc_arch * diskc_readir(const char *directory)
  2. {
  3.     DIR *dir = NULL;
  4.     struct dirent *entry = NULL;
  5.     diskc_arch **list = NULL;
  6.     int i=0;
  7. /* Ouverture du répertoire */
  8.     dir = opendir(directory);
  9.     if (dir == NULL)
  10. return NULL;
  11. /* Lecture du dossier */
  12.     while ((entry = readdir(dir)) != NULL) {
  13. if (strcmp(entry->d_name, "." ) != 0
  14.     && strcmp(entry->d_name, ".." ) != 0) {
  15.             list = realloc( list, sizeof(*list) * nb_file);
  16.     /* Compléter les informations du fichiers: nom, chemin, pointeur suivant, pointeur précédent */
  17.     list[i]->name = malloc( sizeof( entry->d_name ) );
  18.     list[i]->name = strdup( entry->d_name );
  19.     list[i]->chemin = malloc( strlen( directory )+1 );
  20.             list[i]->chemin = strdup( directory );
  21.             list[i]->next = list[i+1];
  22.     list[i]->subdir = NULL;
  23.             nb_file++;
  24. i++;
  25. }
  26.     }
  27.     closedir(dir);
  28.     return list[i];
  29. }


 
ligne de compilation: gcc -Wall -W -O2 -pedantic -o diskclean main.c
 
ca donne:
 
main.c:58: erreur: request for member ‘name’ in something not a structure or union
main.c:59: erreur: request for member ‘name’ in something not a structure or union
main.c:60: erreur: request for member ‘chemin’ in something not a structure or union
main.c:61: erreur: request for member ‘chemin’ in something not a structure or union
main.c:62: erreur: request for member ‘next’ in something not a structure or union
main.c:63: erreur: request for member ‘subdir’ in something not a structure or union

Reply

Marsh Posté le 31-10-2005 à 12:26:27    

super-tupapau a écrit :

Le problème ne vient pas du malloc voila le code:


Ce code ne compile pas.  

  • Quelle est la définition de 'diskc_arch' ?
  • Où est défini 'nb_file' ?


Il faut poster du code complet, compilable (sauf erreurs), mais réduit au minimum qui montre le défaut.


Message édité par Emmanuel Delahaye le 31-10-2005 à 12:26:52

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 31-10-2005 à 12:40:59    

ok voila tous le programme:

Code :
  1. /* DISKCLEAN --[ Trieur/Nettoyeur de dossier personnel ]-- */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <dirent.h>
  5. #include <string.h>
  6. /* DISKCLEAN  
  7.    STRUCTURE --[ diskc_arch ]--
  8.    Structure chainée
  9. */
  10. struct arch {
  11. char *name;
  12. char *chemin;
  13. struct arch *next;
  14. struct arch *subdir;
  15. };
  16. typedef struct arch * diskc_arch;
  17. /* DISKCLEAN  
  18.    FONCTION --[ diskc_readir ]--
  19.    Lecteur de dossier récursif.
  20.    Retourne un pointeur sur  
  21.    tableau des fichiers présent  
  22.    dans le dossier spécifié
  23.    en argument.
  24. */
  25. /* Nombre de fichier analysé */
  26. int nb_file = 1;
  27. diskc_arch * diskc_readir(const char *directory)
  28. {
  29.     DIR *dir = NULL;
  30.     struct dirent *entry = NULL;
  31.     diskc_arch **list = NULL;
  32.     int i=0;
  33. /* Ouverture du répertoire */
  34.     dir = opendir(directory);
  35.     if (dir == NULL)
  36. return NULL;
  37. /* Lecture du dossier */
  38.     while ((entry = readdir(dir)) != NULL) {
  39. if (strcmp(entry->d_name, "." ) != 0
  40.     && strcmp(entry->d_name, ".." ) != 0) {
  41.             list = realloc( list, sizeof(*list) * nb_file);
  42.     /* Compléter les informations du fichiers: nom, chemin, pointeur suivant, pointeur précédent */
  43.     list[i]->name = malloc( sizeof( entry->d_name ) );
  44.     list[i]->name = strdup( entry->d_name );
  45.     list[i]->chemin = malloc( strlen( directory )+1 );
  46.             list[i]->chemin = strdup( directory );
  47.             list[i]->next = list[i+1];
  48.     list[i]->subdir = NULL;
  49.             nb_file++;
  50. i++;
  51. }
  52.     }
  53.     closedir(dir);
  54.     return list[i];
  55. }
  56. /* DISKCLEAN  
  57.    FONCTION --[ main ]--
  58.    Appeler par le systeme
  59.    Aucun arguments
  60. */
  61. int main( int argc, char ** argv )
  62. {
  63.     int i;
  64.     diskc_arch *file = NULL;
  65.     if(argv[1] == NULL)
  66. return EXIT_FAILURE;
  67.     file = diskc_readir(argv[1]);
  68.     if (file == NULL)
  69. return EXIT_FAILURE;
  70.     if (file != NULL)
  71. free(file);
  72.     return EXIT_SUCCESS;
  73. }

Reply

Marsh Posté le 31-10-2005 à 13:05:27    

super-tupapau a écrit :

ok voila tous le programme:

typedef struct arch * diskc_arch;
    diskc_arch **list = NULL;



Une étoile de trop...

   diskc_arch *list = NULL;


Citation :

    list[i]->name = malloc( sizeof( entry->d_name ) );
     list[i]->name = strdup( entry->d_name );
     list[i]->chemin = malloc( strlen( directory )+1 );
            list[i]->chemin = strdup( directory );



Ben non. Relire la doc de strdup(). Il fait l'allocation tout seul...

    list[i]->name = strdup( entry->d_name );
            list[i]->chemin = strdup( directory );


 
Quand à la libération, un simple free() est bien optimiste!
 
Il faut tout parcourir et libérer tout ce qui a été alloué sans couper la branche sur laquelle on est assis...


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 31-10-2005 à 13:37:16    

j'ai compris!
 
quand je même ceci:

Code :
  1. typedef struct arch * diskc_arch;
  2. diskc_arch **list = NULL;


 
ca donne un pointeur sur un pointeur sur un pointeur.
j'ai donc supprimer mit

Code :
  1. typedef struct arch diskc_arch;


 
comme ca j'ai plus d'erreur de compilation ms un segment fault avec list[i]->name = strdup( entry->d_name );
 
et pour le free je ferais comme ca?

Code :
  1. if (file != NULL)
  2.     for( i = 0; i<nb_file-2; i++ )
  3. free(file->next+i);
  4.     free(file);

Message cité 1 fois
Message édité par super-tupapau le 31-10-2005 à 13:43:43
Reply

Marsh Posté le 31-10-2005 à 13:45:54    

super-tupapau a écrit :

j'ai compris!
 
quand je même ceci:

Code :
  1. typedef struct arch * diskc_arch;
  2. diskc_arch **list = NULL;


 
ca donne un pointeur sur un pointeur sur un pointeur.
j'ai donc supprimer mit

Code :
  1. typedef struct arch diskc_arch;


comme ca j'ai plus d'erreur de compilation ms un segment fault avec list[i]->name = strdup( entry->d_name );


Ben oui. Tu as alloué le tableau mais pas les éléments...

Citation :


et pour le free je ferais comme ca?

Code :
  1. if (file != NULL)
  2.     for( i = 0; i<nb_file-1; i++ )
  3. free(file->next+i);
  4.     free(file);




Insuffisant. Chaque strdup() doit être compensé par un free(). C'est dans la doc, tu ne l'as donc pas lue malgré mon insistance ? Mais qu'est-ce qu'il faut faire pour se faire entendre ?


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed