관우는 왜 C 언어를 살육했나? [2-7] 표준 입력
by
[2-7] 표준 입력 : scanf(), getchar(), getc(), gets()
표준 입력은 유닉스 및 유닉스 계열 운영체제에서 프로그램과 환경 사이에 미리 연결된 입력 통로입니다. PC에서 표준 입력은 일반적으로 키보드입니다. 임베디드 단말에서는 키패드 등이 될 수도 있죠.
[2.5] 표준 출력, printf(), putchar(), putc()’에서 표준 출력인 콘솔로 문자를 출력했으니 표준 입력을 받아봅시다.
문자열, 정수, 문자 등을 입력받을 수 있습니다. 여기서는 주로 사용하는 scanf, getchar(), fget() 함수만 살펴봅니다.
scanf() 함수
scanf()는 표준 입력에서 입력한 형식화된 바이트 입력을 읽습니다. 함수 원형은 다음과 같습니다.
int scanf( const char *restrict format, ... );
- 입력 : 형식지정자를 사용해 입력받습니다.
- 반환값 int : 성공하면 성공적으로 할당된 인수 수, 실패하면 EOF를 반환합니다.
printf()와 같이 가변변수를 사용합니다. 사용법은 다음과 같습니다.
#include <stdio.h>
int main(void) {
char ch = 0;
scanf("%c", &ch);
printf("input is %c\n", ch);
return 0;
}
로컬 PC에서 이 프로그램을 실행하면 명령 프롬프트가 뜰 겁니다. 숫자 하나면 넣으면 됩니다. https://ideone.com에서는 실행하기 전에 다음과 같이 에 미리 값을 입력하면 됩니다.
[출력]
press any key : 3
c is 3
입력값으로 3을 넣었더니 위와 같이 출력됩니다. printf()와 마찬가지로 형식지정자로 s(문자열), i(정수형), f(실수형) 등을 받을 수 있습니다.
초보자가 scanf()를 쓰면서 가장 많이 실수하는 곳이 있습니다. 바로 scanf(“%c”, &ch);에서 &ch 부분입니다. &를 빼먹게 되어 버그를 잡는데 잠을 설치게 됩니다. 표준 입력으로 받은 값을 해당 변수의 주소로 보내주기 때문입니다. 반드시 &를 빼먹지 마세요!
이번에는 문자열을 받아보겠습니다.
#include <stdio.h>
int main(void) {
char str[5];
printf("press one word : ");
scanf("%s", str);
printf("\ninput : %s\n", str);
return 0;
}
[출력]
press one word : hello world
input : hello
“hello world”를 입력했지만 str 크기가 5라서 딱 문자 5개까지만 입력으로 받았습니다.
다음과 같이 한 번에 여러 변수를 입력 받을 수 있습니다.
#include <stdio.h>
int main(void) {
char c;
char str[10];
int i;
scanf("%c %s %d\n", &c, str, &i);
printf("your input : %c, %s, %d\n",c, str, i);
return 0;
}
순서대로, 문자, 문자열, int형 변수값이 입력되었습니다. 문자열을 입력받는 str[ ] 변수 앞에는 앞에는 &가 붙지 않았습니다. 배열의 이름은 배열의 시작 주소를 나타내기 때문입니다. 이미 주소인데 &를 붙일 필요가 없는거죠.
이 함수는 쓰인세도 다양하고 초보자가 실수하기도 쉽습니다. 예를 들어 다음 두 줄의 코드는 서로 다른 형식의 입력을 받습니다.
scanf("%c %d\n", &c, &i);
scanf("%c, %d\n", &c, &i);
첫 번째 코드의 입력 형식은 다음과 같습니다.
문자 + 공백 + 숫자
그런데 두 번째 코드의 입력 형식은 다음과 같습니다.
문자 + 쉼표 + 공백 + 쉼표 + 숫자
이를 활용하면 형식 고정적인 데이터를 쉽게 불러올 수 있습니다.
한번 코드를 작성해 실험해보시기 바랍니다.
이상 관우였습니다!
제갈량의 동남풍 : 왜 scanf() 함수는 주소로 인수를 입력해야 하나?
오래간만에 인사드리는 제갈량입니다. scanf( ) 함수를 사용하면서 ‘scanf( ) 함수는 왜 주소를 인수로 전달해야 하는 걸까? 그냥 & 없이 변수명만 넣어주면 알아서 값을 복사해주면 안 되나’라는 의문이 들지 않나요?
함수에서 반환값의 위치를 떠올려보세요.
int scanf( const char *restrict format, ... );
int는 반환값이고, ‘const char *restrict format, …’는 scanf() 함수 입장에서 파라미터, 즉 입력값입니다.
코드가 어떻게 동작하는지 아래 그림을 참조하면서 살펴보겠습니다.
입력값은 scanf로 전달되는 값이므로, 주소를 전달하지 않고서야 이 파라미터에 무언가를 쓸 방법이 없습니다. 그런데 ① 주소를 전달한다는 사실만 안다면 해당 주소에 ② 표준입력된 값을 써두면 되니까 원활히 표준 입력값을 전달 할 수 있는 겁니다. 그래서 인수로 주어지는 변수의 주소를 입력하고, 해당 주소에 값을 쓰는 거죠.
風 |
getchar() 함수
getchar() 함수는 표준 입력에서 1바이트를 읽습니다. 함수원형은 다음과 같습니다.
int getchar(void);
- 입력 : 없습니다.
- 반환 : 성공하면 입력받은 문자를 반환합니다. 실패하면 EOF를 반환하고 표준 에러에 오류 메시지를 보냅니다.
예제를 살펴보겠습니다.
#include <stdio.h>
int main(void) {
char ch;
printf("press one word : ");
// stdin에서 읽기
ch = getchar ( );
printf("\ninput : %c\n", ch);
return 0;
}
[출력]
press one word : g
input : g
g를 표준 입력에서 입력받아 ch에 저장하고 printf()문으로 출력했습니다.
fget()
사용자가 지정한 파일 스트림에서 1바이트를 읽는 함수입니다. 함수 원형은 다음과 같습니다.
int gutc(FILE *stream);
- 입력 : 1바이트를 읽을 파일 스트림을 지정합니다.
- FILE *stream : 파일이거나 장치일 수 있습니다. stdin은 표준 입력, stdout은 표준 출력, stderr는 표준 에러 장치를 지칭합니다. 물론 그밖에 다른 장치와 파일 기술자도 사용할 수 있습니다.
- 반환 : 성공하면 성공한 글자 수를, 실패하면 EOF를 반환하고, 표준 에러에 오류 메시지를 남깁니다.
파일 기술자(file descriptor)를 파일 설명자, 파일 디스크립터라고도 합니다.
FILE *stream에 표준 장치인 stdout를 인수로 입력하면 gutchar()는 완전히 같은 기능을 수행합니다. 앞서 다룬 gutchar() 예제를 gutc()로 구현해보겠습니다.
#include <stdio.h>
int main(void) {
char ch;
printf("press one word : ");
// stdin에서 읽기
ch = getc(stdin);
printf("\ninput is %c\n", ch);
return 0;
}
[출력]
press one word : g
input is g
함수 이름을 바꾸고 stdin만 인수로 주었습니다. 예제 분석에 무리가 없을 겁니다. 그런데 이 함수는 기억해 둘 필요가 있습니다. 표준 입력 말고 파일이나 다른 장치를 읽을 때 유용합니다. 보통 다음과 같이 사용합니다.
while ( ( ch = getc(파일 스트림 ) ) ! = EOF )
위 while문은 읽은 문자가 EOF일 때까지 읽습니다. EOF는 파일의 끝이라고 표준 출력에서 이야기를 했었습니다. 왜 파일이나 장치를 읽을 때 getc() 함수가 유용한지 이제 감이 오죠?
gets() 함수
gets() 함수는 표준입력에서 개행 문자(\n)나 파일 끝을 나타내는 EOF를 만나기까지 문자열을 가져옵니다.
함수 원형은 다음과 같습니다.
char * gets ( char * str );
- char * str : 문자열을 읽을 메모리 공간입니다.
- 반환 : 아무것도 읽지 못하거나 오류가 발생하면 NULL을, 읽었다면 읽은 문자열을 반환합니다.
사용 예는 다음과 같습니다.
#include <stdio.h>
#include <string.h>
int main(void) {
char str[20];
gets(str);
printf("input : %s\n", str);
return 0;
}
hello world를 키보드로 입력한 결과 출력은 다음과 같습니다.
[결과]
hello world
문자열이 얼마나 큰지 모른다면 충분한 메모리 공간을 확보해 사용하고, 에러와 예외 체크도 해야 합니다.
殺
Subscribe via RSS