scanf

프로그래밍/C/C++ 강좌 2007. 8. 31. 11:11

프로그램은 혼자 실행되는 것이 아니라 보통 사용자와 상호 작용한다. 어떤 특정한 동작을 하려면 사용자로부터 명령을 받아 들이거나 동작에 필요한 기본적인 정보를 입력받아야 한다. 예를 들어 바이오 리듬 프로그램을 작성한다면 생년월일과 조사하고 싶은 날짜를 사용자에게 물어 보아야 할 것이고 성적 관리 프로그램이라면 관리의 대상이 되는 성적을 입력받아야 할 것이다.

scanf(스캔에프라고 읽는다)는 사용자로부터 정보를 입력받는 기본 함수이다. printf의 반대 함수이며 동일한 서식을 사용한다. 즉 정수를 입력받고 싶으면 %d 서식을 사용하고 문자열을 입력받고 싶으면 %s 서식을 사용하면 된다. 단 실수 서식인 %f가 printf는 float, double에 모두 대응되는데 비해 scanf는 float와만 대응된다는 점만 다르다. scanf로 double값을 입력받으려면 %lf 서식을 사용해야 한다. scanf를 호출하면 화면에 커서가 나타나 깜박거리며 입력을 요구하는데 이 상태에서 사용자는 키보드를 통해 프로그램이 요구하는 정보를 입력하고 Enter키를 누르면 된다. 기본 형식은 다음과 같다.

scanf("서식문자열", &변수 [,&변수, ...]);

printf 와는 달리 서식 문자열에는 오로지 서식만 들어갈 수 있으며 서식 이외의 문자열은 넣어 봐야 무시된다. 입력받고자 하는 정보를 사용자에게 요구할 때는 scanf이전에 printf로 미리 어떤 정보를 입력하라는 안내 문자열(프롬프트라고 한다)을 출력해야 한다. 앞장에서 작성한 숫자 맞추기 게임의 소스를 보면 scanf의 사용예가 있다.

printf("숫자를 입력하세요(끝낼 때는 999) : ");

scanf("%d",&input);

printf 함수로 미리 어떤 값을 입력해 달라는 메시지를 출력하였다. 이때 개행 코드(\n)를 출력하지 않아야 메시지 바로 다음 위치에서 입력을 받을 수 있다. 서식 문자열로 %d를 주어 정수값 하나를 입력받는다는 것을 표시했으며 이 값을 input이라는 변수에 대입하도록 했다. 문자를 입력받는다면 %c, 실수는 %f, 문자열은 %s 서식을 사용하면 된다.

이때 scanf로 입력받을 변수를 지정할 때 변수명앞에 & 연산자를 붙여야 한다. 이유는 변수의 값이 아닌 번지를 전달해야 scanf가 이 변수의 값을 변경할 수 있기 때문이다. 무척 복잡하게 들리겠지만 &연산자는 한참 후에나 살펴볼 수 있는 어려운 연산자이기 때문에 일단은 이해가 가지 않더라도 scanf로 값을 입력받을 때는 & 연산자를 변수명앞에 붙여야 한다는 것을 외워 버리도록 하자.

사용자 삽입 이미지
정수형 변수 a에 값을 입력받으려면 scanf("%d", &a), 실수형 변수 b에 값을 입력받으려면 scanf("%f", &b) 라고 호출하면 된다. 문자열의 경우는 입력받는 방법이 조금 다른데 아직 문자열 표현 방법을 배우지 않았으므로 다음에 기회가 될 때 설명하도록 하자. 다음 예제는 입출력 실습을 위한 예제이다. 두 개의 정수를 사용자로부터 입력받아 그 합을 출력한다.

: scanf

#include <Turboc.h>

 

void main()

{

     int a,b;

     int sum;

 

     printf("첫 번째 숫자를 입력하세요 : ");

     scanf("%d",&a);

     printf("두 번째 숫자를 입력하세요 : ");

     scanf("%d",&b);

     sum=a+b;

     printf("입력한 두 수의 합은 %d입니다.\n",sum);

}

