C - Get_next_line

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Hello ! Voilà, je me retrouve avec quelque difficulté en voulant lire ligne par ligne un fichier avec n'importe quelle taille (la valeur de BUFF_SIZE) Donc voici ce que cela me retourne:

1
2
3
4
5
6
7
8
3
1 - #include <stdio.h>
#
1 - include <stdlib.h>
#
1 - include <fcntl.h>
#i
1 - nclude "libft/libft.h"

Donc voilà, ils manquent des caractères à chaque ligne récupérée, pourquoi ? Voici mon code source:

 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
53
54
55
56
57
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include "libft/libft.h"
# define BUFF_SIZE  3

int     get_next_line(int const fd, char **line)
{
    static char *buffer;
    char *tmp;
    int ret;
    char *endl;

    if (!buffer && !(buffer = ft_memalloc(BUFF_SIZE + 1)))
        return (-1);
    tmp = ft_strnew(0);
    endl = ft_strchr(buffer, '\n');
    while (endl == NULL)
    {
        if ((ret = read(fd, buffer, BUFF_SIZE)) > 0)
        {
            buffer[ret] = '\0';
            endl = ft_strchr(buffer, '\n');
            tmp = ft_strjoin(tmp, buffer);
        }
        else if (ret < 0)
            return (-1);
        else if (ret == 0)
        {
            if ((endl = ft_strchr(buffer, '\0')) == buffer)
                return (0);
        }
    }
    *line = ft_strdup(tmp);
    ft_memmove(buffer, endl + 1, ft_strlen(endl + 1) + 1);
    return (1);
}

int     main(void)
{
    int     fd;
    int     ret;
    char    *line;

    if ((fd = open("main.c", O_RDONLY)) < 3 && fd != 0)
        return (-1);
    printf("%d\n", fd);
    ret = get_next_line(fd, &line);
    printf("%d - %s\n", ret, line);
    ret = get_next_line(fd, &line);
    printf("%d - %s\n", ret, line);
    ret = get_next_line(fd, &line);
    printf("%d - %s\n", ret, line);
    ret = get_next_line(fd, &line);
    printf("%d - %s\n", ret, line);
    return (0);
}

Merci d'avance de votre aide ! : )

+0 -0

Salut,
Si tu lis 3 caractères à chaque fois, tu risques d'en lire trop à la fin de la ligne. Déjà, il faudrait donc terminer buffer avant afin de les supprimer.
Ensuite, si tu veux les retrouver au prochain appel, il faut éviter de relire dans buffer depuis le début, ce que tu fais à la ligne 20 (effaçant par-là même les effets du memmove lors de l'appel précédent). Une solution possible serait de commencer par mettre le contenu de buffer dans tmp avant de faire quoi que ce soit…

Auteur du sujet

Merci beaucoup @Lucas-84 ! J'ai réécris mon code, et la sa fonctionne sauf que pour la dernière ligne le programme crash pour tout buffer > 3

Output:

1
2
3
4
5
3
1 - #include <stdio.h>
1 - #include <stdlib.h>
1 - #include <fcntl.h>
crash ..

Mon code:

 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
53
54
55
56
57
58
59
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include "libft/libft.h"
# define BUFF_SIZE  3

int     get_next_line(int const fd, char **line)
{
    static char *buffer;
    char        *tmp;
    char        *endl;
    int         ret;

    if (!buffer && !(buffer = ft_memalloc(BUFF_SIZE + 1)))
        return (-1);
    tmp = ft_strdup(buffer);
    endl = ft_strchr(buffer, '\n');
    while (endl == NULL)
    {
        ret = read(fd, buffer, BUFF_SIZE);
        if (ret < 0)
            return (-1);
        else if (ret == 0)
        {
            if ((endl = ft_strchr(buffer, '\0')) == buffer)
                return (0);
        }
        else if (ret > 0)
        {
            buffer[ret] = '\0';
            endl = ft_strchr(buffer, '\n');
            tmp = ft_strjoin(tmp, buffer);
        }
    }
    tmp[ft_strchr(tmp, '\n') - tmp] = '\0';
    *line = ft_strdup(tmp);
    ft_memmove(buffer, endl + 1, ft_strlen(endl + 1) + 1);
    return (1);
}

int     main(void)
{
    int     fd;
    int     ret;
    char    *line;

    if ((fd = open("main.c", O_RDONLY)) < 3 && fd != 0)
        return (-1);
    printf("%d\n", fd);
    ret = get_next_line(fd, &line);
    printf("%d - %s\n", ret, line);
    ret = get_next_line(fd, &line);
    printf("%d - %s\n", ret, line);
    ret = get_next_line(fd, &line);
    printf("%d - %s\n", ret, line);
    ret = get_next_line(fd, &line);
    printf("%d - %s\n", ret, line);
    return (0);
}

Merci ! :)

