`fgets` 함수

fgets 함수 (fgets)

파일에서 한 줄씩 읽는 건 정말 자주 하는 일이에요. fgets는 그 작업을 버퍼 오버플로 걱정 없이 안전하게 해 주는 함수예요. 줄 단위가 아니라 "최대 몇 글자까지"라는 단위로 동작해서, 내가 준 버퍼 크기를 넘지 않는 선에서 읽도록 설계되어 있어요.

출처: cppreference

본문

함수 원형

<stdio.h>에 정의돼 있어요.

char* fgets( char* str, int count, FILE* stream );                   // (until C99)
char* fgets( char* restrict str, int count, FILE* restrict stream ); // (since C99)

설명 (Explanation)

주어진 파일 스트림에서 최대 count - 1개의 문자를 읽어 str이 가리키는 문자 배열에 저장해요. 개행 문자를 만나면 그 지점에서 파싱을 멈추는데, 이때 str에는 그 개행 문자까지 포함돼요. 파일 끝(end-of-file)에 도달해도 멈춰요. 바이트가 읽히고 오류가 없다면, str에 마지막으로 쓰인 문자 바로 뒤에 널 문자('\0')를 기록해요.

매개변수 (Parameters)

  • str — char 배열의 한 요소를 가리키는 포인터
  • count — 쓸 최대 문자 수(보통 str의 길이)
  • stream — 데이터를 읽어올 파일 스트림

반환값 (Return value)

성공하면 str을, 실패하면 널 포인터를 돌려줘요.

파일 끝 조건을 만난 경우 stream에 eof 표시를 설정해요(feof() 참고). 이때 아무 바이트도 읽지 못했다면 실패로 처리되어 널 포인터를 돌려주고, str이 가리키는 배열의 내용은 바뀌지 않아요(즉 첫 바이트가 널 문자로 덮이지 않아요).

다른 오류로 실패했다면 stream에 오류 표시를 설정해요(ferror() 참고). 이 경우 str이 가리키는 배열의 내용은 불확정(indeterminate)이에요(널 종료조차 안 되어 있을 수 있어요).

주의할 점 (Notes)

POSIX는 읽기 오류가 발생하면 fgetserrno를 설정하도록 추가로 요구해요.

표준 명세가 count <= 1인 경우를 명확히 다루지 않아서 구현마다 다를 수 있는데, 흔한 구현은 이러합니다.

  • count < 1: 아무것도 하지 않고 오류로 보고
  • count == 1: 어떤 구현은 아무것도 하지 않고 오류로 보고, 다른 구현은 아무것도 읽지 않고 str[0]에 0을 저장한 뒤 성공으로 보고

예제 (Example)

임시 파일에 몇 줄을 써 두고, 작은 버퍼(char buf[8])로 옮겨 읽으면서 버퍼 크기만큼 잘려 나가는 모습을 보여 줘요.

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE* tmpf = tmpfile();
    fputs("Alan Turing\n", tmpf);
    fputs("John von Neumann\n", tmpf);
    fputs("Alonzo Church\n", tmpf);
    rewind(tmpf);

    char buf[8];
    while (fgets(buf, sizeof buf, tmpf) != NULL)
          printf("\"%s\"\n", buf);

    if (feof(tmpf))
       puts("End of file reached");
}

출력:

"Alan Tu"
"ring
"
"John vo"
"n Neuma"
"nn
"
"Alonzo "
"Church
"
End of file reached

버퍼가 8바이트라서 count - 1인 7글자씩 끊겨 읽히는 걸 볼 수 있어요. 마지막에 feof로 파일 끝까지 읽었는지 확인하는 게 이 함수 사용의 정석이에요.

같이 보기 (See also)

  • scanf/fscanf/sscanf — 서식 입력
  • fputs — 파일 스트림에 문자열 쓰기