[42Seoul] get_next_line

jiyseo·2022년 4월 19일
0

42 Seoul

목록 보기
5/9

과제를 시작하기 전 ..

  • 파일 디스크립터 (fd)

    1. 운영체제가 파일 또는 하드웨어와 통신을 하기 위해 부여하는 숫자

    2. 파일 디스크립터는 0,1,2 순으로 숫자 부여, 0,1,2는 이미 사용중이기 때문에 3부터 파일 디스크립터를 부여함

      • 0 : 표준 입력

      • 1 : 표준 출력

      • 2 : 표준 에러

    3. open() 함수는 파일을 열고 파일 디스크립터 값을 반환. 그 값을 이용하여 이후에도 계속해서 그 열었던 파일에 접근할 수 있다.

  • read() 함수

size_t read(int fd, void *buf, size_t bytes)

  1. 인자로 받은 bytes의 수 만큼 fd를 읽어 buf에 저장하는 함수
  2. 읽어온 바이트 수를 반환하며 실패 시 -1을 반환
  3. 파일을 끝까지 읽었다면 다음 번에는 더 이상 읽을 바이트가 없기 때문에 0반환
  • static 변수 (정적 변수)
    1. 변수를 선언할 때 static키워드를 붙여 선언한다. static int num
    2. 메모리의 데이터 영역에 저장되어 프로그램이 종료될 때까지 남아있는 변수
    3. 함수를 벗어나도 해당 변수는 사라지지 않고 계속 유지 하지만 함수 내부에서 선언되었다면 다른 함수에서는 이 값을 참조할 수 없다. 또한 함수의 시작이 아닌 프로그램의 시작 시 할당이 되며, 프로그램이 종료될 때 해제됨
    4. 함수 내에서 static int num = 0 식으로 초기화하면 프로그램이 시작될 때 변수를 초기화하며, 함수가 호출될 때는 변수를 초기화하지 않는다. (여러번 함수를 실행하더라도 그 변수가 또 초기화되지 않는다.)
    5. 정적 변수는 초기값을 지정하지 않으면 0으로 알아서 초기화된다.
    6. 이번 과제에서는 다음 line을 읽을 시작 주소를 계속 저장할 수 있도록 백업 버퍼를 만들어 static 변수로 선언해야 한다.
    7. 위키디피아의 정적변수 설명
  • gcc의 -d 플래그
    1. 프로그램 외부에서 #define을 정의하여 컴파일 시 반영할 수 있다.

    2. 이 과제에서 채점 시 컴파일은 다음과 같이 진행한다.

      $ gcc -Wall -Wextra -Werror -D BUFFER_SIZE=32 get_next_line.c get_next_line_utils.c
    3. 즉 컴파일 할 때 BUFFER_SIZE를 정하고 이 버퍼의 크기만큼 파일을 한 번에 읽게 된다.

  • 과제의 목표
    1. GNL 함수를 반복문 안에서 호출하면, fd의 텍스트를 EOF가 올 때까지 한 번에 한 줄씩 읽을 수 있다.
    2. GNL 함수를 처음 호출했을 때 지정한 버퍼의 크기가 매우 커서 한 번에 파일을 끝까지 읽었다 하더라도 두 번째 호출했을 때는 두 번째 줄부터 읽기를 시작해야한다.
    3. file, redirection, stdin으로부터 읽었을 때 함수가 제대로 작동해야한다.
    4. gcc -d 플래그로 받을 BUFFER_SIZE가 1일 때, 9999일 때, 10000000일 때도 함수가 제대로 작동해야한다
    5. GNL 프로젝트는 open함수로 파일을 열었을 때 받는 파일 디스크럽터(fd)를 사용하여 한 줄씩 line에 저장하는 함수를 구현하면 된다고 할 수 있다. (정확한 의미로는 line의 포인터가 한 줄을 가리키게 만들어야 한다는 뜻)

static 변수

  • static 변수를 한 줄로 요약하자면, 지역변수와 전역변수 둘의 성질을 같이 가지고 있다고 생각하면 된다.
    • static 변수는 지역변수와 같이 선언된 함수 내에서만 사용이 가능하다.
    • 그러나 한 번만 초기화하며, 전역 변수처럼 프로그램이 종료될 때까지 메모리 공간에 존재한다.
    • 지역 변수와는 달리, 해당 함수가 종료되거나 반환을 하더라도 소멸되지 않는다.
  • 변수를 선언할 때 static 키워드를 붙여 선언한다. static int num
  • 메모리의 데이터 영역에 저장되어 프로그램이 종료될 때까지 남아있는 변수다.
  • 함수를 벗어나도 해당 변수는 사라지지 않고 계속 유지된다. 하지만 함수 내부에서 선언되었다면, 다른 함수에서는 이 값을 참조할 수 없다. 또한 함수의 시작이 아닌 프로그램의 시작 시 할당이 되며, 프로그램이 종료될 때 해제된다.
  • 일반 지역 변수가 할당되는 stack 부분이 아니라 data 부분에 할당된다.
  • 함수 내에서 static int num = 0 식으로 초기화하면 프로그램이 시작될 때 변수를 초기화하며, 함수가 호출될 때는 변수를 초기화하지 않는다. (여러 번 함수를 실행하더라도 그 변수가 또 초기화되지 않는다)
  • 정적 변수는 초깃값을 지정하지 않으면 0으로 알아서 초기화된다. 구조체를 static으로 선언한 경우 그 안의 멤버변수들이 0으로 초기화된다. (지역 변수는 초기화하지 않으면 쓰레기값으로 초기화된다.)

Logic

  1. 우선 파일을 read 및 저장, 반환값을 저장할 수 있도록 구조체를 만든다.
typedef struct s_buffer
{
	char	*buf;
	size_t	pos;
	size_t	size;
}	t_buffer;

typedef t_buffer	t_line_buffer;
typedef t_buffer	t_read_buffer;
  1. 파일을 읽는 read하고 저장할 static 구조체를 선언한다.
static t_read_buffer	rb[OPEN_MAX];
  1. read한 char를 ‘\n’ 문자가 나올 때까지 저장 후 리턴할 구조체를 만든다.
t_line_buffer			lb;
  1. read(fd, buf, BUFFER_SIZE); 를 해서 버퍼만큼 라인을 읽는다. 그리고 read buffer의 buf에 저장한다.
read(fd, buf, BUFFER_SIZE);
// fd = 파일 디스크립터
// buf = 파일을 읽어들일 버퍼
// BUFFER_SIZE = 버퍼의 크기
// return 값 = 수신한 바이트 수, 실패 시 -1
  1. read buffer의 buf에서 한 글자씩 개행문자가 있는지 확인한다.
  2. 개행문자가 없다면 읽은 한 문자를 line buffer에 넣어준다. 개행문자가 있거나 파일의 끝인 경우애는 line 버퍼에 넣어주는 것을 멈추고 이 과정을 멈춘다.
  3. BUFFER_SIZE보다 큰 길이의 파일이 들어온 경우에는 다시 read를 하여 read buffer를 덮어씌우고 위의 과정을 이어간다.
  4. 함수를 다시 호출한 경우 static 변수인 rb에 의해 저장되어있던 곳부터 다시 시작한다.
profile
코딩뿡뿡이

0개의 댓글