récuperer un caractère dans un fichier avec read

récuperer un caractère dans un fichier avec read - C - Programmation

Marsh Posté le 24-11-2012 à 18:16:40    

Bonjour à tous,
 
alors voila j'ai fais une fonction permettant de renvoyer la première ligne d'un fichier.
Le problème c'est que dès la ligne 10, quand j'essaie d'afficher le caractère lu dans la variable courant, ben ça marche pas ^^
quelqu'un saurait m'expliquer ?  
 

Code :
  1. char* read_line(int fd)
  2. {
  3.         int i=0;
  4.         char *line;
  5.         char courant;
  6.         line=malloc(sizeof(char*));
  7.         read(fd,&courant,1);
  8.        
  9.         printf("%c\n",courant);
  10.         while(courant!='\n')
  11.         {
  12.                 line[i]=courant;
  13.                 i++;
  14.                 realloc(line,(1+i)*sizeof(char*));
  15.                 read(fd,&courant,1);
  16.         }
  17.         line[i]='\0';
  18.         return line;
  19. }


 
avec son main :  
 

Code :
  1. int main()
  2. {
  3.         int f=open("ff",O_WRONLY | O_CREAT, 0644);
  4.         printf("%s",read_line(f));
  5. return 0;
  6. }


 
le fichier ff contient bien des caractères, des retours à la ligne...
 
 
merci d'avance :)

Reply

Marsh Posté le 24-11-2012 à 18:16:40   

Reply

Marsh Posté le 24-11-2012 à 18:39:18    

Bonjour !
Vous ouvrez le fichier en mode "write only" (O_WRONLY), en demandant au système de le créer si nécessaire, ce qui n'est pas des plus astucieux pour lire le contenu du fichier ! :)
 
Vous devriez tenter :
 
int f = open("ff", O_RDONLY);
 
Puis tester (éventuellement dans la fonction "read_line" qui pourrait dans ce cas-là renvoyer NULL), que f n'est pas égal à -1 (que le fichier a donc bien été ouvert).
 
