버퍼 (Buffer)
지금까지 써왔던 scanf와 printf 등 stdio.h 에서 제공하는 표준 입출력함수들을 사용할 경우
해당 데이터들은 운영체제가 제공하는 '메모리 버퍼'를 중간에 통과하게 된다.
키보드로 데이터를 입력할 때 한 글자 한 글자 입력할 때마다 즉시 프로그램으로 전달되는 것이 아니라
일단 입력버퍼에 저장된 다음에 프로그램으로 저장되는 것이다.
이때 입력버퍼에서 프로그램으로 데이터가 전달되는 시점은 엔터 키가 눌리는 시점이다.
이 일련의 작업을 버퍼링(Buffering)이라고 한다.
그렇다면 버퍼링을 하는 이유는 무엇일까?
데이터를 하나씩 전달하는 것보다 여러 개의 데이터를 한 번에 전달하는 것이 빠르고 효율적이기 때문이다.
출력버퍼 비우기
출력버퍼가 비워진다는 것은 데이터가 메모리버퍼를 떠나 출력이 완료되었다는 뜻이다.
그런데 출력버퍼가 비워지는 시점은 시스템과 버퍼의 성격에 따라서 달라진다.
예를 들어 버퍼가 꽉 찼을 때 비워지는 버퍼도 있고, 하나의 문장이 완전히 입력되었을 때마다 비워지는 버퍼도 있다.
이때 fflush 함수를 사용하면 시스템과 버퍼에 상관없이 표준 출력버퍼에 저장되어 있던 데이터가 목적지로 이동하고
버퍼는 비워진다.
fflush(stdout);
위 코드와 같이 작성하면 표준 출력버퍼를 비우라는 의미이다.
입력버퍼 지우기
입력버퍼의 비움은 출력버퍼 비움과 개념적인 차이가 있다.
출력버퍼가 비워진다는 것은 데이터가 목적지로 전송된 것을 의미하지만
입력버퍼가 비워졌다는 것은 데이터가 소멸했다는 것을 의미한다.
아래코드처럼 fflush를 사용한 입력버퍼 지움은 C언어의 표준에서 그 결과를 정의하고 있지 않다.
fflush(stdin);
따라서 아래 코드처럼 사용하는 것이 하나의 해결책이 될 수도 있다.
void ClearReadBuffer() {
while(getchar()!='\n'); }
입력버퍼에 저장된 문자들은 읽게 되면 지워진다. 그래서 \n을 만날 때까지 문자를 읽어 들이는 함수를 정의하였다.
fgets 함수의 잘못된 사용
#include <stdio.h>
int main()
{
char str[7];
int i;
for (i=0;i<3;i++)
{
fgets(str, sizeof(str), stdin);
printf("Read %d: %s \n", i+1, str);
}
return 0;
}
이제 저번 포스팅에서 봤던 위 코드의 결과가 왜 이렇게 나오는지 이해가 가능할 것이다.
먼저 처음으로 123456 이 문자열에 들어가고 나머지는 입력버퍼에 남아있을 것이다.
그리고 입력버퍼에 데이터가 남아있으니 이 중 789012 가 자동으로 다음 문자열 입력에 들어간다.
그리고 마지막으로 345678 이 입력돼서 출력되고 프로그램은 종료된다.
이제 위 상황도 설명이 가능하다.
like를 예시로 들면 like와 널문자, 그리고 엔터 총 6개의 데이터가 입력버퍼에 들어가게 되고
like와 엔터가 출력되고 (널문자는 없는 문자이므로 출력 x) printf에서 엔터가 한 번 더 출력돼서
개행이 두 번 이루어지는 것이다.
해결 방법
이제 입력 버퍼를 비우는 것으로 위 문제를 해결해 보겠다.
#include <stdio.h>
void ClearReadBuffer() {
while(getchar()!='\n'); }
int main()
{
char str[7];
int i;
for (i=0;i<3;i++)
{
fgets(str, sizeof(str), stdin);
printf("Read %d: %s \n", i+1, str);
ClearReadBuffer();
}
return 0;
}
위 코드를 다시 실행시켜 초과된 크기의 문자열을 입력해 보겠다.
초과된 값이 다음 문자열 입력 시에 들어가지 않고 삭제되는 것을 확인할 수 있다.
먼저 1234567890'\n'을 입력했을 때
123456 은 str로 들어가게 되고 getchar()!='\n'을 통해 개행을 입력받을 때까지 버퍼메모리의 데이터를 읽어 삭제하게 된다.
따라서 890'\n'을 순차적으로 읽을 것이고 해당 데이터는 전부 지워진다.
그 아래 두 번도 같은 과정을 거쳐 정상적으로 문자열이 출력되는 것이다.
'C언어 > C언어 문법' 카테고리의 다른 글
[C언어] 사용자 정의 자료형(typedef), 구조체 typedef 선언 (0) | 2024.02.23 |
---|---|
[C언어] 구조체(struct), 구조체 배열, 구조체 포인터, 화살표 연산자, 구조체 변수의 주소값 (0) | 2024.02.23 |
[C언어] 파일 입출력 함수 (fputc, fputs, fgetc, fgets, putchar, getchar, puts, gets) (0) | 2024.02.21 |
[C언어] 스트림(Stream), EOF (0) | 2024.02.20 |
[C언어] static 변수, register 변수 (0) | 2024.02.19 |