get_next_line은 반복문 안에서 외부 파일의 내용을 개행문자까지 또는 EOF를 만날때까지 출력하는 함수입니다. 개행문자를 만났다면 해당 라인을 출력하고 다시 get_next_line 함수를 호출하면서 출력한 문자열의 다음 라인부터 출력합니다. 매개변수로 fd(파일디스크립터 값) 를 받습니다. 지역 변수나 매개 변수는 스택 영역에 할당되어집니다. 스택 영역은 함수의 호출과 함께 할당되고, 함수의 호출이 종료되면 소멸합니다.
일단 유효성 검사를 진행합니다. 들어온 fd 가 유효한 fd 인지 (0 미만의 값이면 유효하지 않은 값이라고 인식), 버퍼 사이즈는 유효한지 (0 이하일 경우 유효하지 않은 값으로 인식) 검사를 해준 후, 필요한 만큼의 메모리를 buffer 에 할당해줍니다. 이 버퍼는 read 함수를 이용해 원하는 바이트만큼 fd 를 읽어 줄 임시 버퍼로 사용될 것입니다.
ft_read_line 함수를 통해 read 함수로 읽어 온 문자열을 line 에 저장해줍니다. 이 때의 line 에는 여러 개의 \n 을 포함한 여러 문장이 들어가 있을 것입니다. ft_read_line 이 동작하는 과정은 다음과 같습니다.
우선 무한 반복문을 통해 count 변수에 read 함수가 뱉어낸 값을 저장해줍니다. count 가 -1이라면 fd 를 읽는 과정에서 오류가 났다는 의미이므로 함수를 종료시켜주고, 0이라면 파일의 종료를 의미하는 EOF를 만난 것이므로 반복문을 중단시켜줍니다. 에러가 난 경우에는 line 이 NULL 값을 갖게 되고, EOF 를 만난 경우라면 지금까지 읽어들인 문자열의 값을 갖게 될 것입니다.
count 가 0 초과의 값으로 fd 를 잘 읽어들였다면, 우선 버퍼의 마지막에는 문자열의 끝을 의미하는 \0 값을 넣어줍니다. save 가 NULL 값을 가진다면 fd 에 대해 get_next_line 을 처음 실행한 것이므로 strdup 을 이용해 빈 문자열을 할당해줍니다. 이후 strjoin 을 이용해 buffer 에 저장되어 있는 읽어 온 문자열을 붙여 준 새로운 문자열을 save 에 저장해줍니다. 버퍼에 \n 을 포함하고 있다면 반복문을 중단시키고 save 를 return 해줍니다. \n 을 기준으로 인덱스를 이동시킨 뒤, strdup 으로 한 문장을 제외한 뒷부분을 save 에 저장한 후 line 은 한 문장만을 포함하도록 해준 뒤 본 함수에서 line 을 리턴해줍니다.
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t nbytes);
int fd
읽을 파일의 파일 디스크립터
void *buf
읽어들인 데이터를 저장할 버퍼(배열)
size_t nbytes
읽어들일 데이터의 최대 길이 (buf의 길이보다 길어선 안됨)
return value
읽어들이는 작업에 성공하면 읽어들인 데이터의 길이를 반환하고,
실패하면 -1을 반환하면서 errno를 설정한다.
무조건 nbytes 가 리턴되는 것은 아니다.
반환값이 0인 경우가 있는데, 읽을 바이트가 남아 있지 않다는 뜻이다.
즉, EOF를 만난 경우이다.
EOF와는 달리, len바이트만큼 읽으라고 요청했지만 더 읽을 게 없다면 그건 에러로 취급된다.
다시 말해 사용 가능한 데이터가 없는 것과 파일 끝에 도착한 것은 차이가 있다.
정적변수(static variable)는 프로그램이 종료되기 전까지 메모리가 소멸되지 않는 변수입니다. 함수를 벗어나도 변수가 사라지지 않고 유지되는데, get_next_line 에서는 \n 을 포함한 한 줄을 return 한 뒤에도 읽어들인 문자열을 유지해놓는 변수가 필요하기 때문에 정적 변수의 사용을 필요로 합니다.
정적 변수를 초기화할 때 반드시 상수로 초기화 해야하며, 초깃값을 지정하지 않으면 디폴트값 0으로 자동 초기화 됩니다.
정적변수는 프로그램이 시작될 때 생성 및 초기화 되고 프로그램이 끝날 때 사라집니다.
또한 함수의 매개변수로 사용할 수 없다는 특징이 있습니다.
malloc 함수는 크기가 고정되어 있는 배열과는 달리 변수에 동적으로 메모리를 할당해주는 함수입니다. 동적으로 메모리를 할당하면 사용되지 않는 메모리의 낭비를 줄일 수 있고, 실행중에 필요한 메모리양을 판단해서 할당함으로써 효율적으로 메모리를 관리할 수 있습니다. 단 메모리를 할당하기 위해 malloc 을 이용할 때에 제대로 메모리가 할당되었는지 체크해주는 과정(NULL guard) 이 필요합니다.
동적 메모리를 할당한 메모리를 해제하기 위해 free 함수를 사용하는데, 정적 변수를 사용 시 유의해야 할 점은 free 를 이용해 정적 변수에 할당된 메모리를 해제하려 할 경우 오류가 발생한다는 점입니다.
정적 변수는 컴파일 시에 메모리에 할당되며, 프로그램이 종료 시 메모리가 해제됩니다.
#include <stdio.h>
int test(void)
{
int count = 0;
count++;
return (count);
}
int main()
{
printf("%d\n", test());
printf("%d\n", test());
return (0);
}
위의 코드에서 main() 함수의 printf() 함수로 test() 를 호출할 때에 비로소 count 변수에 대한 메모리가 할당되며 초기화된다는 것입니다.
따라서 이중 포인터가 아닌 static 변수를 사용할 때에, 그 변수를 직접 free 해줄 수는 없습니다.
하나의 정적 변수 사용해서 여러 개의 fd 를 읽어들이는 get_next_line을 구현하면 됩니다.