Par ailleurs, votre gestion de la mémoire comporte plusieurs erreurs :  
   * ligne 6 : line = (char *) malloc (sizeof(char)); [Note : la norme impose sizeof(char) = 1, donc on peut ne pas le préciser, mais ce n'est pas une faute de le mettre], car vous voulez stocker dans line 1 caractère, pas un pointeur sur un caractère.
   * ligne 16 : line = (char *)realloc(line, (1+i)*sizeof(char));
   * Au vu des faibles tailles de mémoire qui sont demandées, les fonctions malloc et realloc se déroulement correctement, mais, en théorie, vous devriez tester qu'elles ne renvoient pas NULL, ce qui indiquerait que la mémoire demandée ne peut être allouée.
 
De plus, vous ne vérifiez pas que la fonction read se déroule correctement (code de retour = nombre d'octets lus, soit 1 dans le cas présent).
 
Pour terminer, n'oubliez pas de libérer la mémoire allouée par la fonction "read_line"
 
Bonne continuation à vous !

Message cité 1 fois
Message édité par Farian le 24-11-2012 à 18:47:38
Reply

Marsh Posté le 24-11-2012 à 18:49:38    

Farian a écrit :

Bonjour !
Vous ouvrez le fichier en mode "write only" (O_WRONLY), en demandant au système de le créer si nécessaire, ce qui n'est pas des plus astucieux pour lire le contenu du fichier !
 
Vous devriez tenter :
 
int f = open("ff", O_RDONLY);
 
Puis tester (éventuellement dans la fonction "read_line" qui pourrait dans ce cas-là renvoyer NULL), que f n'est pas égal à -1 (que le fichier a donc bien été ouvert).
 
Par ailleurs, votre gestion de la mémoire comporte plusieurs erreurs :  
   * ligne 6 : line = (char *) malloc (sizeof(char)); [Note : la norme impose sizeof(char) = 1, donc on peut ne pas le préciser, mais ce n'est pas une faute de le mettre], car vous voulez stocker dans line 1 caractère, pas un pointeur sur un caractère,
   * ligne 16 : line = (char *)realloc(line, (1+i)*sizeof(char)); (Idem)
 
De plus, vous ne vérifiez pas que la fonction read se déroule correctement (code de retour = nombre d'octets lus, soit 1 dans le cas présent).
 
Bonne continuation à vous !


 
 
Merci pour votre réponse, par contre, à l’exécution :

Code :
  1. printf("%c\n",courant);

n'affiche pas le bon caractère qui est sensé se trouver dans mon fichier mais un autre
 
et puis juste après l'avoir affiché, l’exécution plante même après vos modifications :/

Reply

Marsh Posté le 24-11-2012 à 18:54:38    

Re-bonjour !
 
Comme je le dis souvent : "CMCM" ! (Chez Moi, Ça Marche :) ), et valgrind ne trouve rien à redire lors de l'exécution ...
 
Il doit y avoir une autre petite erreur dans votre code, postez-le, cela ne doit pas être grand chose.


Message édité par Farian le 24-11-2012 à 18:56:52
Reply

Marsh Posté le 24-11-2012 à 19:00:51    

Je suis trop bête !!!!! j'avais oublié de mettre mon fichier dans le même dossier que mon main ^^  
 
problème résolu :) merci encore


Message édité par Benh_31 le 24-11-2012 à 19:14:21
Reply

Marsh Posté le 24-11-2012 à 19:15:21    

Je ne vois pas de faute, si ce n'est que j'aurais remplacé le code "if (errno)" par "if (f < 0)", qui est quand même plus propre, mais qui doit revenir au même ...
 
Chez moi, votre code s'exécute sans problème (valgrind ok)
 
Que ce soit sous windows ne devrait, en théorie, pas poser de problème ... la seule chose que je vois est que si votre fichier ne contient qu'une seule ligne et donc pas de retour chariot, le comportement sera sans doute étrange ...)
 
Ma version du code, qui ajoute simplement la gestion du code de retour de la fonction "read" :  
 

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <fcntl.h>
  7. char* read_line(int fd)
  8. {
  9.     if (fd < 0)
  10.     {
  11.         return NULL;
  12.     }
  13.    
  14.     int i=0;
  15.     char *line;
  16.     char courant;
  17.     line=(char *)malloc(sizeof(char*));
  18.     int res = read(fd,&courant,1);
  19.     if (res == 1)
  20.     {
  21. //      printf("%c\n",courant);
  22.         while(courant!='\n' && res == 1)
  23.         {
  24.             line[i]=courant;
  25.                 i++;
  26.                 line = (char *)realloc(line,(1+i)*sizeof(char*));
  27.                 res = read(fd,&courant,1);
  28.         } 
  29.     }
  30.     line[i]='\0';
  31.     return line;
  32. }
  33. int main()
  34. {
  35.     int f=open("ff",O_RDONLY, 0644);
  36.     char *retour = read_line(f);
  37.     if (retour != NULL)
  38.     {
  39.         printf("%s\n",retour);
  40.         free(retour);
  41.     }
  42.     return 0;
  43. }

Reply

Marsh Posté le 24-11-2012 à 19:16:06    

Hé hé ! J'étais trop occupé à mettre en forme ma version du code et j'avais raté votre dernier message :)
 
Tout est bien qui finit bien, donc !  
 
Bonne continuation à vous !

Reply

Marsh Posté le 25-11-2012 à 00:32:34    

j'ai toujours un problème :( j'arrive bien à récupérer ma ligne, mais après mon return line; je récupère NULL :/ je comprends pas...

Reply

Marsh Posté le 25-11-2012 à 09:19:22    

Précisez votre problème ...  
 
Le code que j'ai posté, moyennant quelques petites adaptations, cf. ci-dessous, fonctionne correctement, pour plusieurs lignes :  
 

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <fcntl.h>
  7. char* read_line(int fd)
  8. {
  9.     if (fd < 0)
  10.     {
  11.             return NULL;
  12.     }
  13.     int i=0;
  14.     char *line = NULL;
  15.     char courant;
  16.     int res = read(fd,&courant,1);
  17.     if (res == 1)
  18.     {
  19.         line=(char *)malloc(sizeof(char*));
  20.         while(courant!='\n' && res == 1)
  21.         {
  22.             line[i]=courant;
  23.             i++;
  24.             line = (char *)realloc(line,(1+i)*sizeof(char*));
  25.             res = read(fd,&courant,1);
  26.         }
  27.         line[i]='\0';
  28.     }
  29.     return line;
  30. }
  31. int main()
  32. {
  33.     int f=open("ff",O_RDONLY, 0644);
  34.     char *retour;
  35.     int numeroLigne = 1;
  36.     while ((retour  = read_line(f)) != NULL)
  37.     {
  38.         printf("Ligne %d : %s\n", numeroLigne, retour);
  39.         free(retour);
  40.         numeroLigne++;
  41.     }
  42.     return 0;
  43. }

Message cité 2 fois
Message édité par Farian le 25-11-2012 à 09:22:21
Reply

Marsh Posté le 25-11-2012 à 12:10:01    

je viens de reregarder mon code et j'avais oublié de faire un free, maintenant ça marche ( pour de bon cette fois ^^ )
 
merci encore :)

