티스토리 뷰

C언어를 배워보셨으면 fflush()라는 함수를 한 번쯤은 써본 경험이 있으실 겁니다. 문제는 우리나라에서 C언어의 바이블이라고 불리는 베스트셀러에서 fflush()를 잘못된 방법으로 사용하고 있어서 그 책으로 입문하는 경우, fflush()의 사용법을 잘못 배우는 경우가 많습니다.


매뉴얼에서 fflush()와 정의와 설명을 찾아보면


int fflush(FILE *stream)



라 정의돼 있고 "C 라이브러리 함수로서 출력 버퍼를 비운다."라고 돼 있습니다. 그리고 정의를 살펴보면 FILE 포인터인 스트림을 매개변수로 받는다는 것을 알 수 있습니다. 이 글은 fflush의 상세한 설명보다는 잘못된 방법으로 사용하고 있는 것을 교정하기 위한 글이므로 그 외의 내용은 매뉴얼을 참조하시기 바랍니다.


여기서 중요한 것은 바로 출력 버퍼를 비운다는 것입니다. 다시 말하겠습니다. 입력 버퍼가 아닌 출력 버퍼를 비웁니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
 
int main(void) {
    int total = 0;    // 문자의 수를 저장하는 변수
    char ch;
 
    whiile (1) {
        fputs("Data input (EOF to exit) : ", stdout);
        if ((ch = getchar()) == EOF)    // 값을 입력받고, 만약 그 값이 EOF라면
            break;                      // while문을 빠져나간다.
 
        fflush(stdin);                    // fflush()의 잘못된 
        total++;
    }
 
    printf("입력된 문자의 수 : %d\n", total);
    
    return 0;
}
cs


위 프로그램은 EOF가 입력될 때까지 문자를 입력받고 EOF가 입력되면 지금까지 입력된 문자의 수를 출력합니다.


먼저 9라인을 보면 문자를 입력받기 위해 getchar()을 사용하는 것을 볼 수 있는데 scanf()는 지정 문자(%c, %d 등)에 따라 화이트 스페이스(띄어쓰기, 줄바꿈 등)를 무시하는 반면, getchar()은 모든 문자를 읽어들입니다. 그래서 만약 C를 입력하고 엔터를 눌렀다면 처음엔 C가 입력될테지만 그 다음 반복에서 아무 문자를 입력하지 않았음에도 불구하고 엔터를 누르면서 입력된 줄바꿈 문자가 자동으로 입력돼, 원했던 결과와는 조금 다르게 흘러갈 것입니다.


이 문제를 해결하기 위해서는 입력 버퍼를 비워줘야 하는데 12라인을 보면 입력 버퍼를 비우기 위해 fflush() 함수를 사용하는 것을 볼 수 있습니다. 이런 식으로 입력 버퍼를 비우는 분들이 꽤 많으실 거라 생각되는데 이는 잘못된 방법입니다. 위에 fflush() 함수의 정의에서 말했듯이 fflush() 함수가 비우는 건 입력 버퍼가 아닌 출력 버퍼입니다. 그런데 위 프로그램에서는 stdin 즉, 표준 입력 스트림을 매개변수로 전달함으로써 입력 버퍼를 비우려고 하고 있습니다.


"저렇게 해봤는데 아무 문제 없이 잘 되던데요?"라고 묻는 분이 있을 겁니다. fflush() 함수의 매개변수로 입력 스트림을 전달하는 것은 정의되지 않은 방법입니다. 즉, 어떻게 작동할지 정의돼 있지 않기 때문에 그 누구도 결과를 예측할 수 없고, 경우에 따라 치명적인 결과를 초래할 수도 있습니다. 물론 저렇게 사용하더라도 원하는 방향대로 잘 작동할 수도 있습니다. 하지만 이는 어디까지나 가능성입니다. 예측할 수 없는 가능성을 믿고 프로그램을 만드시겠습니까?


그럼 입력 버퍼를 어떻게 비워야 하는가라는 질문이 생기실 겁니다. 우리가 입력 버퍼를 비우려는 이유는 위와 같이 엔터를 누름으로써 의도하지 않았던 줄바꿈 문자가 프로그램의 입력 버퍼로 들어갔기 때문입니다. 그러므로 우리는 이 줄바꿈 문자를 그냥 읽고 버리면 됩니다. 위 프로그램에서 12라인만 바꿔보겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
 
int main(void) {
    int total = 0;    // 문자의 수를 저장하는 변수
    char ch;
 
    whiile (1) {
        fputs("Data input (EOF to exit) : ", stdout);
        if ((ch = getchar()) == EOF)    // 값을 입력받고, 만약 그 값이 EOF라면
            break;                      // while문을 빠져나간다.
 
        while (getchar() != '\n')        // 읽은 값이 줄바꿈 문자가 아니면
            continue;                    // 반복한다.
 
        total++;
    }
 
    printf("입력된 문자의 수 : %d\n", total);
    
    return 0;
}
cs


getchar()은 읽어들인 값을 반환하는 함수입니다. 이를 이용해서 줄바꿈 문자 즉, '\n'을 읽어들일 때까지 계속해서 반복하다가 '\n'을 읽어들이면 while문을 빠져나오게 하는 겁니다. 이렇게 하면 위에서 fflush(stdin)를 사용함으로써 원했던 결과와 똑같은 결과를 얻을 수 있습니다.

댓글