C언어 입/출력 버퍼

    2019-05-16 18:14:43 작성

    버퍼 (buffer)

    표준입/출력 함수를 통해서 데이터를 입/출력 하는 경우 운영체제가 제공하는 메모리버퍼를 통과 하게 됩니다.
    메모리버퍼란 데이터를 임시로 모아두는 메모리 공간을 뜻합니다.

    키보드로 입력을 하면 입력스트림을 통해 입력된 데이터는 입력버퍼에 저장된 다음에 프로그램으로 읽혀지는 것을 알수 있습니다.
    입력된 데이터가 입력 스트림을 거처 입력버퍼로 들어가게 되는 시점은 엔터키가 눌리는 시점입니다.
    그래서 문자열을 읽어드리는 함수는 엔터키가 눌리기전에는 문자열을 읽어 드리지 못하는 것입니다.

    데이터를 목적지로 바로 전송하지 않고 중간에 버퍼를 둬서 데이터를 임시 저장하는 이유는 데이터 전송의 효율성과 관련이 있습니다.
    예를 들어 창고의 물건을 옴길때 하나씩 옴기는것보다 손수레에 가득채워서 한번에 나르는 것이 보다 빠르고 효율적일 것입니다.

    버퍼를 비우는 것은 버퍼에 저장된 데이터가 버퍼를 떠나서 목적지로 이동되는 것을 뜻합니다.


    출력버퍼 비우기

    fflush 함수를 호출하면 출력 스트림의 버퍼를 비우는 기능을 제공합니다.

    int fflush(FILE * stream);

    fflush 함수는 호출성공시 0을 반환하고 실패시 EOF를 반환합니다.
    출력버퍼를 비우는 것은 출력버퍼에 저장된 데이터가 버퍼를 떠나서 목적지로 이동됨을 의미합니다.


    입력버퍼 비우기

    입력버퍼의 비워짐은 데이터의 소멸을 뜻합니다.
    가끔은 입력버퍼에 남아있는 불필요한 데이터의 소멸하기 위해 입력 버퍼를 비워야 하는 경우가 생깁니다.

    #include <stdio.h>
    
    int main(void) {
    	char id[7];
    	char name[10];
    
    	fputs("주민번호 앞 6자리 입력 : ", stdout);
    	fgets(id, sizeof(id), stdin);
    	fputs("이름 입력 : ", stdout);
    	fgets(name, sizeof(name), stdin);
    
    	printf("주민번호 : %s\n", id);
    	printf("이름 : %s\n", name);
    	return 0;
    }


    위와 같이 주민번호 앞 6자리를 입력하였는데 이름 입력의 기회가 주어지지 않고 프로그램이 종료 되었습니다.
    그 이유는 "760259\n" 그리고 엔터키를 포함하여 7개의 문자가 입력되었습니다.
    fgets 함수로 sizeof(id)하여 7이 전달되었으며 마지막은 NULL문자로 저장되기 때문에 "760529\0"이 저장되고 "\n"는 입력버퍼에 남게 됩니다.
    그리고 이어서 이름을 입력받을 fgets 함수가 호출되며 이때 버퍼에 남아있는 "\n"을 읽어 들이며 fgets 함수는 엔터키를 칠때까지 문자입력을 받기 때문에 name에는 "\n\0"문자가 저장되며 함수호출이 종료됩니다.

    또는 다음의 경우가 있을 수 있습니다.

    위의 경우에는 주민번호 앞 6자리만 입력을 받아야 하는데 사용자의 실수(?)에 의해 더 긴 문자열이 입력된 경우이며, 이름입력의 기회는 사라지고 버퍼에 남아있는 나머지 문자열들이 저장되어집니다.

    이러한 이유들로 인해서 의도하지 않은 입력이 일어나지 않게 fgets 함수 호출전에 입력버퍼를 비울 필요가 있습니다. 다음 예제의 clearReadBurffer 함수는 입력버퍼를 비웁니다.

    #include <stdio.h>
    
    void clearReadBuffer(FILE * stream);
    
    int main(void) {
    	char id[7];
    	char name[10];
    
    	fputs("주민번호 앞 6자리 입력 : ", stdout);
    	fgets(id, sizeof(id), stdin);
    	clearReadBuffer(stdin); // 의도하지 않은 입력버퍼를 청소
    	fputs("이름 입력 : ", stdout);
    	fgets(name, sizeof(name), stdin);
    
    	printf("주민번호 : %s\n", id);
    	printf("이름 : %s\n", name);
    	return 0;
    }
    
    void clearReadBuffer(FILE * stream) {
    	while (fgetc(stream) != '\n');
    }


    clearReadBuffer는 전달받은 스트림의 '\n'문자를 만날때까지 문자를 읽어 들이는 함수입니다.
    사용자가 실수를 하더라도 필요한 만큼만 읽어드리고 나머지는 버리기 때문에 정상적으로 작동합니다.