[42서울 / gnl] get_next_line 정리

Hans Park·2021년 6월 29일
0

42서울 본과정

목록 보기
2/15
post-thumbnail

Born to Code

42서울 본과정

토글이 없어 보기 힘듭니다.
노션과 깃 페이지를 남겨두니 참고하세요.

mandatory part와 bonus part 코드가 같음.

노션

🚀 고려사항


  • 서브젝트에 명시되어 있듯이, read함수를 최대한 적게 사용하는 방안으로 모색하였다.
  • 에러 발생시 함수만 멈출지, 데이터들을 원상복구하는지에 대한 고민은 하였다.
    • 에러 발생 시 (malloc 실패 등), 함수를 호출하기 이전으로 원상복구하는 방향으로 하였다.

🖋 문제해결순서

  1. 이전에 받아둔 문자열에 \n 확인.
    1. 있다면, 해당 문자열을 조작하고 1 반환.
  2. read함수를 사용하여 BUFFER_SIZE만큼 읽어오기
  3. 문자열을 저장하는 문자열에 strjoin을 사용하여 저장.
  4. 해당 문자열에 \n이 있는지 확인.
    1. 있다면, 해당 문자열을 조작하고 1 반환.
    2. 없다면, 2번으로
  5. read함수가 EOF를 만나면, 저장되어 있는 문자열 확인 후 1 반환.

🖋 하나의 정적변수만 사용할 것.

  • 하나의 정적변수를 사용할 수 있게 문자열 하나로 관리함.
  • 문자열 하나만 사용하기 위해 문자열을 조작하는 각종 util 함수들을 사용
    • char *ft_strndup(const char *s1, size_t n)
    • char *ft_strjoin(char const *s1, char const *s2)

🖋 다중 파일 디스크립터를 관리할 수 있을 것.

  • 파일 디스크립트마다 문자열을 저장하기 위해 정적변수를 배열화 함.
    static char *storage[OPEN_MAX]
    이때, OPEN_MAXlimit.h에서 가져옴. (컴파일러, os마다 값이 다르기 때문)

🚀 get_next_line


구현방법은 정말 여러가지입니다. 참고용으로만 보시길 바랍니다.

🖋 get_next_line (메인함수)

  • 코드참고

    int			get_next_line(int fd, char **line)
    {
    	static char *storage[OPEN_MAX];
    	char		str_buffer[BUFFER_SIZE + 1];
    	size_t		read_size;
    	int			return_val;
    
    	if (read(fd, str_buffer, 0) == -1 || !line || BUFFER_SIZE <= 0)
    		return (-1);
    	if (ft_strchr(storage[fd], '\n'))
    		return (cut_new_line(&storage[fd], line));
    	while ((read_size = read(fd, str_buffer, BUFFER_SIZE)) > 0)
    	{
    		str_buffer[read_size] = 0;
    		storage[fd] = ft_strjoin(storage[fd], str_buffer);
    		if (ft_strchr(storage[fd], '\n'))
    			return (cut_new_line(&storage[fd], line));
    	}
    	return_val = cut_new_line(&storage[fd], line);
    	if (return_val == 1)
    		return (0);
    	return (return_val);
    }
if (read(fd, str_buffer, 0) == -1 || !line || BUFFER_SIZE <= 0)
  1. 해당 fd, 혹은 read함수에 문제가 있거나, 문자열의 주소값을 저장할 line이 할당되어있지 않거나, BUFFER_SIZE가 양수가 아닐 경우 에러라 판단하고 -1을 리턴함.
if (ft_strchr(storage[fd], '\n')) 
{ return (cut_new_line(&storage[fd], line)); }
  1. storage[fd] 변수에 개행이 있다면, read함수를 호출하지 않고 바로 문자열 처리함.
str_buffer[read_size] = 0;
storage[fd] = ft_strjoin(storage[fd], str_buffer);
  1. 받아온 문자열 마지막에 널을 넣어주고, storage 변수에 저장되어 있는 문자열 뒤에 합침.
return_val = cut_new_line(&storage[fd], line);
if (return_val == 1)
    return (0);
  1. while문에서 탈출했다는 것은, read함수가 EOF를 만났고, 저장된 문자열에 \n이 없음을 의미함.
    따라서, 다시 한번 cut_new_line을 호출하여 문자열 처리함.
    또한 EOF를 만났으므로 0을 반환할 수 있게 함.

🖋 cut_new_line (문자열 처리 함수)

  • 코드참고

    static	int	cut_new_line(char **buf, char **line)
    {
    	char	*patrol;
    	char	*temp;
    
    	if (!buf || !*buf)
    	{
    		*line = ft_strndup("", 0);
    		return ((*line != 0) ? 0 : -1);
    	}
    	patrol = ft_strchr(*buf, '\n');
    	if (!patrol)
    	{
    		*line = *buf;
    		*buf = 0;
    		return (1);
    	}
    	if (!(*line = ft_strndup(*buf, patrol - *buf)))
    		return (-1);
    	if (!(temp = ft_strndup(patrol + 1, ft_strlen(patrol + 1))))
    	{
    		free(*line);
    		return (-1);
    	}
    	free(*buf);
    	*buf = temp;
    	return (1);
    }
patrol = ft_strchr(*buf, '\n')
if (!patrol)
{
    *line = *buf;
    *buf = 0;
    return (1);
}
  1. patrol 변수는 buf 문자열에서 개행을 찾는 변수임.
  2. patrol이 null이라는 뜻은, 해당 문자열에 널이 없다는 것을 의미함.
  3. 이때, cut_new_line함수는 read함수가 EOF를 만나지 않는 이상 \n이 있을 때만 함수가 호출됨, 즉 현재 EOF를 만났고, 문자열에 \n이 없다는 뜻이 됨.
  4. 따라서, buf문자열 전부를 line에 넣어주고, buf에는 0을 넣어둠.

🖋 ft_strndup (문자열 복제)

char	*ft_strndup(const char *s1, size_t n)
{
	size_t	i;
	char	*ptr;

	i = 0;
	ptr = malloc(sizeof(char) * (n + 1));
	if (!ptr)
		return (0);
	while (i < n)
	{
		ptr[i] = s1[i];
		i++;
	}
	ptr[i] = 0;
	return (ptr);
}
  • s1문자열에서 일부분만 복제하기 위해 n 매개변수를 추가함.

🖋 ft_strjoin (문자열 합체)

char	*ft_strjoin(char const *s1, char const *s2)
{
	size_t	s1_len;
	size_t	s2_len;
	char	*ptr;

	if (!s1 && !s2)
		return (0);
	if (!s1)
		return (ft_strndup(s2, ft_strlen(s2)));
	else if (!s2)
		return (ft_strndup(s1, ft_strlen(s1)));
	s1_len = ft_strlen(s1);
	s2_len = ft_strlen(s2);
	if (!(ptr = (char *)malloc(sizeof(char) * (s1_len + s2_len + 1))))
		return (0);
	ft_strlcpy(ptr, s1, s1_len + 1);
	free((void *)s1);
	ft_strlcpy(ptr + s1_len, (char *)s2, s2_len + 1);
	return (ptr);
}
  • get_next_line함수에서 s1변수에 반환값을 저장하므로, 반환 전 s1의 할당된 메모리를 free해야 함.

🚀 get_next_line 코드 전문

  • velog에서 삭제합니다. 노션과 깃을 참고하세요.
profile
장안동 개발새발

0개의 댓글