Reply

Marsh Posté le 25-11-2012 à 12:10:01   

Reply

Marsh Posté le 25-11-2012 à 12:38:32    

Farian a écrit :

Le code que j'ai posté, moyennant quelques petites adaptations, cf. ci-dessous, fonctionne correctement, pour plusieurs lignes


Bonjour
Oui il fonctionne. Mais faire des realloc de 1 en 1 c'est pas super super optimisé vitesse. De plus, mettre le mode 0644 dans open() ne se justifie que si le fichier est créé donc si on passe le flag "O_CREATE" (ce qui s'adapte mal avec le flag O_RDONLY)
Et tant qu'à mettre un mode, autant utiliser les constantes appropriées S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH...

Message cité 1 fois
Message édité par Sve@r le 25-11-2012 à 12:43:07

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 25-11-2012 à 17:55:23    

Sve@r a écrit :


Bonjour
Oui il fonctionne. Mais faire des realloc de 1 en 1 c'est pas super super optimisé vitesse. De plus, mettre le mode 0644 dans open() ne se justifie que si le fichier est créé donc si on passe le flag "O_CREATE" (ce qui s'adapte mal avec le flag O_RDONLY)
Et tant qu'à mettre un mode, autant utiliser les constantes appropriées S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH...


 
 
Pour le realloc de 1 en 1 c'est ce qui m'est demandé : ça permet de pas avoir de problèmes si la chaine dépasse le buffer et aussi de pas gaspiller de l'espace pour rien.

Reply

Marsh Posté le 25-11-2012 à 22:35:30    

Benh_31 a écrit :

Pour le realloc de 1 en 1 c'est ce qui m'est demandé : ça permet de pas avoir de problèmes si la chaine dépasse le buffer et aussi de pas gaspiller de l'espace pour rien.


Il est bien évident qu'il faut réallouer pour éviter un dépassement. Mais de 1 en 1...
En fait, le gaspillage d'espace est bien évidemment un problème à prendre en compte mais c'est là qu'on peut faire des compromis entre ce problème et les autres. Par exemple allouer de 100 en 100 permettra une certaine souplesse (surtout qu'on lit une ligne et que les lignes de plus de 100 caractères ne sont pas courantes) et le gaspillage n'est pas énorme.
 
Bien entendu s'il est demandé spécifiquement une allocation de 1 en 1 tu le fais mais rien ne t'empêche d'aller au-delà de ce qui est demandé. Par exemple la taille d'allocation pourrait être une macro ce qui permettrait à ton code d'évoluer facilement si besoin était. C'est ce qu'on nomme "évolutivité"...


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 26-11-2012 à 19:07:36    

c'est sur je suis tout à fait d'accord avec toi, dans mon cas c'est ce qui m'est demandé :)

Reply

Marsh Posté le 26-11-2012 à 22:50:37    

Farian a écrit :

Précisez votre problème ...

 

Le code que j'ai posté, moyennant quelques petites adaptations, cf. ci-dessous, fonctionne correctement, pour plusieurs lignes :

 


 

Il marche, mais il n'est néanmoins pas parfait: c'est malloc(sizeof(char)) que l'on devrait avoir, et non malloc(sizeof(char*)) et idem pour le réalloc.

 

A+,


Message édité par gilou le 26-11-2012 à 22:51:01

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Sujets relatifs:

Leave a Replay

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