printf로 어떤 수를 입력하라는 안내 메시지를 먼저 출력하고 scanf로 정수값을 입력받아 a, b 변수에 저장했다. sum에 두 수의 합을 구하고 printf로 그 합을 출력하면 된다. 실행 결과는 다음과 같다.

첫 번째 숫자를 입력하세요 : 26

두 번째 숫자를 입력하세요 : 32

입력한 두 수의 합은 58입니다.

printf가 한꺼번에 여러 개의 변수를 출력할 수 있듯이 scanf도 여러 개의 변수를 한꺼번에 입력받을 수 있다. 서식 문자열에 여러 개의 서식을 작성하고 뒤쪽에 입력받을 변수도 서식 개수만큼 나열하면 된다. 다음 코드는 scanf 를 한 번 호출하여 두 개의 정수를 입력받는다.

printf("두 개의 숫자를 입력하세요 : ");

scanf("%d%d",&a,&b);

사용자는 두 정수를 공백, 개행 코드 등으로 분리해서 입력한다. printf와 마찬가지로 %와 서식 사이에 입력 형식을 지정하는 다양한 양식도 사용할 수 있다. 별로 어렵지는 않지만 여기서는 이런 것들에 대해서 굳이 설명하지 않고자 한다. 지금은 그래픽 환경의 윈도우즈 시대이고 그래픽 환경에서는 값을 입력하거나 선택하는 다양한 컨트롤들이 제공된다. 다음은 값을 입력받는 대화상자의 한 예이다.

사용자 삽입 이미지

입력받고자 하는 값의 성격에 따라 적합한 컨트롤들을 사용할 수 있으므로 훨씬 더 직관적이고 사용하기도 쉽다. 뿐만 아니라 scanf는 질문과 답변 형태로 값을 입력받지만 대화상자는 순서에 상관없이 입력할 수 있고 확인 버튼을 누르기 전에 마음대로 수정할 수도 있다. 키보드로 값을 타이프해서 입력하는 시대는 한참 전에 지났으며 그래서 도스용 프로그램을 작성하지 않는 한 scanf 함수로 값을 입력받아야 하는 경우는 거의 없다.

하지만 지금 C를 처음 배우는 사람들은 scanf 함수의 기본적인 사용 방법을 알아야 하는데 이 함수 외에는 콘솔 환경에서 값을 입력받을만한 적당한 방법이 없기 때문이다. 위에 보인 대화상자가 멋있어 보이겠지만 C문법을 처음 배우는 사람에게 저런 대화상자를 만드는 것은 너무 너무 어려운 기술이다. 그래서 당분간은 기본적인 입력을 scanf 함수로밖에 할 수가 없다.

지금 scanf 함수를 알아야 하는 이유는 실제 프로젝트에 이 함수가 필요해서가 아니라 문법 공부를 하는데 이 함수의 도움이 필요하기 때문이다. 요즘같은 그래픽 환경에서 이 함수는 실습용 이상의 의미를 부여하기 어렵다. scanf 함수를 실제로 사용해야 한다거나 더 자세한 사항을 알고 싶다면 레퍼런스를 참고하기 바라되 그렇지 않다면 정수값과 문자열을 입력받을 수 있는 정도의 사용법만 알아도 당장 실습하는데는 별 무리가 없을 것이다. scanf가 아니더라도 공부해야 할 것들이 얼마든지 많으므로 여기서 불필요하게 힘을 뺄 필요는 없다.

Posted by 테티스
,
압축 파일에는 강좌 본문에서 작성한 예제와 실습에 필요한 파일들, 검색 유틸리티 등이 포함되어 있습니다. 압축을 푸신 본문의 지시에 따라 Turboc.h 파일을 설치하십시오. 헤더 파일을 설치하지 않으면 강좌의 예제를 컴파일할  없습니다.
Posted by 테티스
,

