--- Category : get_next_line Id : 2 Title : "get_next_line : Static" Description : "get_next_line에서 주의할 부분들을 알아보자" Date : 2020, 10, 21 (Wed) Auther : seolim pre : 1 next : 3 tags : get_next_line --- # 2 get_next_line : Static > Link [link not yet]() > Caution 본 문서를 포함한 블로그의 모든 내용은 <b>42 innovation academy</b>의 과제의 작성자의 해석 및 풀이 등으로 이루어져 있습니다.</br>본인이 42 교육생이거나 42 교육을 희망하는 분이라면 글을 먼저 보기보다는 고민해보고 읽어보기를 추천드립니다. > 목적 get_next_line의 구현에 있어 주의해야 할 부분들을 알아보자. ```c int get_next_line(int fd, char **line); ``` > read, offset, static의 연관성 앞서 말했듯이 get_next_line은 정해진 버퍼사이즈가 어떻던간에 한줄씩의 문자열을 읽어야 한다. 한번 아래 코드를 살펴보자. ```c /* * 아래코드는 과제의 정답 코드가 아니다. * EOF에도 동작하지 않고 return 처리도 되어있지 않다. 참고만 하길 바란다. * * file 내용은 아래와 같다고 가정한다. * 1 * 12 * 123 */ void get_next_line(int fd, char **line) { char temp[100]; char buf; int i = 0; int read_size = 1; bzero(temp, 100); while (read(fd, &buf, read_size)) { if (buf == '\n') { *line = strdup(temp); return (1); } temp[i++] = buf; } *line = strdup(""); return (0); } int main() { int fd = open("file_name", O_RDONLY); char *line = NULL; get_next_line(fd, &line); /* line = 1 */ free(line); get_next_line(fd, &line); /* line = 12 */ free(line) } ``` 위 코드는 EOF를 만나기 전까지한줄씩 문자열을 읽는데에 아무런 문제없이 동작한다. 문자를 한개씩 읽기 때문에 개행을 넘어갈 일이 없기 때문이다. 이번엔 아래 코드를 살펴보자 ```c /* * 아래코드는 과제의 정답 코드가 아니다. * EOF에도 동작하지 않고 return 처리도 되어있지 않다. 참고만 하길 바란다. * * file 내용은 아래와 같다고 가정한다. * 1 * 12 * 123 */ void get_next_line(int fd, char **line) { char file[100]; char buf[5]; char *cursor; int i = 0; int read_size = 5; while (read(fd, buf, read_size)) { if ((cusor = memchr(buf, '\n', 5)) { memcpy(file + i, buf, cursor - buf); line = strdup(file); return (1); } memcpy(file + i, buf, 5); i += 5; } *line = strdup(""); return (0); } int main() { int fd = open("file_name", O_RDONLY); char *line = NULL; get_next_line(fd, &line); /* line = 1 */ free(line); get_next_line(fd, &line); /* line = 123 */ free(line) } ``` 위 코드는 read_size를 5로 바꾸었을 뿐이지만 정상적으로 동작하지 않는다. `read`와 file의 offset을 알고있다면 왜 이렇게 동작하는지 알 수 있을것이다. `read`함수는 파일을 읽은만큼 offset을 이동시킨다. 따라서 처음 `get_next_line`이 동작하였을 때, read함수는 파일에서 "1\n12\n"까지 읽어냈기에 descriptor는 이미 그 뒤인 "1"을 가르키고 있게 된다. 따라서 다음 get_next_line은 "123"을 읽어내는 것이다. 아래 그림을 참고하자. ##### TODO : 그림 넣기 위를 해결하기 위해선 2가지 방법이 있을 수 있다. 첫번째는 offset을 매번 제 위치로 돌려놓는 것이고 두번째는 이전에 읽었던 내용을 계속 담고 있는 것이다. 첫번째 방법은 `lseek`를 통해 구현이 가능하나 과제에선 허용되지 않으며 성능도 좋지않다.</br></br>두번째 방법을 위해 static 변수를 활용하는 것이다. 아래 코드를 보자 ```c /* * 아래코드는 과제의 정답 코드가 아니다. * EOF에도 동작하지 않고 return 처리도 되어있지 않다. 참고만 하길 바란다. * * file 내용은 아래와 같다고 가정한다. * 1 * 12 * 123 */ void get_next_line(int fd, char **line) { static char file[100]; //make static char temp[100]; //임시 버퍼, 이미 복사한 파일의 내용을 삭제하기 위함 char buf[5]; char *cursor; int i = 0; int read_size = 5; //읽은 내용에 이미 개행이 존재하면 file을 읽지 않음 if ((cursor = memchr(file, '\n', strlen(file))) { line = strdup(); return (1); } else { while (read(fd, buf, read_size)) { if ((cusor = memchr(buf, '\n', 5)) { memcpy(file + i, buf, cursor - buf); line = strdup(file); // 이미 복사된 내용을 제거하는 코드 memcpy(temp, cursor strlen(cursor)); bzero(file); memcpy(file, temp, strlen(temp)); return (1); } memcpy(str + i, buf, 5); i += 5; } } *line = strdup(""); return (0); } int main() { int fd = open("file_name", O_RDONLY); char *line = NULL; get_next_line(fd, &line); /* line = 1 */ free(line); get_next_line(fd, &line); /* line = 12*/ free(line) } ``` 위코드는 static과 일부 조건만 추가했음에도 정상적으로 동작한다. static으로 선언된 `file`이 프로그램(main)이 종료되기 전까지 저장된 값을 계속 유지한다. 따라서 처음에 "1\n12\n"를 읽고 출력한 "1\n"을 지워두면 두번째 get_next_line이 호출될 때, file에는 "12\n"이 남아있고 원하는 결과를 얻을 수 있게된다.