get_next_line(2) - 줄 바꿈 함수

yeham·2022년 12월 7일
0

42Seoul

목록 보기
4/18
post-thumbnail

들어가기에 앞서

  • 해당 함수를 반복문에서 호출하면, fd의 텍스트를 EOF가 올 때 까지 한번에 한 줄 씩 읽을 수 있는 코드를 작성하는 프로젝트입니다.

  • 함수를 처음 호출했을 때 지정한 버퍼의 크기가 매우 커서 한번에 파일을 끝까지 읽었다 하더라도, 두번째 호출 했을때는 두번째 줄 부터 읽기 시작해야 합니다.

  • file, redirection, stdin으로부터 읽었을 때 함수가 제대로 작동해야합니다.

  • GNL 프로젝트는 open함수로 파일을 열었을 때 받는 파일 디스크럽터(fd)를 사용하여 한 줄씩 line에 저장하는 함수를 구현하면 된다고 할 수 있습니다. (정확한 의미로는 line의 포인터가 한 줄을 가리키게 만들어야 한다는 뜻)

이전에 작성한 사전지식 fd, 정적변수 등을 공부하고 오면 좋습니다.

🖥️ Mandatory

char	*get_next_line(int fd)
{
	char		buf[BUFFER_SIZE + 1];
	char		*line;
	char		*temp2;
	static char	*storage;

	if (fd < 0 || BUFFER_SIZE < 1)
		return (NULL);
	line = line_maker(fd, buf, storage);
	if (line == NULL)
		return (NULL);
	storage = namuji(line);
	temp2 = gnl_strdup(line);
	free(line);
	line = NULL;
	return (temp2);
}

동작하는 큰 틀은 텍스트를 static변수에 저장한 다음 해당 저장내용에 '\n' 개행문자가 있는지 확인하고, 개행문자를 기준으로 개행문자 전까진 출력하고 나머지는 storage에 계속 가지고 있으며 다음 반복문때 다시 접근하여 해당 동작을 파일의 EOF가 나올때까지 반복하는 함수입니다.

read() 함수

size_t read(int fd, void *buf, size_t bytes)
  1. 인자로 받은 bytes의 수 만큼 fd를 읽어 buf에 저장하는 함수
  2. 읽어온 바이트 수를 반환하며, 실패 시 -1을 반환
  3. 파일을 끝까지 읽었다면 다음 번에는 더 이상 읽을 바이트가 없기 때문에 0반환
char	*line_maker(int fd, char *buf, char *storage)
{
	int	r_size;

	r_size = read(fd, buf, BUFFER_SIZE);
	while (r_size > 0)
	{
		buf[r_size] = '\0';
		if (!storage)
			storage = gnl_strdup(buf);
		else
			storage = gnl_strjoin(storage, buf);
		if (storage == NULL)
			return (NULL);
		if (gnl_check(storage) != -1)
			return (storage);
		r_size = read(fd, buf, BUFFER_SIZE);
	}
	return (storage);
}

버퍼 사이즈만큼 읽은것을 buf 변수에 넣고, 해당 문자열을 storage에 계속 넣어줍니다.
그때마다 storage'\n' 개행이 있으면 storage를 리턴하고 앞뒤로 잘라 출력해줍니다.

#include "get_next_line.h"
#include <stdio.h>

int main(void)
{
	char *line; 
	int fd;
    
    fd = open("./test.txt", O_RDONLY);
    
	while(1)
	{
    	line = get_next_line(fd);
        if (line < 1)
        	break ;
		printf("line : %s\n",line);
	}
	return (0);
}

간단하게 출력하는 main문을 짜본다면,
test.txt 파일을 open하여 나온 리턴값을 get_next_line()함수 인자로 넣으면, 해당 txt 파일에 개행을 만나기 전까지의 문자열을 출력합니다.

💻 Bonus

char	*get_next_line(int fd)
{
	char		buf[BUFFER_SIZE + 1];
	char		*line;
	char		*temp2;
	static char	*storage[OPEN_MAX];

	if (fd < 0 || fd > OPEN_MAX || BUFFER_SIZE < 1)
		return (NULL);
	line = line_maker(fd, buf, storage[fd]);
	if (line == 0)
		return (NULL);
	storage[fd] = namuji(line);
	temp2 = gnl_strdup(line);
	free(line);
	line = NULL;
	return (temp2);
}

보너스는 fd를 활용하여 각각의 fd값마다 다른 문자열 배열에 저장하는 방식입니다.

✅ 배운점

이전 포스트와 해당 포스트를 통해 알게된 점은
흔히 리눅스 시스템에서 사용하는 모든 것은 파일이고, 일반적인 파일(Regular File)에서부터 디렉토리(Directory), 소켓(Socket), 파이프(PIPE) 등등 모든 객체들은 파일로써 관리한다는 걸 알게 되었고, 프로세스가 이 파일들을 접근할 때에 파일 디스크립터(fd)라는 개념을 이용한다는걸 배웠습니다.

또한, 프로그램이 운영체제로부터 할당받는 대표적인 메모리 공간코드, 데이터, , 스택 영역이 있다는 사실과

일반적으로 사용하는 지역변수스택영역 // malloc, calloc, new와 같은 동적할당한 변수는 힙영역 // static 정적변수데이터 영역 이라는 메모리 영역에 대해서도 깊게 공부하는 계기가 되었습니다.

코드를 작성하면서는 동적할당을 포함하는 strdup, strjoin등을 많이 활용하였는데 그에따른 동적할당 해제를 하지않아 메모리 누수가 나는 부분에 대해서도 많은 공부가 되었습니다.

https://github.com/zerowin96/my_readline

profile
정통과 / 정처기 & 정통기 / 42seoul 7기 Cardet / 임베디드 SW 개발자

0개의 댓글