공부했던 자료 정리하는 용도입니다.

재배포, 수정하지 마세요.

 

 


 스트림 

  • 스트림의 생성, 소멸
    * 표준 스트림

 

 표준 입출력과 버퍼 

  • 출력 버퍼 비우는 함수 : fflush
  • 입력 버퍼 비우기

 


 

스트림(stream)

  •  입력  : (프로그램을 기준으로) 프로그램 안으로 데이터가 들어오는 것
    입력장치의 예 : 키보드, 파일 등..
  •  출력  : (프로그램을 기준으로) 프로그램 밖으로 데이터가 나가는 것
    출력 장치의 예 : 모니터, 파일 등..
  •  스트림  : 외부장치와 프로그램과의 데이터 송수신 도구(프로그램과 입출력 장치를 연결해주는 다리 역할을 하는 매개체). 단방향으로만 데이터의 전송이 이루어진다. 소프트웨어적으로 구현되어 있으며 운영체제에서 제공한다.

 

 

스트림의 생성, 소멸

  ``console``(일반적으로 키보드와 모니터를 의미) 입출력을 위한 '입력 스트림'과 '출력 스트림'은 '표준 스트림(standard stream)'으로, 프로그램이 실행되면 자동으로 생성되고, 프로그램이 종료되면 자동으로 소멸한다. 반면 파일과의 연결을 위한 스트림의 생성은 프로그래머가 직접 요구해야 한다.

 

 

  ■ 표준 스트림(standard stream)

  ``stderr``는 ``stdout``과 기능은 같지만 입출력 리다이렉션(redirection) 시 ``stderr``는 표준 에러 스트림의 출력 대상을 변경시킬 수 있다는 점에서 차이가 있다.

스트림 이름 스트림 종류 기능
stdin 표준 입력 스트립 키보드 대상으로 입력
stdout 표준 출력 스트림 모니터 대상으로 출력
stderr 표준 에러 스트림 모니터 대상으로 출력

 

 

 

 

 


표준 입출력과 버퍼

  ``printf``와 ``scanf``, ``fputc``, ``fgetc``등은 ANSI C의 표준에서 정의된 함수기 때문에 '표준 입출력 함수'라고 한다. 표준 입출력 함수를 통해 데이터를 입출력하는 경우, 해당 데이터들은 운영체제가 제공하는 '메모리 버퍼'를 중간에 통과하게 된다.

  •  메모리 버퍼  : 데이터를 임시로 저장하는 메모리 공간
  • 버퍼링(Buffering)을 하는 이유
    데이터의 전송 효율성 때문. 외부장치의 입출력은 시간이 많이 걸리므로 데이터를 묶어 보내는 것이 더 빠르고 효율적이다.

  예를 들어 키보드를 통해 입력된 데이터는 일단 입력 버퍼에 저장된 다음(버퍼링 된 다음) 프로그램에서 읽혀진다. ##enter## 키가 눌리는 시점에 키보드로부터 입력된 데이터가 입력 스트림을 거쳐 입력 버퍼로 들어가게 된다. 그래서 ##enter##키가 눌리기 전에는 입력 버퍼가 비워져 있기 때문에 ##fgets## 함수가 문자열을 읽어 들이지 못한다.

 

 

 

출력 버퍼를 비우는 함수 : fflush

#include <stdio.h>
int fflush(FILE * stream);

// ex
fflush(stdout);	// 표준 출력 버퍼 비우기

이 함수는 인자로 전달된 스트림의 버퍼를 비우는 기능을 한다.

함수 호출 성공 시 ##0##, 실패 시 ##EOF##를 반환한다.

 

  • 출력 버퍼가 비워진 다는 것은 출력 버퍼에 저장된 데이터가 버퍼를 떠나 목적지로 이동된다는 의미이다.
  • 출력 버퍼가 비워지는 시점은 시스템이나 버퍼의 성격에 따라 달라진다.
  • ``fflush`` 함수를 사용하면 시스템의 어떤 표준 출력 버퍼라 할지라도 버퍼의 저장된 내용이 비워지면서 데이터가 목적지로 이동한다.
  • 파일을 대상으로 호출하는 것도 가능한데, 인자로 파일의 스트림 정보가 전달되면 해당 버퍼에 저장되어 있던 데이터가 버퍼를 떠나 파일에 기록된다.

 

 

 

입력 버퍼 비우기

  입력 버퍼의 비워짐은 데이터의 소멸을 의미하기 때문에 출력 버퍼를 비우는 것과 개념적으로 차이가 있다. 가끔 입력 버퍼에 남아있는 불필요한 데이터의 소멸을 위해 입력 버퍼를 비워야 하는 경우가 있다.

 

#include <stdio.h>

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

위의 예시는 ``fgets``를 통해 입력받은 데이터를 ``perID``라는 배열에 저장한다.

 

실행 결과

  그런데 ``fgets``를 두 번 사용했음에도 사용자에게 입력을 ``1``번밖에 받지 않는다. 입력 버퍼에 ``\n``이 남기 때문이다. 지금과 같은 경우에는 입력 버퍼에서 문자 하나만 지워주면 되지만 입력값을 예상하기 어려운 경우가 많으므로 지정한 자리수 외에는 전부 입력 버퍼에서 지워주어야 한다.

 

 

   위와 같은 결과가 나온 이유 

  1. ``fgets``는 ``\n``까지 문자로 받기 때문에 입력값이 ``950915``인 경우 ``950915\n``으로 7자리가 된다.
  2. 문자열의 마지막 값엔 ``null``이 들어가기 때문에 끝에 있던 ``\n``는 입력 버퍼에 남는다.
  3. 이후에 ``fgets``함수가 호출되면 ``\n``이 나올 때까지 읽어 들이기 때문에 버퍼에 하나 남아있던 ``\n``를 읽어버리게 된다.

 

 

#include <stdio.h>

void ClearLineFromReadBuffer(void)	// 입력 버퍼를 비우는 함수
{
	while(getchar() != '\n');	// null 문자가 아닐때까지 문자를 입력받음(버퍼 비우기)
}

int main(int argc, int argv[])
{	
	char perID[7];
	char name[10];
	
	fputs("주민번호 앞 6자리 : ", stdout);
	fgets(perID, sizeof(perID), stdin);
	ClearLineFromReadBuffer();	// 함수 호출
	
	fputs("이름 입력 : ", stdout);
	fgets(name, sizeof(name), stdin);
	
	printf("주민번호 : %s \n", perID);
	printf("이름 : %s \n", name);
	
	return 0;		
}

  입력 버퍼에 저장된 문자들은 읽어 들이면 지워지므로 ``null``문자가 나올 때까지 ``getchar( )``로 문자열을 입력받아 버퍼를 비우는 함수를 선언하면 된다. (저장하지 않고 받기만 해서 결과적으로는 버퍼에서 지워짐)

 

실행 결과

``perID``보다 큰 값을 입력했음에도 의도한 대로 ``fgets``가 동작하는 것을 확인할 수 있다.

 

 

 

'기타 > C' 카테고리의 다른 글

[C] 구조체  (0) 2020.06.01
[C] 문자, 문자열  (0) 2020.05.28
[C] 함수 포인터, void 포인터  (0) 2020.05.22
[C] 다차원 배열과 포인터  (0) 2020.05.19
[C]이중 포인터(더블 포인터)  (0) 2020.05.12

+ Recent posts