변수나 제어문을 공부하기 전에 기본적인 입출력 방법을 먼저 알아보도록 하자. 변수의 값을 확인하거나 처리 결과가 어떻게 나오는지 보려면 일단 화면에 찍어 봐야 하므로 효율적인 실습을 위해서는 입력과 출력 명령을 먼저 사용할 수 있어야 한다. 초보자들은 이론적인 설명보다는 눈에 보이는 것을 더 믿는 경향이 있어서 int Num=12; 선언문에 의해 정수형의 Num 변수가 생성되고 12로 초기화된다고 해도 "증거를 대라"는 식으로 믿지 않는 희한한 버릇이 있다. 공부할 때는 아무리 간단한 것이라도 확인해 보고 넘어가는 것이 좋다.

베이직 PRINT라는 기본적인 출력문을 언어 차원에서 제공한다. 이에 비해 C언어는 문법의 간결성과 이식성 확보를 위해 언어 자체에 입출력 명령이 포함되어 있지 않다. 대신 컴파일러 제조사가 라이브러리 (일단 명령의 집합이라고 생각하면 된다) 형태로 입출력 명령을 제공하며 이 명령등른 C 표준에 의해 모든 컴파일러가 의무적으로 제공하도록 되어 있으므로 언제든지 사용할 수 있다.

printf는 C의 표준 출력 함수이며 C를 배우는 사람이 가장 먼저 대하는 명령어이다. 마치 도스를 처음 배우는 사람이 dir을 가장 먼저 배우고 윈도우즈를 처음 배울 때 탐색기부터 배우듯이 말이다. 함수의 정확한 개념에 대해서는 다음에 상세하게 배워 보기로 하되 일단은 명령의 일종이라고 생각하면 된다. 이 함수의 철자에 조금 주의해야 하는데 print가 아니라 printf이며 읽을 떄는 "프린트에프"라고  읽는다. printf의 제일 뒤에 있는 f는 Formatting의 약자이며 서식화된 출력을 한다는 뜻이다.

서식화라는 말이 어렵게 들린다면 일단 조립이라고 생각하도록 하자. 가장 기초적인 명령이면서도 사실 이만큼 복잡한 명령어도 드물어서 완벽하게 자유 자재로 사용하려면 많은 경험을 필요로 한다. 복잡한 내용은 차후에 천천히 알아보기로 하고 여기서는 기본적인 사용법만 익혀보도록 하자.

printf는 괄호안의 문자열을 화면으로 출력한다. 가장 단순한 형태는 printf("문자열"); 인데 겹따옴표안의 문자열이 화면으로 그대로 출력된다. printf("나는 바보다"); 라는 명령은 "나는 바보다"를 화면으로 출력한다. 앞장에서 이미 printf("korea\n");이라는 명령을 사용해 본 적이 있지 않은가? 이 함수의 일반적인 사용법은 다음과 같다.

printf("서식문자열"[,인수,인수,...]);

서식 문자열을 화면으로 출력하되 문자열 내에 %로 시작되는 서식이 있으면 이 서식과 대응되는 뒤쪽의 인수(일단 변수라고 생각하기 바란다)를 문자열안에 넣어 같이 출력한다. 즉 출력하기 전에 서식과 인수를 대응시켜 조립(Formatting)하는 과정을 먼저 거친다. 뒤쪽의 인수는 서식의 개수만큼 오되 서식이 없으면 인수를 생략할 수 있다.

: printf

#include <Turboc.h>

