I'm new to C and still don't really know how to work with valgrind. I'm doing a project where i need to create a function that returns a line of text from a file descriptor each time it's called using just one static variable.
Repeated calls (e.g., using a loop) to your get_next_line() function should let
you read the text file pointed to by the file descriptor, one line at a time.
I have come up with this but I can't find where the memory leak is:
char *output(char **backup, char *rbackup, int ret, int fd)
{
int value;
char *temp;
if (ret < 0)
return (NULL);
else if (ret == 0 && backup[fd] == NULL)
return (NULL);
value = (int)(ft_strchr(backup[fd], '\n') - backup[fd] + 1);
rbackup = ft_substr(backup[fd], 0, value);
temp = ft_substr(backup[fd], value, BUFFER_SIZE * BUFFER_SIZE);
free(backup[fd]);
if (temp[0] == '\0')
{
free(temp);
temp = NULL;
}
backup[fd] = temp;
return (rbackup);
}
char *get_next_line(int fd)
{
int ret;
char buf[BUFFER_SIZE + 1];
static char *backup[NUM_OF_FD];
char *rbackup;
if (fd < 0 || fd > NUM_OF_FD)
return (NULL);
while (ft_strchr(backup[fd], '\n') == NULL)
{
ret = read(fd, buf, BUFFER_SIZE);
buf[ret] = '\0';
if (ret <= 0)
break ;
if (backup[fd] == NULL)
backup[fd] = ft_strdup(buf);
else
{
rbackup = ft_strjoin(backup[fd], buf);
free(backup[fd]);
backup[fd] = rbackup;
}
}
return (output(backup, rbackup, ret, fd));
}
The ft_functions are equivalent to the LibC counterparts but in case of having a bug I'll post them here:
void *ft_memcpy(void *dst, const void *src, size_t n)
{
size_t i;
i = -1;
if ((dst != src) && n)
while (++i < n)
((unsigned char *)dst)[i] = ((unsigned char *)src)[i];
return (dst);
}
size_t ft_strlen(const char *s)
{
size_t i;
i = 0;
while (s[i])
{
i++;
}
return (i);
}
char *ft_strchr(const char *s, int c)
{
char chr;
chr = (char)c;
if (s == NULL)
return (NULL);
while (*s && *s != chr)
s++;
if (*s == chr)
return ((char *)s);
else
return (NULL);
}
char *ft_substr(char const *s, unsigned int start, size_t len)
{
char *str;
if (!s)
return (NULL);
if (len > ft_strlen(s))
len = ft_strlen(s);
if (start > ft_strlen(s))
len = 0;
str = malloc(sizeof(char) * (len + 1));
if (!str)
return (NULL);
str = ft_memcpy(str, &s[start], len);
str[len] = '\0';
return (str);
}
char *ft_strdup(const char *s1)
{
size_t len;
void *new;
len = ft_strlen(s1) + 1;
new = malloc(len);
if (new == NULL)
return (NULL);
return ((char *) ft_memcpy(new, s1, len));
}
char *ft_strjoin(char const *s1, char const *s2)
{
int i;
char *str;
size_t size;
if (!s1 || !s2)
return (NULL);
i = 0;
size = (ft_strlen(s1) + ft_strlen(s2) + 1);
str = malloc(sizeof(char) * size);
if (!str)
return (NULL);
while (*s1)
str[i++] = *s1++;
while (*s2)
str[i++] = *s2++;
str[i] = '\0';
return (str);
}
void *ft_memset(void *b, int c, size_t len)
{
size_t i;
i = -1;
while (++i < len)
((unsigned char *)b)[i] = (unsigned char)c;
return (b);
}
Is there any rookie mistake in my code?
Well I ran your code like this
int main(int a, char**b)
{
int f = open("poop.c", O_RDONLY);
for(int i = 0; i < 10; i++)
{
char *x = get_next_line(f);
printf("x");
free(x);
}
}
reading the first 10 lines. No leaks detected by valgrind (once I added the free in the loop)
It did moan about other things though
==3695== Invalid read of size 1
==3695== at 0x109270: ft_memcpy (poop.c:26)
==3695== by 0x1093BB: ft_substr (poop.c:70)
==3695== by 0x109619: output (poop.c:120)
==3695== by 0x109802: get_next_line (poop.c:155)
==3695== by 0x109857: main (poop.c:162)
==3695== Address 0x4a4a0a5 is 0 bytes after a block of size 101 alloc'd
==3695== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==3695== by 0x109408: ft_strdup (poop.c:81)
==3695== by 0x109724: get_next_line (poop.c:147)
==3695== by 0x109857: main (poop.c:162)
==3695==
==3695== Conditional jump or move depends on uninitialised value(s)
==3695== at 0x109546: output (poop.c:114)
==3695== by 0x109802: get_next_line (poop.c:155)
==3695== by 0x109857: main (poop.c:162)
==3695==
==3695== Conditional jump or move depends on uninitialised value(s)
==3695== at 0x109556: output (poop.c:116)
==3695== by 0x109802: get_next_line (poop.c:155)
==3695== by 0x109857: main (poop.c:162)
==3695==
seems like the uninitialized read is caused by reading an empty line.
The invalid read is here
((unsigned char*)dst)[i] = ((unsigned char*)src)[i];
If you have Makefile for the C file, then you can add -g after flags in your Makefile. If you use compile the C file by clang or gcc directly, you can put -g after clang or gcc. Then you can get more information about your problem. -g is used for debugging. If you don't add that, Valgrind will only tell you which part you need to debug (like a specific function). But if you add -g, you will be able to know which line you need to debug with.
You definitely have a problem with:
static char *backup[NUM_OF_FD];
You check that fd is larger than NUM_OF_FD, but NUM_OF_FD would still try to index outside of the backup array.
if (fd < 0 || fd > NUM_OF_FD)
return (NULL);
should be
if (fd < 0 || fd >= NUM_OF_FD)
return (NULL);
Also be aware that read() can return -1, so this code could be problematic:
ret = read(fd, buf, BUFFER_SIZE);
buf[ret] = '\0';
if (ret <= 0)
break ;
Check the return value before using it.
Related
As an exercise i'm writing a C function to read content from a file descriptor one line at a time.
In the exercise i'm only allowed to use read(), malloc() and free() from the standard library, while using one static variable. The function works but i keep getting a persistent memory leak when i reach the last line in the file that i cant seem to solve.
Leak:
Direct leak of 1 byte(s) in 1 object(s) allocated from:
#0 0x7f37f253a4bf in __interceptor_malloc (/usr/lib/gcc/x86_64-pc-linux-gnu/12/libasan.so.8+0xbd4bf)
#1 0x5644d5df4735 in offset /home/practical/Documents/Code/42/get_next_line/get_next_line.c:71
#2 0x5644d5df49ba in get_next_line /home/practical/Documents/Code/42/get_next_line/get_next_line.c:116
#3 0x5644d5df4a8b in main /home/practical/Documents/Code/42/get_next_line/get_next_line.c:138
#4 0x7f37f22cd189 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
SUMMARY: AddressSanitizer: 1 byte(s) leaked in 1 allocation(s).
Code:
#include "get_next_line.h"
#include <stdlib.h>
#include <unistd.h>
// needed for main:
#include <stdio.h>
#include <fcntl.h>
// finds the first line ending in \n from buffer
// this is the line for get_next_line to return
char *next_line(char *a)
{
int i;
char *buf;
if (!a || !a[0])
return (NULL);
i = 0;
while (a[i] && a[i] != '\n')
i++;
if (a[i] == '\n')
i++;
buf = (char *)malloc((sizeof(char) * i) + 1);
if (!buf)
return (NULL);
i = 0;
while (a[i] && a[i] != '\n')
{
buf[i] = a[i];
i++;
}
if (a[i] == '\n')
buf[i++] = '\n';
buf[i] = '\0';
return (buf);
}
// finds the end of the line we just returned in the buffer
// moves it to the end of new buffer
// changes the \n before it to '\0', so our new buffer does not contain it
// this offsets our buffer, the buffer now starts
// at the next line to be printed
char *offset(char *a)
{
char *buf;
int i;
int x;
i = 0;
x = 0;
while (a[i] && a[i] != '\n')
i++;
if (a[i] == '\0')
{
free(a);
return (NULL);
}
if (a[i] == '\n')
i++;
buf = (char *)malloc(ft_strlen(a) - i + 1);
if (!buf)
return (NULL);
while (a[i + x])
{
buf[x] = a[i + x];
x++;
}
buf[x] = '\0';
free(a);
return (buf);
}
// static buffer str starts at the next line to be printed
// we use strchr to find if there is a \n in the buffer
// if theres not, we read from the file into the buffer
// if \n is present, this is the line to print
// next_line then gets the first line ending in '\n' from the static buffer
// we return this line
// then we offset the static buffer by the line we just returned
char *get_next_line(int fd)
{
static char *str;
char *buf;
int i;
if (fd < 0 || BUFFER_SIZE <= 0)
return (NULL);
buf = (char *)malloc((sizeof(char) * BUFFER_SIZE) + 1);
if (!buf)
return (NULL);
i = 1;
while (!(ft_strchr(str, '\n')) && i != 0)
{
i = read(fd, buf, BUFFER_SIZE);
if (i == -1)
{
free(buf);
return (NULL);
}
buf[i] = '\0';
str = ft_strjoin(str, buf);
}
free(buf);
buf = next_line(str);
str = offset(str);
return (buf);
}
int main(int argc, char *argv[])
{
char *line;
int fd;
if (argc < 2)
{
printf("Usage: %s <file>\n", argv[0]);
return (1);
}
fd = open(argv[1], O_RDONLY);
if (fd == -1)
{
perror("Failed to open file");
return (1);
}
while (line != NULL)
{
line = get_next_line(fd);
printf("%s", line);
free(line);
}
close (fd);
return (0);
}
ft_strjoin
char *ft_strdup(char *src)
{
char *dst;
int i;
i = 0;
dst = malloc(ft_strlen(src) + 1);
if (!dst)
return (NULL);
while (src[i])
{
dst[i] = src[i];
i++;
}
dst[i] = '\0';
return (dst);
}
char *ft_strcat(char *dest, char *src)
{
int i;
int l;
i = 0;
l = ft_strlen(dest);
while (src[i] != '\0')
{
dest[i + l] = src[i];
i++;
}
dest[i + l] = '\0';
return (dest);
}
char *ft_strjoin(char const *s1, char const *s2)
{
char *str;
size_t len;
if (!s1 && !s2)
return (ft_strdup(""));
if (s1 && !s2)
return (ft_strdup((char *)s1));
if (!s1 && s2)
return (ft_strdup((char *)s2));
len = ft_strlen((char *)s1) + ft_strlen((char *)s2);
str = malloc(sizeof(char) * (len + 1));
if (!str)
return (NULL);
str[0] = '\0';
ft_strcat(str, (char *)s1);
ft_strcat(str, (char *)s2);
return (str);
}
Problem
I went over the code and it seems that i am freeing everything.
I think the issue may be with returning buf in the get_next_line function, which gets allocated by the next_line function. I cant free this because i am returning it, but i am freeing the string later in the main().
Maybe i should be freeing the static variable after i reach the end of the file i'm reading from the descriptor?
Any suggestions appreciated, thanks
"seems that i am freeing everything" --> code does not free str in get_next_line() when done.
hello guys a just need help on this, not showing the text I wrote:
This program open the file and just show on command what is inside,
if buffer is > 0 show all the text contained in file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
char *ft_strncat(char *dst, const char *src, size_t n)
{
if (n != 0) {
char *d = dst;
const char *s = src;
while (*d != 0)
d++;
do {
if ((*d = *s++) == 0)
break;
d++;
} while (--n != 0);
*d = 0;
}
return (dst);
}
char *get_next_line(int fd)
{
char buffer[2] = "";
char **line;
if( !*line )
*line = malloc(100 * sizeof(char));
*line[0] = '\0';
while( read(fd, buffer, 1) > 0 ) {
ft_strncat(*line, buffer, 1);
if( buffer[0] == '\n' )
break;
}
return (0);
}
int main(void)
{
int fd;
int ret;
fd = open("ola.txt", O_RDONLY);
if (fd < 3 && fd != 0)
return (-1);
printf("%d\n", fd);
printf("%s\n", get_next_line(fd));
return (0);
}
im trying to see the error but I cant, im a noob on C yet
thank you for help me.
line should be char *, not char **. That would only be needed if it were a function parameter that should be updated by the function.
You need to return line from the function, not 0.
You should use realloc() to grow line if the input line is longer than the size of line. Use a variable capacity to hold the current size.
There's no good reason to use ft_strncat(). Use another variable to hold the current position in line, and write the character there directly.
char *get_next_line(int fd)
{
char buffer;
size_t capacity = 100;
char *line = malloc(capacity * sizeof(char));
size_t pos = 0;
*line[0] = '\0';
while( read(fd, &buffer, 1) > 0 ) {
if (pos > capacity - 2) {
capacity += 100;
line = realloc(line, capacity);
}
line[pos++] = buffer;
if( buffer == '\n' ) {
line[pos] = '\0';
break;
}
}
return line;
}
In addition, the caller should assign the result to a variable, so it can free the memory. Otherwise you'll create lots of memory leaks when you read all the lines of the file.
I have to recode an implementation of the getline() function, but using the file descriptor of the file and not a FILE *. I am only allowed to use malloc() and free(), along with 5 functions being 25 lines long at most.
I think I've done correctly the project although I am a beginner in C and my code isn't probably good.
When I run it, it works fine, but valgrind shows that I definetely lost x bytes, x depending of the file length and the READ_SIZE (macro defined in the header).
According to valgrind's --leak-check=full, I have a memory leak in the str_realloc_cat function, when I malloc dest. I tried but couldn't find where should I free / do something else?
Here below is my code:
char *get_next_line(const int fd)
{
static char *remaining = "";
char *buffer;
ssize_t cread;
size_t i;
i = 0;
if (remaining == NULL)
return (NULL);
if ((buffer = malloc(SOF(char) * READ_SIZE + 1)) == NULL ||
(cread = read(fd, buffer, READ_SIZE)) < 0)
return (NULL);
buffer[cread] = 0;
remaining = str_realloc_cat(remaining, buffer);
while (remaining[i])
{
if (remaining[i] == 10)
{
remaining[i] = 0;
buffer = str_create_cpy(remaining);
remaining = remaining + i + 1;
return (buffer);
}
i++;
}
return (check_eof(fd, buffer, remaining, cread));
}
char *str_realloc_cat(char *rem, char *buf)
{
size_t i;
size_t dest_i;
char *dest;
i = (dest_i = 0);
if ((dest = malloc(SOF(char) * (str_len(rem) + str_len(buf) + 1))) == NULL)
return (NULL);
while (rem[i])
{
dest[dest_i] = rem[i];
dest_i++;
i++;
}
i = 0;
while (buf[i])
{
dest[dest_i] = buf[i];
dest_i++;
i++;
}
dest[dest_i] = 0;
free(buf);
return (dest);
}
char *check_eof(const int fd, char *buffer, char *remaining, ssize_t cread)
{
if (cread == 0)
return (NULL);
if (cread < READ_SIZE)
{
buffer = remaining;
remaining = NULL;
return (buffer);
}
return (get_next_line(fd));
}
char *str_create_cpy(const char *src)
{
char *dest;
size_t i;
i = 0;
if ((dest = malloc(sizeof(char) * str_len(src) + 1)) == NULL)
return (NULL);
while (src[i])
{
dest[i] = src[i];
i++;
}
dest[i] = 0;
return (dest);
}
int str_len(const char *str)
{
size_t i;
i = 0;
while (str[i])
i++;
return (i);
}
And a main functon if you would like to test:
#define SOF(x) sizeof(x) // Why in the comments
int main(int ac, char **av)
{
int fd;
char *s;
UNUSED(ac);
if (!av[1])
return 1;
fd = open(av[1], O_RDONLY);
while ((s = get_next_line(fd)))
{
printf("%s\n", s);
free(s);
}
close(fd);
}
Your algorithm is bad:
You keep the buffer in a allocate memory
You don't use a structure to regroup your variable
You use magic number remaining[i] == 10
You use recursive you can stack overflow return get_next_line(fd). Never mind, I didn't read well you have a tail recursive, just be sure to have the optimization on your compile for it.
You have Spaghetti code.
etc.
You should rewrite your whole function with a better logic first use this structure:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define GNL_SIZE 4096
struct gnl_context {
char buffer[GNL_SIZE];
size_t i;
size_t read;
};
char *get_next_line_r(int fd, struct gnl_context *gnl_context);
char *get_next_line(int fd);
static char *read_buffer(struct gnl_context *gnl_context, char *str,
size_t *size) {
size_t i = gnl_context->i;
while (i < gnl_context->read && gnl_context->buffer[i] != '\n') {
i++;
}
size_t j = i - gnl_context->i;
char *ret = realloc(str, *size + j + 1);
if (ret == NULL) {
return NULL;
}
memcpy(ret + *size, gnl_context->buffer + gnl_context->i, j);
*size += j;
ret[*size] = '\0';
gnl_context->i = i;
return ret;
}
char *get_next_line_r(int fd, struct gnl_context *gnl_context) {
char *str = NULL;
size_t size = 0;
loop:
if (gnl_context->i == gnl_context->read) {
ssize_t ret = read(fd, gnl_context->buffer, GNL_SIZE);
if (ret <= 0) {
return str;
}
gnl_context->read = (size_t)ret;
gnl_context->i = 0;
}
char *tmp = read_buffer(gnl_context, str, &size);
if (tmp == NULL) {
return str;
}
if (gnl_context->i != gnl_context->read) {
gnl_context->i++;
return tmp;
}
str = tmp;
goto loop;
}
char *get_next_line(int fd) {
static struct gnl_context gnl_context;
return get_next_line_r(fd, &gnl_context);
}
int main(void) {
char *str;
while ((str = get_next_line(0)) != NULL) {
printf("%s\n", str);
free(str);
}
}
I am concerned about this line:
remaining = remaining + i + 1;
remaining is a pointer to the allocated buffer. On this line, you destroy it, which means that you cannot free() it anymore.
I have to recode an implementation of the getline() function, but using the file descriptor of the file and not a FILE *. I am only allowed to use malloc() and free(), along with 5 functions being 25 lines long at most.
I think I've done correctly the project although I am a beginner in C and my code isn't probably good.
When I run it, it works fine, but valgrind shows that I definetely lost x bytes, x depending of the file length and the READ_SIZE (macro defined in the header).
According to valgrind's --leak-check=full, I have a memory leak in the str_realloc_cat function, when I malloc dest. I tried but couldn't find where should I free / do something else?
Here below is my code:
char *get_next_line(const int fd)
{
static char *remaining = "";
char *buffer;
ssize_t cread;
size_t i;
i = 0;
if (remaining == NULL)
return (NULL);
if ((buffer = malloc(SOF(char) * READ_SIZE + 1)) == NULL ||
(cread = read(fd, buffer, READ_SIZE)) < 0)
return (NULL);
buffer[cread] = 0;
remaining = str_realloc_cat(remaining, buffer);
while (remaining[i])
{
if (remaining[i] == 10)
{
remaining[i] = 0;
buffer = str_create_cpy(remaining);
remaining = remaining + i + 1;
return (buffer);
}
i++;
}
return (check_eof(fd, buffer, remaining, cread));
}
char *str_realloc_cat(char *rem, char *buf)
{
size_t i;
size_t dest_i;
char *dest;
i = (dest_i = 0);
if ((dest = malloc(SOF(char) * (str_len(rem) + str_len(buf) + 1))) == NULL)
return (NULL);
while (rem[i])
{
dest[dest_i] = rem[i];
dest_i++;
i++;
}
i = 0;
while (buf[i])
{
dest[dest_i] = buf[i];
dest_i++;
i++;
}
dest[dest_i] = 0;
free(buf);
return (dest);
}
char *check_eof(const int fd, char *buffer, char *remaining, ssize_t cread)
{
if (cread == 0)
return (NULL);
if (cread < READ_SIZE)
{
buffer = remaining;
remaining = NULL;
return (buffer);
}
return (get_next_line(fd));
}
char *str_create_cpy(const char *src)
{
char *dest;
size_t i;
i = 0;
if ((dest = malloc(sizeof(char) * str_len(src) + 1)) == NULL)
return (NULL);
while (src[i])
{
dest[i] = src[i];
i++;
}
dest[i] = 0;
return (dest);
}
int str_len(const char *str)
{
size_t i;
i = 0;
while (str[i])
i++;
return (i);
}
And a main functon if you would like to test:
#define SOF(x) sizeof(x) // Why in the comments
int main(int ac, char **av)
{
int fd;
char *s;
UNUSED(ac);
if (!av[1])
return 1;
fd = open(av[1], O_RDONLY);
while ((s = get_next_line(fd)))
{
printf("%s\n", s);
free(s);
}
close(fd);
}
Your algorithm is bad:
You keep the buffer in a allocate memory
You don't use a structure to regroup your variable
You use magic number remaining[i] == 10
You use recursive you can stack overflow return get_next_line(fd). Never mind, I didn't read well you have a tail recursive, just be sure to have the optimization on your compile for it.
You have Spaghetti code.
etc.
You should rewrite your whole function with a better logic first use this structure:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define GNL_SIZE 4096
struct gnl_context {
char buffer[GNL_SIZE];
size_t i;
size_t read;
};
char *get_next_line_r(int fd, struct gnl_context *gnl_context);
char *get_next_line(int fd);
static char *read_buffer(struct gnl_context *gnl_context, char *str,
size_t *size) {
size_t i = gnl_context->i;
while (i < gnl_context->read && gnl_context->buffer[i] != '\n') {
i++;
}
size_t j = i - gnl_context->i;
char *ret = realloc(str, *size + j + 1);
if (ret == NULL) {
return NULL;
}
memcpy(ret + *size, gnl_context->buffer + gnl_context->i, j);
*size += j;
ret[*size] = '\0';
gnl_context->i = i;
return ret;
}
char *get_next_line_r(int fd, struct gnl_context *gnl_context) {
char *str = NULL;
size_t size = 0;
loop:
if (gnl_context->i == gnl_context->read) {
ssize_t ret = read(fd, gnl_context->buffer, GNL_SIZE);
if (ret <= 0) {
return str;
}
gnl_context->read = (size_t)ret;
gnl_context->i = 0;
}
char *tmp = read_buffer(gnl_context, str, &size);
if (tmp == NULL) {
return str;
}
if (gnl_context->i != gnl_context->read) {
gnl_context->i++;
return tmp;
}
str = tmp;
goto loop;
}
char *get_next_line(int fd) {
static struct gnl_context gnl_context;
return get_next_line_r(fd, &gnl_context);
}
int main(void) {
char *str;
while ((str = get_next_line(0)) != NULL) {
printf("%s\n", str);
free(str);
}
}
I am concerned about this line:
remaining = remaining + i + 1;
remaining is a pointer to the allocated buffer. On this line, you destroy it, which means that you cannot free() it anymore.
In this function, I have leak of memory
static int read_buffer(int const fd, char **buffer)
{
char buff[BUFF_SIZE + 1];
int ret;
ret = read(fd, buff, BUFF_SIZE);
if (ret > 0)
{
buff[ret] = 0;
if (!(*buffer = ft_strjoin(*buffer, buff)))
return (-1);
}
return (ret);
}
I tried to do this and more solution again.. But I get also leak of memory
static int read_buffer(int const fd, char **buffer)
{
char buff[BUFF_SIZE + 1];
char *tmp;
int ret;
ret = read(fd, buff, BUFF_SIZE);
tmp = *buffer;
if (ret > 0)
{
buff[ret] = 0;
if (!(*buffer = ft_strjoin(*buffer, buff)))
return (-1);
free(tmp);
}
return (ret);
}
Here is ft_strjoin function: (can't modify)
char *ft_strjoin(char const *s1, char const *s2)
{
size_t size_s1;
size_t size_s2;
char *strjoin;
size_s1 = ft_strlen(s1);
size_s2 = ft_strlen(s2);
if (!(strjoin = malloc(size_s1 + size_s2 + 1)))
return (NULL);
ft_strcpy(strjoin, s1);
ft_strcat(strjoin, s2);
return (strjoin);
}
How I can resolve this ?
Thank you !
Anytime a function returns malloc'd memory, you've got a hot potato. You have to free that memory and cannot pass it on unless you've documented you're doing so. And you mustn't lose hold of (e.g. reuse) the pointer before freeing it. Below is how I interpret how read_buffer() needs to work. Since "buffer length is unknown" I'm assuming it comes from malloc and we can use realloc:
static int read_buffer(int const fd, char **buffer)
{
char local_buffer[BUFF_SIZE + 1];
int bytes_read = read(fd, local_buffer, BUFF_SIZE);
if (bytes_read > 0)
{
local_buffer[bytes_read] = '\0';
char *joined = ft_strjoin(*buffer, local_buffer);
if (joined != NULL)
{
*buffer = realloc(*buffer, strlen(joined) + 1);
if (*buffer != NULL)
{
ft_strcpy(*buffer, joined);
}
else
{
bytes_read = -1;
}
free(joined);
}
else {
bytes_read = -1;
}
}
return bytes_read;
}
Note that there are a lot of potential pitfalls that you need to test for and recover from.
If you're reading from the user directly, and don't want newlines as part of the concatenation of strings, you can replace this line:
local_buffer[bytes_read] = '\0';
with something like:
if (local_buffer[bytes_read - 1] == '\n')
{
local_buffer[bytes_read - 1] = '\0';
}
else
{
local_buffer[bytes_read] = '\0';
}
Assuming the above newline fix, here's a small test program I wrote:
int main() {
char *buffer = malloc(1);
*buffer = '\0';
for (int i = 0; i < 3; i++)
{
(void) read_buffer(0, &buffer);
puts(buffer);
}
free(buffer);
return 0;
}
RESULT
> ./a.out
abcdefg
abcdefg
hijklmn
abcdefghijklmn
opqrstu
abcdefghijklmnopqrstu
>