[gnl] get_next_line - 배열
get_next_line 구성
get_next_line 과제에서는 총 세가지 파일을 제출해야한다.
get_next_line.c
, get_next_line_utils.c
, get_next_line.h
.
libft를 사용할 수 없는 대신 _utils.c
가 허용되어 총 10개의 함수를 사용할 수 있다.
배열을 이용하여 기능을 구현하였으며, 사용한 함수들은 다음과 같다.
char *get_next_line(int fd)
static char *check_remain(int fd, char *remain)
static char *make_next_line(char *remain)
static char *update_remain(char *remain)
size_t ft_strlen(const char *str);
char *ft_strchr(const char *str, int c);
size_t ft_strlcpy(char *dst, char *src, size_t size);
char *ft_strdup(const char *src);
char *ft_strjoin(char const *str1, char const *str2);
코드 분석
get_next_line 함수
char *get_next_line(int fd)
{
static char *remain = NULL;
char *next_line;
if (fd < 0 || BUFFER_SIZE <= 0)
return (NULL);
remain = check_remain(fd, remain);
if (!remain)
return (NULL);
next_line = make_next_line(remain);
remain = update_remain(remain);
return (next_line);
}
메인에서 직접 호출될 함수로, 이곳에서 정적 변수를 선언하여 써먹게된다.
static char *remain
: 파일 디스크립터를read
함수로 읽은 후 남은 문자열이라는 의미로remain
이라는 이름을 붙였다.char *next_line
: 함수의 반환 목표로써, 출력할 한 줄의 문자열이다.
get_next_line
함수의 작동과정은 다음과 같다.
- 인자로 받아온
fd
값과, 컴파일시-D
옵션으로 지정한 변수BUFFER_SIZE
의 값을 체크한다.fd < 0
이거나BUFFER_SIZE <= 0
이라면 정상적인 입력이 아니므로NULL
을 리턴한다. check_remain
함수를 통해remain
에 문자열이 남아있는지 체크한다.remain
이 없다면NULL
을 리턴한다.- 있다면
make_next_line
함수를 통해remain
에 남아있는 문자열에서\n
까지의 한 줄을 읽어next_line
변수에 저장한다. update_remain
함수를 통해next_line
으로 저장할 한 줄을 빼고 나머지를remain
으로 저장한다.next_line
을 리턴한다.
check_remain 함수
static char *check_remain(int fd, char *remain)
{
char *buff;
char *temp;
int read_idx;
buff = (char *)malloc((BUFFER_SIZE + 1) * sizeof(char));
while (!remain || !ft_strchr(remain, '\n'))
{
read_idx = read(fd, buff, BUFFER_SIZE);
if (read_idx <= 0)
break ;
buff[read_idx] = '\0';
if (!remain)
remain = ft_strdup(buff);
else
{
temp = ft_strjoin(remain, buff);
free(remain);
remain = temp;
}
}
free(buff);
return (remain);
}
fd
에서 데이터를 읽어들여 정적 변수 remain
에 저장하는 함수다.
check_remain
함수의 작동과정은 다음과 같다.
- 변수
buff
를BUFFER_SIZE + 1
(\0
문자가 들어갈 공간)만큼 할당한다. remain
이 없거나,remain
에 남아있는 문자열에\n
이 없을 경우 반복문으로 들어간다.read
함수로fd
에서BUFFER_SIZE
바이트만큼 데이터를 읽어와buff
에 저장한다.
이 때read
함수의 반환값은 정상적으로 읽어들인 바이트의 크기가 된다.
이를read_idx
변수에 저장해 0보다 작으면fd
에 해당하는 파일을 끝까지 읽은것이므로 반복문을 빠져나와 파일 읽기를 멈춘다.- 그렇지 않으면 읽어낸 데이터를 다루기 위해
buff[read_idx]
, 즉buff
의 마지막에\0
을 넣어준다. - 만약
remain
이 빈 상태였다면ft_strdup
함수를 이용해remain
에 새롭게 메모리를 할당하며buff
를 복사해준다. remain
에 남아있는 데이터가 있었다면ft_strjoin
함수를 이용해remain
뒤에buff
를 붙인 새로운 문자열을 할당한다.- 이 때
ft_strjoin
함수로 반환되는 문자열은 기존의remain
과 다른 메모리를 가지고 있으므로, 메모리 누수를 피하기 위해서 기존remain
의 메모리를 해제한 후 새롭게 만든 메모리로 연결시켜주어야 한다.
- 이 때
remain
에서\n
을 찾을 수 있을 때까지 위 과정을 반복한다. 물론 중간의 탈출조건으로 반복문을 빠져나올 수도 있다.- 역할이 끝난
buff
의 메모리를 해제한 후,remain
을 반환한다.
이 결과 만들어지는 remain
은 셋 중 하나이다.
\n
이 반드시 하나 이상 포함되어있는 문자열\n
이 없고,EOF
에 도달한 문자열NULL
(처음부터remain
이 비어있었고,read
함수로 읽어올 데이터도 남아있지 않았을 경우)
make_next_line 함수
static char *make_next_line(char *remain)
{
char *next_line;
int len;
len = 0;
while (*(remain + len))
{
if (*(remain + len++) == '\n')
break ;
}
next_line = (char *)malloc((len + 1) * sizeof(char));
ft_strlcpy(next_line, remain, len + 1);
return (next_line);
}
remain
에서 \n
을 포함한 한 줄의 문자열을 뽑아내는 함수다.
make_next_line
함수의 작동과정은 다음과 같다.
remain
을 읽으면서next_line
에 할당할 길이를 잰다.\n
가 있다면 거기서 멈추고, 없다면remain
의 끝까지 잰다.\n
가 없는 경우는 파일을 끝까지 읽은 것이다.- 잰 길이로
next_line
에 메모리를 할당한다. ft_strlcpy
함수를 이용해next_line
에remain
의 문자열을 길이만큼 복사하고 마지막에\0
을 넣는다.- 만들어진
next_line
을 반환한다.
update_remain 함수
static char *update_remain(char *remain)
{
char *temp;
char *fix_remain;
fix_remain = ft_strchr(remain, '\n');
if (!fix_remain)
{
free(remain);
return (NULL);
}
temp = (char *)malloc(ft_strlen(fix_remain) * sizeof(char));
if (!ft_strlcpy(temp, fix_remain + 1, ft_strlen(fix_remain)))
{
free(temp);
free(remain);
return (NULL);
}
free(remain);
return (temp);
}
remian
에서 next_line
으로 출력할 문자열을 빼는 함수다.
update_remain
함수의 작동과정은 다음과 같다.
ft_strchr
함수를 이용해remain
에서\n
의 위치를 찾아fix_remain
변수에 저장한다.- 찾을 수 없다면(
fix_remain == NULL
) 파일을 끝까지 읽은 경우이다. 더이상remain
을 남길 이유가 없으니 메모리를 해제한 후NULL
을 반환한다. - 찾은 경우엔 남은 부분을 저장할 메모리를 새롭게 할당한다.
ft_strlcpy
함수를 통해 새로 할당한 메모리에\n
뒷부분을 복사한다.
복사할 데이터가 없어ft_strlcpy
함수의 반환값이 0이었다면BUFFER_SIZE
만큼 읽어들였을 때 우연히\n
로 끝나거나, 혹은 읽어들인 파일 자체가\n
으로 끝나는 경우이다. 어느 쪽이든remain
에 남길 데이터가 없으므로 새로 할당한 메모리와remain
의 메모리를 해제 후NULL
을 반환한다.- 복사한 데이터가 있다면 기존의
remain
은 해제하고, 새로 만들어진 문자열을 반환한다.