-
C언어 프로그램 입력에 대해Visual Studio/C 기초 2012. 9. 22. 16:32Jaeseok Han
대부분의 프로그램은 입출력 동작을 수행합니다. 프로그램이 입출력 동작을 얼마나 효과적으로 처리하는지는 가끔 프로그램의 유용성을 판단하는 가장 좋은 기준이 됩니다. 오늘은 스트림, 프로그램의 입력과 출력을 전환시키는 방법 등에 대해 알아보겠습니다.
C프로그램이 실행되는 동안 데이터는 읽고 쓰기가 가능한 메모리에 저장됩니다. 데이터는 프로그램에서 선언된 변수, 구조체, 배열의 형태로 존재하는데요, 데이터는 외부로부터 프로그램으로 전달될 수 있고, 외부에서 프로그램이 사용할 수 있는 메모리로 데이터가 전달되는 것을 입력(input)이라고 합니다.
여기서 외부로 전달되는 과정을 출력(output)이라고 합니다.
스트림(stream)이란?
스트림은 문자의 구성이라고 보시면 됩니다. C++에서 포함시키는게 iostream이죠? 여기서 io는 각각 input, output을 뜻합니다. 프로그램으로 전달되는 바이트는 입력스트림, 프로그램에서 외부로 이동되는 바이트는 출력스트림이라 합니다.
C언어의 스트림에는 텍스트 스트림과 바이너리 스트림, 이 두 가지 모드가 있는데, 텍스트 스트림은 화면에 출력되는 텍스트 데이터와 같은 문자만으로 구성되고, 255자의 길이를 가질 수 있으며, 문장의 마지막을 나타내는 문자(EOF)나 새로운 줄 문자에 의해서 종료되는 문장으로 구성됩니다.
바이너리 스트림은 텍스트 데이터로 제한되지 않고 모든 종류의 데이터를 다룰 수 있습니다.
아래의 표는 표준 스트림과 스트림에 연결되어 있는 장치들을 표시한 표입니다.
stdin
표준 입력
키보드 stdout
표준 출력
화면 stderr
표준 에러
화면
stdprn
표준 프린터
프린터(LPT1:)
stdaux
표준 보조
직렬 포트(COM1:)
표준 프린터와 표준 보조는 DOS에서만 지원됩니다.
아래의 표는 C의 스트림 함수입니다. 몇가지는 잘 아실거라 생각합니다.
표준 스트림의 종류
스트림의 이름을 입력하도록 요구하는 것
수행하는 동작
printf() fprintf()
형식화된 출력
vprintf()
vfprintf()
인수의 목록을 이용해서 형식화된 출력
puts()
fputs()
문자열 출력 putchar()
putc(), fputc()
문자 출력
scanf() fscanf()
형식화된 입력
gets()
fgets()
문자열 입력
getchar()
getc(), fgetc();
문자 입력
perror()
stderr로 문자열 출력
이 스트림 함수 중에서 getchar()은 스트림 stdin에서 문자를 읽어들입니다. 버퍼를 사용하고 문자 입력을 화면에 표시하는 것이죠.
int getchar(void);
getchar()의 사용 예를 보겠습니다.
#include <stdio.h>
main(){
int ch;
while((ch=getchar()) != '\n')
putchar(ch);
}위 결과는 아직 ENTER 버튼을 누르지 않았을 때 입니다. 버퍼를 사용하는 함수이기 때문에 ENTER를 누르기 전까진 아무런 동작도 수행하지 않습니다.
이번엔 getch()함수에 대해 설명할건데, 이 함수는 버퍼를 사용하지 않고 문자 입력을 화면에 표시하지 않고 수행합니다. ANSI표준이 아니기 때문에 모든 시스템에서 유효하지 않을 수 있을 뿐 더러 환경에 따라 다른 헤더 파일을 요구할 수 있습니다. 헤더파일로는 conio.h를 포함시키면 됩니다.
#include <stdio.h>
#include <conio.h>main(){
int ch;
while((ch=_getch()) != '\r')
putchar(ch);
}ENTER를 누른 후 입니다. 밑에 문장이 출력되지 않죠?
gets()함수는 여기 <<에서 설명 드렸죠? 클릭하면 새 창이 뜹니다. 그렇기 때문에 getc()함수는 넘어가고 fgetc()로 넘어가겠습니다.
fgets()함수는 입력 스트림에서 한 줄의 텍스트를 읽어들인다는 점에서 gets()와 비슷합니다. fgets()는 프로그래머가 사용하는 특정 입력 스트림과 입력되는 최대 문자의 수를 지정할 수 있게 해주므로 더 유용합니다.
char *fgets(char *str, int n, FILE *fp);
1. 매개변수 FILE *fp는 입력 스트림을 지정하는데 사용합니다.
2. 포인터 str은 입력 문자열이 저장되는 곳을 가리킵니다.
3. n은 입력되는 최대 문자의 수를 나타냅니다. 새로운 줄 문자가 나타나거나 파일의 마지막에 도달, 또는 n-1 문자가 입력될 때 까지 지정된 입력 스트림에서 문자를 읽어들입니다.
fgets()의 사용 예를 들겠습니다.
#include <stdio.h>
#define MAXLENG 10main(void){
char buffer[MAXLENG];
puts("문자열을 입력해주세요. 빈칸을 입력하면 종료됩니다.");while(1)
{
fgets(buffer, MAXLENG, stdin);
if(buffer[0] == '\n') //버퍼의 첫 칸이 빈칸일 경우 종료
break;puts(buffer);
}
}이제 우리가 주로 사용하는 입력 함수 scanf()에 대해 알아보겠습니다.
scanf()는 일반적으로 버퍼에 저장됩니다. ENTER를 누르기 전까진 stdin에서 아무런 문자도 읽어들이지 않습니다. ENTER키를 누르면 전체 내용을 stdin에서 읽어들이고 scanf() 순으로 순서대로 사용합니다.
추가 문자나 불필요한 문자가 있다면 stdin에 남아 있게 되는데, 이 남은 문자들은 몇가지 문제를 일으킵니다. 예를 들어 scanf("%d %d",&x, &y) 라는 구문이 있다고 가정합시다.
예를 들어 10 11을 연속적으로 입력하고 ENTER를 누르면 문제가 발생하지 않지만 10만 입력하고 ENTER를 누를 경우 부족한 내용을 읽어들이기 위해 계속 대기합니다. 또, 10 11 12 를 입력할 경우 형식에 어긋나기 때문에 먼저 10 11을 읽어들이고 나서 프로그램으로 되돌아갑니다. 나머지 1, 2(12의 1, 2)는 stdin에 남아있게 됩니다.
이렇게 남은 문자는 프로그램이 실행되는 동안 stdin에서 다시 입력을 받아들일 때 까지 계속 남아 있게 되는데요, 나중에 프로그램이 stdin에서 다시 입력을 받아들이면 나머지 문자는 다른 어떤 입력 내용보다 먼저 읽어들여집니다. 어떤 문제가 일어날지는 상상이 가시죠?
이러한 에러를 방지하기 위한 예제를 몇가지 들겠습니다.
#include <stdio.h>
void forclear(void);
main(void){
int age;
char name[20];puts("당신의 나이를 입력해주세요");
scanf("%d", &age);forclear(); //stdin에 남아있는 문자 제거.
puts("당신의 이름을 입력해주세요");
scanf("%s", name);printf("당신의 나이는 %d살 이군요.\n", age);
printf("당신의 이름은 %s이군요.\n", name);
}void forclear(void){
char junk[80];
gets(junk);
}이 프로그램을 컴파일하고 ENTER를 누르기 전에 나이 다음에 몇가지 문자를 입력해보면 프로그램이 추가로 입력된 문자를 무시하고 정확한 이름을 출력한다는 것을 알 수 있습니다.
forclear를 제거하고 다시 컴파일 한 후에 나이 다음에 몇가지 문자를 입력해보면 나이와 같은 줄에 입력된 나머지 문자들이 이름에 출력될 것입니다.
stdin에 남아있는 문자를 제거하기 위한 두번째 방법은 바로 fflush()를 사용하는 방법입니다. 이 함수는 표준 입력 스트림(stdio.h)을 포함하여 특정 스트림에서 데이터를 지웁니다.
#include <stdio.h>
main(void){
int age;
char name[20];puts("당신의 나이를 입력해주세요");
scanf("%d", &age);fflush(stdin);//stdin에 남아있는 문자 제거.
puts("당신의 이름을 입력해주세요");
scanf("%s", name);printf("당신의 나이는 %d살 이군요.\n", age);
printf("당신의 이름은 %s이군요.\n", name);
}
첫번째 방법보다 간단하죠? 다음엔 프로그램 출력에 대해 알아보겠습니다.
'Visual Studio > C 기초' 카테고리의 다른 글
fopen() (0) 2012.10.16 C언어 프로그램 출력에 대해 (0) 2012.09.23 C언어 연결리스트 (linked list) (0) 2012.09.21 C언어 함수 기초 (2) 2012.09.14 C언어 고급포인터 (0) 2012.09.13