La J
La J

Reputation: 55

C - Get next line

( I'm just authorized to use: malloc, free, read)
I'm trying to get the next line in a file with any BUF_SIZE but it's returning me the wrong value.
So, the returned (wrong value, missing firsts chars) value:

3
1 - #include <stdio.h>
1 - dlib.h>
1 - clude "libft/libft.h"
1 - BUFF_SIZE  32

My source code:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include "libft/libft.h"
# define BUFF_SIZE  32

int     get_next_line(int const fd, char **line)
{
    char buffer[BUFF_SIZE + 1];
    size_t i;
    size_t size;

    if (!(*line = malloc(BUFF_SIZE)))
        return (-1);
    *line[0] = '\0';
    while (read(fd, buffer, BUFF_SIZE) > 0)
    {
        buffer[BUFF_SIZE + 1] = '\0';
        if (buffer[0] == '\n')
            return (1);
        if (ft_strchr(buffer, '\n') != NULL)
        {
            i = 0;
            size = ft_strlen(*line);
            buffer[BUFF_SIZE + 1] = '\0';
            while (buffer[i] != '\0')
            {
                if (buffer[i] == '\n')
                {
                    if (!(*line = realloc(*line, i + size)))
                        return (-1);
                    buffer[i] = '\0';
                    ft_strncat(*line, buffer, i);
                    return (1);
                }
                i++;
            }
        }
        if (!(*line = realloc(*line, BUFF_SIZE)))
            return (-1);
        ft_strncat(*line, buffer, BUFF_SIZE);
    }
    return (0);
}

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);
}

Upvotes: 0

Views: 15556

Answers (1)

Schwern
Schwern

Reputation: 164679

I got this to compile by replacing all the ft_blah functions with their string.h equivalents. There are many problems.

Strings in C are null terminated and so need an extra byte allocated to them for that null. If you want to allocate a string of a single character, you have to allocate two bytes.

Next big problem is you keep trying to append to tmp but it only has a single byte allocated. tmp needs to have more memory allocated to it as you go.

On the theme of memory allocation, buffer is never returned so there's no need to allocate memory for it on the heap. It can simply on the stack instead and automatically free'd when the function returns. char buffer[2] = "".

You should be using strncat, not strcpy, to concatenate strings.

It seems ft_strverif just copies the string? I don't know why you call it before calling strcpy which will just copy the string. strcpy(tmp, ft_strverif(buffer)); means buffer is needlessly copied twice. Worse, that extra copy is never free'd so it will leak memory.

I'd suggest eliminating tmp entirely and instead append directly to line. Use realloc to add more memory to line, probably best to add memory in chunks or double it every time for efficiency.

If you're emulating getline note that getline takes the length of the already allocated line buffer for a reason. This lets line be reused in the while(getline...) loop without having to be free'd every loop iteration. In effect, line becomes a reusable buffer.

Finally, always run with -Wall or even -Weverything if your compiler supports it. Fix all the warnings, even if they seem silly. Then, run your code using valgrind, it will tell you when you're using uninitialized memory or where you're leaking memory. Very, very helpful.

Once all that's done, get_next_line becomes much simpler.

int get_next_line(int const fd, char **line)
{
    char buffer[2] = "";

    /* Allocate line memory if needed */
    if( !*line )
        *line = malloc(100 * sizeof(char));

    /* Blank out the line */
    *line[0] = '\0';

    while( read(fd, buffer, 1) > 0 ) {
        strncat(*line, buffer, 1);
        if( buffer[0] == '\n' )
            break;
    }

    return 0;
}

The exercises left for you are...

  • Protect against overflowing line.
  • Don't use a static size for line.
  • Make get_next_line grow line as needed.
  • Let the caller know how large line is (like getline does).

Upvotes: 2

Related Questions