void main()
{
     int value=12;
     char ch='S';


     printf("값은 %d이며 문자는 %c이다.\n",value,ch);

정수형 변수 value를 12로 초기화하고 문자형 변수 ch는 "S"문자로 초기화한후 printf로 이 변수들의 값을 출력해 보았다. 출력 결과는 다음과 같다.

사용자 삽입 이미지

서식 문자열 안에는 %d, %c 등의 서식이 포함되어 있으며 이 서식과 대응되는 인수 value와 ch가 서식문자열 다음에 온다. 이 함수는 문자열내의 서식을 대응되는 실제 변수값으로 바꾸어 화면에 출력한다. %d 서식은 value에 대응되므로 이 자리에 value 변수의 실제값인 12가 삽입되고 %c 서식은 ch에 대응되므로 ch변수의 실제값인 "S"가 삽입된다.

서식 문자열의 서식과 뒤쪽의 인수는 나타나는 순서대로 1:1 서로 대응된다. 따라서 서식의 개수와 인수의 개수가 같아야 하며 또한 데이터형도 서로 일치해야 한다. %d는 정수형 서식이므로 정수형 변수와 대응되어야 하며 %c는 문자형 서식이므로 문자형 변수와 대응되어야 한다. 만약 개수나 타입이 일치하지 않으면 프로그램이 제대로 동작하지 않을 뿐만 아니라 어떤 경우에는 에러를 일으키고 다운될 수도 있다. 표준은 서식이 일치하지 않을 경우의 동작에 대해서는 정의하고 있지 않으므로(Undefined) 개발자가 반드시 일치시켜야 한다.

서식은 % 다음에 알파벳 문자 하나로 표기하며 다음과 같은 종류가 있다. 서식의 수가 좀 많은데 이 중 %d, %c, %s, %f 정도만 알아 두면 변수값을 확인해 보는 용도로 충분히 활용할 수 있을 것이다. 나머지 서식은 필요할 떄 이 표를 다시 참조하면 된다.

서식

의미

설명

%d 또는 %i

Decimal, Integer

 

10진 정수로 출력한다.

%o

Octal

 

8진 정수로 출력한다.

%x또는 %x

heXadecimal

16진 정수로 출력한다. 대문자 X를 쓰면 A~F까지의 숫자도 대문자로 출력된다.

%u

Unsigned

부호없는 10진 정수로 출력한다.

%c
%s
%f
%e 또는 %E
%g 또는 %G
%p

%n
%%

Character
String
Float


Pointer

1개의문자열을 출력한다.
문자열을 출력한다.
고정 소수점 형식의 실수로 출력
부동 소수점 형식의 실수로 출력
%e,%f중 더 짧은 형식으로 출력
포인터의 번지값을 출력
출력된 문자 개수를 포인터 변수에 대입한다.
%문자 자체를 출력한다.


printf 함수는 변수값을 화면으로 출력하거나 또는 문자열로 조립할 떄 사용하는 가장 기본적인 함수이며 변수의 출력 위치와 형태를 서식으로 지정할 수 있는 아주 편리한 방법이기도 하다. 확인해 보고 싶은 값의 자리에 서식을 대신 넣어 주기만 하면 된다. 예를 들어 Score 정수형 변수에 총점이 있고 Average 실수형 변수에 평균이 저장되어 있다면 다음과 같이 출력한다.

printf("총점은 %d점이며 평균은 %f점입니다.\n",Score,Average);

%d 자리에 Score에 기억된 정수값이 출력될 것이며 %f 자리에 Average에 기억된 실수값이 출력될 것이다. 서식 문자열은 얼마든지 자유롭게 바꿀 수 있으므로 "총점=%d, 평균=f"나 "총점/평균(%d/%f)"로 작성할 수도 있다. printf는 서식이 있는 자리에 실제값을 끼워 넣기만 할 뿐이다.

서식은 이 자리에 "무엇을" 출력할 것인가를 지정하는데 이 외에도 "어떻게" 출력할 것인지도 지정할 수 있다. "%d와 서식 문자 사이에 원하는 출력 형태를 지정하는데 설명을 나열하는 것보다는 구체적인 예제를 통해 동일한 값을 다양한 형태로 출력하는 실습을 해 보자. 다음 예제는 정수형 변수 Num의 값을 %d 서식으로 출력하되 다양한 양식을 지정해 보았다.

: printf2


#include <Turboc.h>

void main(void)
{
     int Num=123;
     
     printf("-->%d<--\n",Num);
     printf("-->%5d<--\n",Num);
     printf("-->%05d<--\n",Num);
     printf("-->%-5d<--\n",Num);

}

출력 자리수를 확인하기 위해 서식 문자열의 앞뒤에 -->와 <--를 넣어 두고 중간에 세자리의 Num값을 출력했다. 실행 결과는 다음과 같다.

-->123<--
-->  123<--
-->00123<--
-->123 <--

%d만 쓰면 Num의 자리수대로 123만 출력되는데 %와 d사이에 원하는 자리수를 지정하면 Num이 설사 이 자리수보다 작더라도 지정한 자리수만큼 차지하도록 한다. Num이 세 자리밖에 안되지만 %5d 서식을 사용했ㅇ므,ㅡ로 앞쪽에 두 개의 공백을 넣어 다섯  자리를 채운다. 숫자가 많이 들어가는 도표 형식을 출력할 때는 각 자리 수가 들쭉 날쭉한 것보다 일정한 자리수를 지정하며 가지런히 정렬되는 것이 훨씬 더 보기 좋다. 다음 출력 결과 둘을 비교해 보라.

12/9 매출 : 3450000, 매입 : 1200000, 이익 : 820000
12/10 매출 : 6700, 매입 : 8000, 이익 : 10
12/11 매출 : 4500000, 매입 : 0, 이익 : 960000

12/ 9 매출 : 3450000, 매입 : 1200000, 이익 : 820000
12/10 매출 :     6700, 매입 :      8000, 이익 :       10
12/11 매출 : 4500000, 매입 :          0, 이익 : 960000

단, 자리수 지정은 최소한의 지정이므로 만약 자리수보다 값이 더 클 경우에는 지정한 자리수가 무시되고 값의 실제 자리수가 적용된다. 예를 들어 Num이 12345인데 %3d로 이 값을 출력하면 강제로 세 자리가 되는 것이 아니라 다섯 자리가 모두 출력된다. 지정한 자리수를 억지로 맞추기 위해 값을 잘라 버린다면 이는 정확한 출력이 아닐 것이다.

자리수 지정앞에 0을 붙이면 앞쪽에 공백 대신 0을 채운다. %5d 서식은 "123"을 출력하지만 %05d 서식은 "00123"을 출력한다. 이때 앞쪽에 추가된 0을 선행 제로(Leading Zero)라고 하는데 값 자체를 바꾸지 않으면서 자리수만큼 글자를 채우는 역할을 한다. 선행 제로를 붙이지 않으면 10이 9나 8보다 작다고 평가되므로 크기순으로 정렬되어야 하는 수식을 위해 일부러 선행 제로를 삽입하는 경우가 종종 있다. 자리수에 - 를 사용하면 전체 자리수에서 왼쪽으로 정렬되어 공백이 뒤쪽에 배치된다. 다음은 실수를 출력하는 %f 서식에 대해 알아보자.

: printf3


#include <Turboc.h>

void main(void)
{
     double pie=3.14
     printf("-->%f<--\n",pie);
     printf("-->%10f<--\n",pie);
     printf("-->%.2f<--\n",pie);
     printf("-->%10.2f<--\n",pie);
     printf("-->%0.102f<--\n",pie);
     printf("-->%-10.2f<--\n",pie);

}

%d 서식과 마찬가지로 전체 자리수를 지정할 수 있고 앞에 0과 -를 붙여 선행 제로를 붙이거나 왼쪽으로 정렬할 수 있다. 다만 점(.)다음에 소수점 이하 몇 번째 자리까지 출력할 것인지를 따로 지정할 수 있다는 점이 다르다. 출력 결과는 다음과 같다.

-->3.140000<--
-->  3.140000<--
-->3.14<--
-->      3.14<--
-->0000003.14<--
-->3.14      <--

% 서식은 기본적으로 소수점 이하 여섯 자리까지 출력하는데 뒤쪽에 의미 없는 0(이것을 후행 제로 : Trailing Zero라고 한다)이 같이 출력되어 보기에 좋지 않다. 이럴 때 %.2f 서식을 사용하면 소수점 이하 두 자리까지만 출력되므로 보기에 훨씬 더 깔끔하다. %f는 지정한 자리수에서 반올림 처리까지 해 주므로 실수를 출력할 때는 가급적이면 소수점 이하 자리수를 지정하는 것이 좋다. 정수와 실수에 대응되는 두 서식의 완전한 형태는 다음과 같이 정리할 수 있다.

정수 : %[-][0][총자리수]d
실수 : %[-][0][총자리수][.소수점 이하 자리수]f

대표적으로 %d와 %f 서식에 대해서만 출력 양식을 지정하는 방법을 실습해 보았는데 나머지 서식들의 출력 양식도 거의 비슷한 방법으로 사용하면 된다. 더 자세한 사항에 대해서는 필요할 때 레퍼런스를 참고하기 바란다.

이상으로 C의 가장 기본적인 출력 함수인 printf 함수에 대해 알아보았는데 보기보다 훨씬 더 복잡하다는 것을 알 수 있다. 이 방식이 조금 구식인 것처럼 느껴질 수도 있고 배워둘 가치가 없는 것처럼 보이기도 하는데 그렇지 않다. 서식을 사용한 문자열 조립은 서식이 불일치할 때 컴파일러가 오류를 확인할 수 없어 다소 위험한 면이 있기는 하지만 굉장히 직관적이면서 효율적인 방법이다.

최신의 개발툴들도 printf와 유사한 서식 출력을 지원하는데 윈도우즈 API 함수중에 wsprintf 함수가 있고 MFC에도 CSting::Format 함수가 동일한 서식을 사용한다. 심지어는 PHP나 ASP같은 스크립트 언어도 유사한 서식 조립 기능이 있다. 따라서 여기서 서식을 잘 익혀 다음에 유용하게 활용할 수 있을 것이다. printf의 서식들은 애써 외워둘만한 충분한 가치가 있다. 단 개발툴에 따라 서식의 고급 설정 부분은 조금씩 차이가 있으므로 그 부분만 다시 공부하면 된다.

C++ 언어는 printf보다 좀 더 안정적이고 확장 가능한 cout 출력 객체를 제공하는데  이 객체는
printf에 비해 훨씬 진보된 개념임은 분명하다. 그러나 현대적인 그래픽 환경에서 사실 텍스트 화면에 출력할 일은 거의 없다고 볼 수 있으므로 cout도 쓸 일이 많지 않을 것이다. 이에 비해 printf 방식의 서식 조립은 앞으로도 계속 사용될 전망이다.

참고

printf를 영문 발음 그대로 "프린트프"라고 읽는다고 해서 꼭 틀렸다고 할 수는 없다. C 표준 문서에 이 함수를 어떻게 읽으라는 발음기호가 명시되어 이쓴 것은 아니므로 읽는 사람이 편한대로 읽으면 된다. 그러나 혼자서 개발을 하지 않는 한 대화를 해야 하는데 이때 함수 이름을 읽는 방법이 제각각 다르다면 원활한 의사 소통에 방해가 되므로 가급적이면 우세한 발음을 따르는 것이 좋다. 영어 단어는 그대로 읽되 앞뒤에 붙는 약자는 알파벳 그대로 읽는 것이 보편적이다. wsprintf를 "위스프린트프" 이렇게 읽으면 저 사람 참 특이하다는 소리를 듣게 될 것이다.
Posted by 테티스
,