그동안 해왔던 libft주제와는 다른 형식의 주제였기 때문에 get_next_line 주제를 제대로 이해하는데만 시간이 다소 소요되었다. 하지만 주제를 한번 제대로 이해하면, 함수 구현을 하는데는 생각보다 시간이 오래 걸리지 않는다.
int get_next_line(int fd, char **line);
free()를 사용하여, memory leaks나 segmentation fault 오류에 주의 해야함.
static char buf[BUFFER_SIZE + 1]
처음 구현한 알고리즘은 norm 에 맞지 않아, 하기의 코드를 2개의 function으로 나눴다.
1) ft_strchr(cur, '\n)을 찾지 못할때까지 while loop을 반복.
- cur내에 '\n'을 찾지 못할때까지, ft_strjoin()을 사용하여 이전 메모리와 이후의 메모리를 malloc해준다.
- free()를 사용함으로써, memory leaks를 방지한다.
- read_line < 0 : error를 방지한다.
2) 만약, 더이상 읽을 line이 없으면 (== 0 이면), while loop을 나가고, EOF(0)을 리턴해준다.
3) ft_strchr(cur, '\n') : 줄바꿈문자 '\n'을 찾을시,cur의 '\n' 자리에 0을 넣고 malloc을 해준다.
'\n'이 아닌 0을 넣어주면서, cur이 다음 line으로 이동 할 수 있도록 이동한다.
==> 이 경우, 리턴값은 1을 리턴해준다(아직 끝이 나지 않았으므로, 아직 읽어야할 line이 있으므로).
#include "get_next_line.h"
int get_next_line(int fd, char **line)
{
static char buf[BUFFER_SIZE + 1];
static char *cur = NULL;
long read_line;
char *line_cpy;
if (fd < 0 || BUFFER_SIZE <= 0 || !line)
return (GNL_ERROR);
if (!cur) // 1er fois => 처음을 정의 해 주어야함. 아니면, cur이 앞으로 나아가지 못함.
{
read_line = read(fd, buf, BUFFER_SIZE);
if (read_line < 0)
return (GNL_ERROR);
buf[read_line] = 0; // buf의 끝은 0.
cur = buf;
}
*line = ft_strdup("");
// *line = ft_strdup("") 해주는 이유 : 추후 while에 해당하는 첫번째 조건이나, 두번째 조건에 ft_strjoin을 사용하는데,
// 사용해주기 위해서는 메모리를 동적할당 해줄 첫번째 값이 필요함. 첫번째 값은 비어있으므로, ft_strdup("") 값을 넣어줌.
// cur : buf내에서 메모리를 동적할당하면서 (malloc), 이동함.
while (!ft_strchr(cur, '\n')) // 첫번째 condition : '\n'을 찾지 못할때까지,while loop 반복하라.
{
line_cpy = ft_strdup(*line);
free(*line); // line을 free 해주어야 memory leaks이 발생하지 않는다.
*line = ft_strjoin(line_cpy, cur);
free(line_cpy);
read_line = read(fd, buf, BUFFER_SIZE);
if (read_line < 0)
return (GNL_ERROR);
buf[read_line] = 0; // buf 마지막을 = 0 으로 정의 해주어한다. 아닐경우, buf의 마지막이 언젠지 알지 못해 infinite loop이 발생한다.
cur = buf;
if (!read_line) // if read_line == 0 끝이므로, while loop을 나간다.
return (GNL_EOF);
}
//두번째 condition : '\n'을 찾으면, cur의 '\n' 자리에 0을 넣고 malloc을 해준다.
*ft_strchr(cur, '\n') = '\0'; // cur의 '\n' 자리에 0을 넣는다.
line_cpy = ft_strdup(*line);
free(*line); //supprimer line
*line = ft_strjoin(line_cpy, cur);
free(line_cpy);
cur = ft_strchr(cur , '\0') + 1; // cur이 다음 line으로 이동한다.
return (GNL_SUCCESS);
}
size_t ft_strlen(const char *str)
{
int i;
i = 0;
while (str[i])
i++;
return (i);
}
char *ft_strjoin(char *s1, char *s2)
{
char *str;
int i;
int j;
int s1_len;
int s2_len;
if (s1 == 0 || s2 == 0)
return (NULL);
i = 0;
j = 0;
s1_len = (int)ft_strlen(s1);
s2_len = (int)ft_strlen(s2);
str = malloc (s1_len + s2_len + 1);
if (!str)
return (0);
while (i < s1_len)
{
str[i] = s1[i];
i++;
}
while (j < s2_len)
str[i++] = s2[j++];
str[i] = '\0';
return (str);
}
char *ft_strdup(const char *s)
{
size_t len;
size_t i;
char *str;
len = ft_strlen(s);
str = malloc (len + 1);
if (!str)
return (NULL);
i = 0;
while (len--)
str[i++] = *s++;
str[i] = 0;
return (str);
}
char *ft_strchr(const char *str, int c)
{
int i;
i = 0;
while(str[i])
{
if ((char)c == str[i])
{
return ((char *)(str + i));
}
i++;
}
if (c == 0)
return ((char *)(str + i));
return (0);
}
int ac char *av[]
을 사용하여 get_next_line의 메인을 만들었다.
하기와 같이 BUFFER_SIZE를 다르게 정의 하면서 컴파일을 해주었다.
gcc -Wall -Wextra -Werror -D BUFFER_SIZE=12 get_next_line.c get_next_line_utils.c
int main(int ac, char *av[])
{
if (ac != 2)
return (0);
char *line;
int fd = open(av[1], O_RDONLY);
int gnl;
while (1)
{
line = NULL;
gnl = get_next_line(fd, &line);
if (line)
{
printf("%d: %s\n", gnl, line);
free(line);
}
if (!gnl)
break;
}
}
Get_Next_line에 사용된 테스터기 (8개의 테스터를 한번에 사용할수 있다.)
출처 :
https://velog.io/@pawer/getnextline
https://velog.io/@yeunjoo121/ftstrdup