+0 -0

Je ne vois pas d'erreur manifeste, mais ça dépend de comment tes fonctions de bibliothèque recodées se comportent. En tout cas, ça fonctionne bien en remplaçant tous les ft_* par leurs équivalents dans la bibliothèque (pseudo)-standard – et en recodant strjoin assez conformément à son nom. valgrind ne me signale rien, si ce n'est des fuites mémoires – si tes fr_strdup/fr_memalloc font des appels cachés à malloc, peut-être penser à free sur tout ça.

Auteur du sujet

Oh oui, j'avais un problème avec ma fonction ft_memmove. Maintenant, avoir découpé ma fonction en deux, j'ai un problème. Je voudrais qu'il retourne val que si endl == NULL:

1
2
3
4
5
6
7
if (val >= 0)
{
    *line = ft_strdup(tmp);
    ft_strcpy(buffer, tmp);
    if (endl)
        return (val);
}

Mais là, le programme crash dès que je rajoute:

1
if (endl)

Mais si je rajoute la condition, le programme me ressort la ligne incomplète, output:

1
2
3
4
5
3
1 - #i
1 - #inc
1 - #inclu
1 - #include

Voici mon code:

 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
53
54
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include "libft/libft.h"
# define BUFF_SIZE  16

int     read_buffer(int const fd, int ret, char **endl, char **buffer, char **tmp)
{
    ret = read(fd, *buffer, BUFF_SIZE);
    (*buffer)[ret] = '\0';
    if (ret == 0)
    {
        if ((*endl = ft_strchr(*buffer, '\0')) == *buffer)
            return (0);
    }
    else if (ret > 0)
    {
        *endl = ft_strchr(*buffer, '\n');
        *tmp = ft_strjoin(*tmp, *buffer);
        return (1);
    }
    return (-1);
}

int     get_next_line(int const fd, char **line)
{
    static char *buffer;
    char        *tmp;
    char        *endl;
    int         ret;
    int         val;

    if (!buffer && !(buffer = ft_memalloc(BUFF_SIZE + 1)))
        return (-1);
    ret = 0;
    tmp = ft_strdup(buffer);
    endl = ft_strchr(buffer, '\n');
    while (endl == NULL && val > 0)
    {
        val = read_buffer(fd, ret, &endl, &buffer, &tmp);
        if (val < 0)
            return (-1);
        if (val >= 0)
        {
            *line = ft_strdup(tmp);
            ft_strcpy(buffer, tmp);
            return (val);
        }
    }
    tmp[ft_strchr(tmp, '\n') - tmp] = '\0';
    *line = ft_strdup(tmp);
    ft_memmove(buffer, endl + 1, ft_strlen(endl));
    return (1);
}

Merci encore ! :)

Édité par jokaymodzz

+0 -0

Mais si endl == NULL, implicitement tu dis « on n'a pas trouvé de '\n'. C'est un peu bizarre pour une fonction qui s'appelle get_next_line de retourner avant la fin de la ligne, non ? (à moins qu'on fixe aussi une taille limite)

Sinon, je pense que tu y verras un peu plus clair dès que tu auras initialisé val (cf. lignes 31 & 38).

Auteur du sujet

La valeur de val ne change rien :/ Je ne sais pas comment faire pour distinguer un fichier une seule ligne donc pas de '\n' et un fichier avec > 1 ligne. Là et mon problème il me faut juste un condition mais laquelle ?.. : /

+0 -0
Auteur du sujet

Dans ta ligne if (val >= 0) tu es sûr d'avoir trouvé ton \n ?

Pouet_forever

Non justement je voudrais qu'il entre dedans que s'il ne trouve pas de '\n' donc !endl && que si il y a qu'une seule ligne dans le fichier, s'il y a +1 ligne dans le fichier alors je voudrais qu'il continu juste à lire grâce à la fonction read_buffer et ensuite qu'il sorte de la boucle mais il ne doit pas aller dans la deuxième condition, mais sa je sais pas comment faire :/

Édité par jokaymodzz

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte