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 :

Recoder la fonction getline


Sujet :

C

  1. #1
    Membre à l'essai
    Homme Profil pro
    Lycéen
    Inscrit en
    Novembre 2015
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Novembre 2015
    Messages : 15
    Points : 15
    Points
    15
    Par défaut Recoder la fonction getline
    Bonjour, j'essaye de re-coder la fonction getline et j'aimerais une petite aide à propos d'une partie... Quand j'appelle plusieurs fois ma fonction, mon fonction est lu sauf que si le read = 0 et que je continue à appeler ma fonction, mon programme segfault. Je ne vois pas comment faire ma condition me permettant de sortir de mon programme une fois que le programme a fini de lire toutes les lignes... Si quelqu'un pouvait me donner une idée, ça m'aiderait beaucoup, merci !

    Le code :

    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
     
    char    *get_next_line(const int fd)
    {
      static char   buffer[READ_SIZE];
      static int    i = 0;
      char          *str;
      int           j;
     
      j = 0;
      if ((str = malloc(sizeof(char) * READ_SIZE)) == NULL)
        return (NULL);
      if (read(fd, buffer, READ_SIZE) > 0)
        {
          while (1)
            {
              if (buffer[i] == '\n')
                {
                  i++;
                  return (str);
                }
              if (buffer[i] == '\0')
                {
                  i = 0;
                  str = my_realloc(str, READ_SIZE);
                  if (read(fd, buffer, READ_SIZE) ==  0)
    		{
                      if (str[0] != '\0')
                        return (str);
                      return (NULL);
    		}
                }
              str[j] = buffer[i];
              j = j + 1;
              i = i + 1;
    	}
          free(str);
        }
    }
     
    int     main(int argc, char **argv)
    {
      int   fd;
      if (READ_SIZE == 0)
        return (-1);
      fd = open(argv[1], O_RDONLY);
      printf("%d\n", fd);
      printf("%s\n", get_next_line(fd));
      printf("%s\n", get_next_line(fd));
      printf("%s\n", get_next_line(fd));
    }

  2. #2
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 690
    Points : 30 985
    Points
    30 985
    Billets dans le blog
    1
    Par défaut
    Bonjour

    Me semble que si tu arrives à la fin de ta fonction, faudrait quand-même lui faire renvoyer quelque chose non ???
    Citation Envoyé par SBRKH Voir le message
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
                      if (str[0] != '\0')
                        return (str);
                      return (NULL);
    Bien que ce test s'écrive plus facilement return (str[0] != '\0') ?str :NULL;, je ne vois pas trop pourquoi tu renvoies NULL si ta chaine est vide. Une chaine vide reste une chaine, ce n'est pas NULL. De plus, tu cherches un '\0' dans une zone lue avec read() alors que read() ne te garantit pas qu'il te fournira une chaine donc pas forcément de '\0'...

    Et ça me fait aussi penser que nulle part tu rajoutes de '\0' à ta zone renvoyée ce qui fait que dans ton main, t'as pas le droit de la lire avec "%s" (ce n'est pas une chaine)...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Points : 1 878
    Points
    1 878
    Billets dans le blog
    21
    Par défaut
    Ta signature pour getline() est différente de la fonction originale, qui retourne le nombre de caractères lus afin de dire au client si tu es arrivé à la fin du fichier. La signature de la fonction linux est:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ssize_t getline(char **lineptr, size_t *n, FILE *stream);
    Donc tu renvoies quoiqu'il arrive le nombre de caractères lus (y compris le séparateur mais en excluant EOF) et l'appelant peut écrire:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    while( getline(&mychaine, &already_allocated, stdin) ) {
      printf("La dernière ligne lue est: %s", mychaine);
    }
    free(mychaine);
    Si tu veux conserver ta signature, ce qui n'est à mon avis pas une bonne idée, il faut que tu distingues entre une ligne vide et un signal d'erreur/de fin de fichier.
    ligne vide => str = "" (en fait { \0 }) mais str pointe bien quelque part
    fin de fichier => str = NULL (str pointe à l'adresse 0 du coup)

    Et on peut écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while (const char* line = std::getline(stdin) ) // on s'arrête si line == NULL

  4. #4
    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
    Cette signature semble imposée, voir : http://www.developpez.net/forums/d15...et_next_ligne/ .

  5. #5
    Membre à l'essai
    Homme Profil pro
    Lycéen
    Inscrit en
    Novembre 2015
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Novembre 2015
    Messages : 15
    Points : 15
    Points
    15
    Par défaut
    @Stendhal666 : Bonjour, comme l'a dit Matt Houston, la signature est imposée.

    @Sve@r :
    Me semble que si tu arrives à la fin de ta fonction, faudrait quand-même lui faire renvoyer quelque chose non ???
    Si une des conditions est rempli je return un char*, je renvoie donc quelque chose non?

    Bien que ce test s'écrive plus facilement return (str[0] != '\0') ?str :NULL;, je ne vois pas trop pourquoi tu renvoies NULL si ta chaine est vide. Une chaine vide reste une chaine, ce n'est pas NULL. De plus, tu cherches un '\0' dans une zone lue avec read() alors que read() ne te garantit pas qu'il te fournira une chaine donc pas forcément de '\0'...
    J'ai remplacé le NULL, à la place j'ai fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    if (read(fd, buffer, READ_SIZE) ==  0)
                {
                  if (str[i] != '\0')
                    return (str);
                  *str = '\0';
                  return (str);
                }
    Et ça me fait aussi penser que nulle part tu rajoutes de '\0' à ta zone renvoyée ce qui fait que dans ton main, t'as pas le droit de la lire avec "%s" (ce n'est pas une chaine)...
    Je renvoie des char* qui sont des chaines de caractère d'où le %s..

  6. #6
    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
    Au fait je ne sais pas ce que fait exactement my_realloc mais si c'est un alias de realloc alors ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    str = my_realloc(str, READ_SIZE);
    est doublement erroné :

    • on alloue toujours READ_SIZE, donc la taille du buffer n'est jamais modifiée ;
    • on écrase la valeur de retour, ce qui empêche de détecter une erreur d'allocation.

  7. #7
    Membre à l'essai
    Homme Profil pro
    Lycéen
    Inscrit en
    Novembre 2015
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Novembre 2015
    Messages : 15
    Points : 15
    Points
    15
    Par défaut
    Citation Envoyé par Matt_Houston Voir le message
    Au fait je ne sais pas ce que fait exactement my_realloc mais si c'est un alias de realloc alors ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    str = my_realloc(str, READ_SIZE);
    est doublement erroné :

    • on alloue toujours READ_SIZE, donc la taille du buffer n'est jamais modifiée ;
    • on écrase la valeur de retour, ce qui empêche de détecter une erreur d'allocation.
    Si jamais mon buffer[i] arrive à READ_SIZE et qu'il n'y a toujours pas de '\n', je suis obligé de ré-allouer READ_SIZE pour str non?

  8. #8
    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
    Oui mais l'argument size de realloc détermine la taille totale de la zone allouée, comme malloc, ce n'est pas un offset. Sinon ce serait un ssize_t (signé). Si ta fonction my_realloc a un comportement similaire (ce que je ne puis affirmer à ce stade) alors cet appel est erroné.

    Tu dois conserver la taille courante de ton buffer de destination quelque part et ré-allouer size + READ_SIZE.

  9. #9
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 690
    Points : 30 985
    Points
    30 985
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par SBRKH Voir le message
    Si une des conditions est rempli je return un char*, je renvoie donc quelque chose non?
    Si tu peux garantir que tu passeras fatalement par ce return, alors c'est ok. C'est pas très clair (généralement, même si on quitte au milieu on a quand-même une fin possible en fin de fonction et là, ça manque ce qui oblige à dérouler l'algo pour vérifier qu'on y passe bien quoi qu'il arrive) mais t'as le droit.

    Citation Envoyé par SBRKH Voir le message
    Je renvoie des char* qui sont des chaines de caractère d'où le %s..
    Non, un char* n'est pas une chaine de caractère !!! Un char* est un type prévu pour stocker un pointeur sur un caractère.
    Bien que les chaines de caractères puissent êtres référencées par l'adresse de leur premier élément, adresse qui sera stockée dans un char*, un char* n'est pas une chaine. Ce n'est qu'une adresse qui, peut-être, pointe vers une chaine...

    Autre exemple: tous les chats sont des animaux, mais un animal n'est pas forcément un chat...

    Une chaine, c'est un tableau de caractères contenant un caractère '\0'. Ainsi char toto[]={'H', 'e', 'l', 'l', 'o'} n'est pas une chaine mais char titi[]={'H', 'e', 'l', 'l', 'o', '\0'} en est une. Et cette seconde écriture peut s'écrire plus simplement char titi[]="Hello" (le compilo la remplace alors par la précédente). Et dans tous les cas t'as le droit d'écrire char *pt1=toto; char*pt2=titi;. Mais t'as pas le droit d'utiliser "toto" ou "pt1" comme une chaine (ou de l'envoyer à une fonction qui s'attend à recevoir une chaine) parce que cette fonction parcourra tout le tableau à la recherche d'un '\0' et continuera au delà s'il le faut => comportement indéterminé (généralement le programme crashe mais ce n'est même pas garanti !!!)

    Citation Envoyé par SBRKH Voir le message
    Si jamais mon buffer[i] arrive à READ_SIZE et qu'il n'y a toujours pas de '\n', je suis obligé de ré-allouer READ_SIZE pour str non?
    Non, tu dois agrandir de READ_SIZE, ce n'est pas la même chose. La fonction realloc() de base ne demande pas combien il faut mettre "en plus" mais combien il faut mettre "au total"
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

Discussions similaires

  1. Probléme Fonction Getline()
    Par Sixpounder dans le forum C++Builder
    Réponses: 4
    Dernier message: 02/11/2010, 14h16
  2. La fonction GetLine?
    Par angeless dans le forum C++
    Réponses: 3
    Dernier message: 30/12/2008, 23h56
  3. fonctions getline / rand
    Par john123 dans le forum C
    Réponses: 2
    Dernier message: 13/03/2007, 01h13
  4. recoder la fonction cat
    Par Pitou5464 dans le forum C
    Réponses: 13
    Dernier message: 17/10/2006, 20h22
  5. Problème avec la fonction getline
    Par iamor dans le forum C++
    Réponses: 36
    Dernier message: 11/08/2006, 11h29

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