본문 바로가기

컴퓨터/언어,프로그래밍

printf(), scanf() 함수와 특수 기호 사용법


17.1.printf() 함수 사용법


printf() 함수는 큰따옴표 안의 문장을 화면으로 표시합니다.

그동안 우리는 printf() 함수라는 내장함수를 여러 차례 사용했습니다. 내장함수는 C언어에서 기본적으로 지원하는 함수를 말하며 꽤 많은 종류의 함수가 있습니다. 이 중 우리가 가장 많이 사용하는 함수는 printf() 함수입니다.

printf() 함수는 사용 형식은 다음과 같습니다.

[헤더 파일]
<stdio.h>

[헤더 파일의 선언 내용]
int printf (const char *format [, argument, ...]);

[사용 형식]
printf("문장",변수);

[보기1]
printf("변수 a의 값은 3");

[보기2]
printf("변수 a의 값은 %d", a);

[보기3]
printf("변수 a의 값은 %d, b의 값은 %d, c의 값은 %f", a, b, c);

format은 문장의 형식을 뜻합니다.

printf() 함수는 큰따옴표("") 안에 있는 일정한 형식의 문장을 표시해주는 함수입니다. 이때 큰따옴표로 문장을 묶는다는 사실은 매우 중요한 내용이므로 잊지 말기 바랍니다. 헤더 파일의 선언 내용에서 'const char *format' 부분은 일정 형식의 문장이라는 뜻입니다. 지금까지 배운 지식을 토대로 이 문장을 해석하면 '상수 문자형 *형식'이 됩니다. 그러니까 printf() 함수의 문장 형식은 '문자 상수 포인터(문자열 포인터)'를 이용한다는 사실을 알 수 있습니다.

'[, argument, ...]'라는 부분은 [] 기호로 감싼 상태이므로 printf() 함수에서 생략 가능한 명령이라는 의미를 가집니다.

만약 사용한다면 쉼표를 사용하여 앞의 *format 부분과 구별해주어야 하며, 이후로 argument 가 계속 반복된다는 뜻입니다. 'argument, ...'의 의미는 argument를 쉼표로 구별하면서 계속 나올 수 있다는 뜻입니다. argument는 함수에 사용하는 독립적인 변수 또는 인수라는 뜻입니다. 쉽게 말하면 변수 자체를 가리킵니다.

argument는 매개변수 부분으로 생략 가능합니다.

그렇지만 argument를 변수라는 말로만 설명하기는 곤란합니다. 왜냐하면 argument로 변수를 사용할 수도 있지만 계산식이 사용될 수도 있기 때문입니다. 그래서 argument는 변수보다 범위가 넓은 대입식의 개념으로 설명해야 합니다. argument의 역할을 고려할 때 의미상으로는 함수의 '대입 변수'라는 명칭이 어울립니다. 그러나 이런 용어를 사용하는 것은 생소하므로 기존에 사용하던 함수의 '매개변수'로 argument를 대신 하겠습니다.

[보기1]은 argument 부분을 생략하고 *format 부분만 사용한 경우입니다. 그래서 큰따옴표로 감싼 문장을 화면에 보여줍니다. [보기2]는 하나의 변수를 *format 안에 사용한 경우입니다. [보기3]은 a, b, c 세 개의 변수를 계속 나열하고 이를 문장에 사용한 경우입니다.

printf() 함수로 안내문 보여주기



** 따라하기:
(1) 다음의 내용을 c170101.c로 저장합니다.


/* c170101.c - printf() 함수 사용법 */

#include <stdio.h>

void main(void)
{
int n=9;
printf("변수 n의 값은 = %d \n",n);
}



**사진: 170101.c 파일의 내용

(2) 소스 파일을 실행하면 printf() 함수의 %d 부분이 화면으로 출력될 때는 9로 바뀌어 표시됩니다.


**사진: 170101.exe의 실행 결과


17.2.scanf() 함수를 이용해 자료 입력받기


scanf() 함수는 사용자로부터 자료를 입력받는 함수입니다.

scanf() 함수는 사용자로부터 자료를 입력받게 해주는 함수입니다. 이렇게 입력받은 내용은 변수를 이용하여 다양하게 활용할 수 있습니다.

[헤더 파일]
<stdio.h>

[헤더 파일의 선언 내용]
int scanf (const char *format [, address, ...]);

[사용 형식]
scanf("문장",변수의 번지);

[보기1] 변수를 하나 입력받을 때
scanf("%d",&n);

[보기2] 변수를 여러 개 입력받을 때
scanf("%d %d %d",&a,&b,&c);

입력된 자료는 변수에 대입됩니다.

scanf() 함수는 입력란을 만들어 자료를 입력받는 함수입니다. 입력된 자료는 매개변수로 지정한 변수에 대입됩니다. 보기에서는 입력된 자료는 n이라는 변수에 대입됩니다. 이때 %d 기호를 사용했기 때문에 scanf() 함수로 입력받을 수 있는 자료는 정수형 자료가 됩니다.

문장 형식(format)을 통해 입력된 자료를 변수에 대입한다는 점에서 변수의 값을 문장 형식에 사용하는 printf() 함수와는 출력 방향이 반대인 셈입니다.

[보기] printf() 함수와 scanf() 함수의 차이
scanf("%d",&n); /* %d의 값이 n에 대입 */
printf("%d",n); /* n의 값이 %d에 대입 */

scanf() 함수와 printf() 함수가 다른 점은 printf() 함수는 변수 이름만 사용했지만 scanf() 함수는 변수의 번지를 사용한다는 점입니다. scanf() 함수로 입력된 값을 변수에 대입할 때 변수 이름을 사용하지 않고 주소(=번지)를 이용함에 주의해야 합니다.

&는 번지 연산자로 &n은 변수 n의 번지(=주소)를 뜻합니다.

&n이라는 명령은 변수 n의 주소를 뜻하는 명령입니다. 번지는 PC의 기억 장치(메모리)에서 사용하는 주소를 뜻합니다. 주소는 기억 장치(메모리) 외에도 각종 부품에서 사용하며 각각 고유의 주소를 가지고 있습니다.

&는 번지를 나타낼 때 사용하는 번지 연산자로 나중에 번지 연산자 부분과 포인터를 다룰 때 좀더 자세하게 다루겠습니다. 다만 지금은 &이 번지 연산자라는 사실과 &n이 n의 번지를 뜻하며, scanf() 함수를 사용할 때 &n의 형태로 사용한다는 사실만 기억하면 됩니다.

scanf() 함수를 사용하기 전에 printf() 함수로 안내문을 보여주는 것이 좋습니다.

scanf() 함수로 입력된 자료는 변수에 저장됩니다. 이때 입력받을 수 있는 자료형의 종류가 정해진 상태이므로 사용자가 제대로 입력해주어야 합니다. 정수형을 입력받아야 하는데 실수형을 입력해서는 안됩니다. 따라서 scanf() 함수로 자료를 입력받기 전에 어떤 자료를 입력해야 하는지 알려주는 안내문이 필요합니다. 이 안내문은 printf() 함수를 통해 미리 보여줄 수 있습니다.

다음 예제는 두 개의 수를 입력받아 입력된 수를 다시 화면으로 알려주는 예제입니다.


** 따라하기:
(1) 다음의 내용을 c170201.c로 저장합니다.


/* c170201.c - scanf() 함수 사용하기 */

#include <stdio.h>

void main(void)
{ int a, b;
printf("숫자를 두 개 입력하세요(보기: 3 5) : ");
scanf("%d %d",&a,&b);
printf("입력한 수는 %d과 %d입니다. \n",a,b);
}




**사진: 170201.c 파일의 내용

(2) c170201.exe를 실행시키면 안내문이 나타납니다.



**사진: 170201.exe의 실행 결과

(3) 3과 4를 입력하고 [Enter]를 누릅니다.



**사진: 두 개의 숫자를 입력합니다.

(4) 입력한 수인 3과 4를 화면으로 보여줍니다.



**사진: 입력된 수를 화면으로 출력합니다.


세 개 이상의 수를 입력받기

두 개의 수를 입력받을 수 있다면 세 개 이상의 수도 같은 방식으로 입력받을 수 있습니다. 이번에는 세 개의 수를 입력받아 세 수의 곱을 알려주는 예제를 만들어봅시다. 이때 주의할 점은 세 수를 구별해야 하므로 format형식에 %d와의 사이에 간격을 만들어주어야 한다는 점입니다. 따라서 '%d%d%d'와 같이 사용하지 않고 '%d %d %d'처럼 최소한 한 칸 이상의 빈 칸을 이용하는 것이 요령입니다.


** 따라하기:
(1) 다음의 내용을 c170202.c로 저장합니다.


/* c170202.c - scanf() 함수로 세 수의 곱 구하기 */

#include <stdio.h>

void main(void)
{ int a, b, c, d;
printf("숫자를 세 개 입력하세요(보기: 3 5 8) : ");
scanf("%d %d %d",&a,&b,&c);
d=a*b*c;
printf("입력한 수 : %d, %d, %d \n",a,b,c);
printf("세 수의 곱: %d \n",d);
}




**사진: c170202.c의 내용

(2) c170202.c를 컴파일한 뒤 실행시키면 숫자 입력을 기다리는 화면이 나옵니다.



**사진: c170202.exe 실행 결과

(3) 2 3 6 을 차례대로 입력합니다. 이때 각 숫자 사이를 빈 칸으로 띄우고 마지막에는 [Enter]를 누릅니다.



**사진: 세 개의 수를 입력합니다.

(4) 입력한 수와 세 수의 곱인 36을 화면에 보여줍니다.



**사진: 세 수의 곱을 화면으로 출력합니다.

(5) 다시 한 번 c170202.exe를 실행시켜 이번에는 9 9 101을 차례대로 입력하면 세 수의 곱인 8181을 화면으로 출력해줍니다.



**사진: 세 수의 곱을 계산하여 보여줍니다.


자료형을 잘못 지정하면 예상치 못한 결과가 나타납니다.

c170202.exe를 실행시키고 적은 숫자를 입력하면 세 수의 곱을 잘 보여줍니다. 그렇지만 큰 수를 입력하면 생각하지 못한 결과를 출력합니다. 예를 들어 100 100 9를 입력했다고 합시다. 세 수의 곱은 90,000이 나와야 합니다. 그렇지만 실제 출력 결과는 24464로 나옵니다. 90,000이 아닌 엉뚱한 숫자가 나오는 이유는 세 수의 곱을 출력하는 변수가 int형이거나 특수문자가 %d로 지정되었기 때문입니다. 정수형의 경우 -32768~32767까지의 숫자를 표현할 수 있기 때문에 이 범위를 넘어가는 숫자는 화면에 표시할 수 없습니다. 그래서 32767보다 클 경우에는 원하는 결과를 표시하지 못하는 것입니다.



**사진: 100*100*9의 결과로 90,000이 아닌 24464가 출력되는 화면

따라서 100*100*9의 결과인 90,000을 제대로 출력하려면 변수의 자료형을 모두 long형으로 바꾸어야 합니다. long형 자료의 사용방법은 %문자의 사용법을 설명할 때 다시 다루겠습니다.

프로그래머는 사용자의 입력 오류에 대비해야 합니다.

scanf() 함수를 주의할 때 주의할 내용이 또 있습니다. 세 개의 수를 입력받도록 했는데 사용자가 2개만 입력하거나 4개 이상을 입력하는 경우의 처리 요령입니다. 만약 2개만 입력하고 [Enter]를 눌렀다면 남은 1개를 입력할 때까지 기다립니다. 그런데 사용자는 프로그램이 멈춘 것으로 착각하기 쉽습니다. 그리고 3개가 넘는 수를 입력했다면 처음의 세 수만 사용하고 뒤에 입력된 수는 버립니다.



**사진: 네 개 이상의 수를 입력하면 앞의 세 개만 사용하고 나머지는 버립니다.



**사진: 숫자를 두 개만 입력하면 남은 수의 입력을 기다립니다.

따라서 이런 문제를 예방하려면 오류 처리 루틴이라는 부분을 삽입해주어야 합니다. 사용자가 잘못 입력할 가능성에 대비하여 잘못 입력했을 경우 오류가 발생하지 않도록 처리하는 과정이 프로그램 안에 삽입되어야 합니다. 그렇지만 초보자가 오류 처리 과정을 제대로 만들어주기는 쉽지 않습니다. 오류 처리 과정을 제대로 만들어주려면 키보드의 키 입력 상황을 제대로 파악해야 하는데 이를 위해서 입출력 과정에 대한 정확한 이해와 입출력 관련 함수를 잘 다루어야 하기 때문입니다. 사용자의 입력 잘못에 대한 처리 능력은 한 순간에 향상되지 않고 프로그램 실력이 향상되면서 조금씩 향상된다는 점을 말씀 드립니다.

17.3.줄바꿈문자 \n의 의미


\n 기호는 줄바꿈문자를 나타내는 특수문자입니다.

그 동안 사용한 예제를 보면 printf() 함수의 문장 뒤에 \n 기호를 붙이는 경우가 많았습니다. 맨 마지막에 붙은 \n에 대해서는 간단하게 말씀드렸습니다. \n 줄바꿈문자를 나타내는 특수한 기호입니다. \ 문자와 n이라는 문자를 출력하라는 뜻이 아닙니다.

줄바꿈문자 \n을 사용하면 줄을 바꾸게 됩니다. 줄을 바꾸라는 명령을 내리면 커서는 다음 줄의 첫 번째 칸에서 깜박거립니다. 우리들이 도스명령어를 치거나 글틀에서 문서를 작성하면서 [Enter]키를 치면 다음 줄의 첫 번째 칸으로 가는 것을 볼 수 있습니다. 이것을 줄바꿈이라고 말하는데 컴퓨터는 두 단계 과정을 거쳐서 줄바꿈을 합니다.

컴퓨터에서 줄바꿈은 캐리지리턴과 라인피드의 두 가지 과정이 합쳐진 것입니다.

줄바꿈 과정은 캐리지리턴(carriage return)과 라인피드(line feed)라는 두 가지 단계를 거칩니다. 캐리지리턴은 커서를 그 줄의 처음으로 옮긴다는 뜻입니다. 라인피드는 커서 위치에서 한 줄 밑으로 커서를 옮긴다는 뜻입니다. 그러니까 다음줄 첫 번째 칸으로 커서가 이동하는 과정은 먼저 캐리지리턴이라는 동작을 통해서 현재 줄의 첫 번째 칸으로 이동한 뒤에 그곳에서 다시 한 칸을 내리는 과정(라인피드해서)이 추가되어 이루어집니다. 간단한 그림으로 설명하면 다음과 같은 과정입니다.

1.
sample_ : 원래는 이런 문장입니다. 커서가 맨 끝에 와 있죠.

2.
sample[Enter] : [Enter]를 입력합니다.

3.

_sample[Enter] : 먼저 캐리지리턴을 해서 첫 번째 칸으로 커서를 이동시킵니다.

4.
sample[Enter] : 라인피드를 해서 커서를 밑줄로 이동시킵니다.
_

5.
sample : 그래서 커서가 다음 줄 첫 번째 칸에서 깜박이는 겁니다.
_

만약 \n이라는 줄바꿈 문자를 사용하지 않는다면 이어서 나오는 printf() 함수의 문장은 지금 출력한 문장에 붙어서 화면에 출력될 겁니다. 그럼 보기에 좋지 않겠죠? 그러니까 원래는 "" 안에 원하는 문장을 아무 것이나 넣을 수 있지만 문장 안에 \라는 문자가 나오면 일단 특수기호라고 생각을 합니다. 그래서 컴파일러가 기계어로 번역을 할 때 특수문자로 번역을 하는 겁니다.


** 따라하기:
(1) 다음의 내용을 c170301.c로 저장합니다.


/* c170301.c - 줄바꿈문자 사용하기 */

#include <stdio.h>

void main(void)
{
printf("안녕하세요? \n 제 이름은 \n 김중태입니다.");
}




**사진: c170301.c의 내용

(2) 줄바꿈문자인 \n을 사용한 곳마다 줄바꿈이 일어나 세 개의 문장으로 분리되었습니다.



**사진: c170301.exe의 실행 결과


\n 기호를 연이어 사용하면 반복된 수만큼 줄바꿈이 일어납니다.

그렇다면 \n 기호를 여러 번 사용할 경우 줄바꿈이 연달아 일어날까요? 예. 사용한 수만큼 줄바꿈이 일어납니다.


** 따라하기:
(1) 다음의 내용을 c170302.c로 저장합니다.


/* c170302.c - 줄바꿈문자 사용하기 */

#include <stdio.h>

void main(void)
{
printf("안녕하세요? \n 제 이름은 \n\n\n\n\n 김중태입니다.");
}




**사진: c170302.c 파일 내용

(2) 줄바꿈문자인 \n을 사용한 곳마다 줄바꿈이 일어나 '김중태입니다' 문장은 이 전 줄보다 다섯 줄 아래에 표시되었습니다.



**사진: \n 기호가 들어간 곳마다 줄바꿈이 일어났습니다.


예제의 문장은 큰따옴표로 묶인 한 문장입니다. 그렇지만 문장 안에 \n 기호를 여러 번 사용했습니다. 특히 '김중태입니다' 이름 앞에 다섯 번을 사용했습니다. 그래서 다섯 번의 줄바꿈이 연달아 발생하였고 그 결과 이전 줄로부터 다섯 번째 줄에 '김중태입니다'라는 문장이 표시되었습니다.

\n 기호의 연속 사용으로 빈 줄을 삽입할 수 있습니다.

결국 \n 기호를 한 번 사용하면 줄바꿈만 일어나지만 두 번 이상 사용할 경우에는 빈 줄을 삽입하는 효과가 생깁니다. 따라서 어떤 문장을 화면에 출력한 뒤에 빈 줄을 몇 줄 삽입하고 다음 문장을 출력하고자 할 때는 \n 기호의 연속 사용을 통해 원하는 수의 빈 줄을 삽입시킬 수 있습니다. 다음 보기의 결과를 예상해보기 바랍니다.

[보기]
printf("1번 줄.\n2번 줄.\n\n4번 줄.\n\n\n\n8번 줄.");

'1번 줄.'이라는 문장을 출력한 다음에 \n 기호에 의해 커서를 다음 줄로 옮겼습니다. 따라서 두 번째 줄에 '2번 줄.' 문장이 표시됩니다. 다시 커서를 두 줄 바꾸어 '4번 줄.'을 출력하고 다시 네 칸 밑으로 옮겨서 '8번 줄.'이라고 표시합니다.
그리고 마지막에는 \n을 사용하지 않았기 때문에 '8번 줄.' 뒤에서 깜박거릴 겁니다. 이 문장대로 프로그램을 작성하고 컴파일하면 아래와 같이 화면에 출력됩니다.

[실행 결과]
1번 줄.
2번 줄.

4번 줄.



8번 줄.

**요약: \n은 라인피드를 뜻하는 ESC문자열인데, 특별한 약속을 하지 않으면 화면에 출력할 때 캐리지리턴과 라인피드코드를 동시에 출력해줍니다. 즉 다음 줄 첫 번째 칸으로 이동하라는 뜻을 지닌 특수문자입니다.



**웃으며 배우는 C언어 습관: 용도에 맞는 함수와 명령어를

어느날 젊은 여자 둘이 과일가게에 왔습니다.

여자1 : 아저씨. 바나나 2개만 주세요.
여자2 : 큰걸로 골라주세요.
주인 : 3개 2000원 줄께.
여자1 : 3개 2000원이래. 살까?
여자2 : 그럼 1개는 남잖아.
여자1 : 1개 남은건 먹으면 되지.
주인 : ?

그럼 원래 바나나의 용도는 무엇이란 말인가요? 이 아가씨들처럼 바나나를 다른 용도에 쓰면서 낭비하지 않도록 합시다. 먹는 것 가지고 장난 치면 벌 받으니까요. 문자를 다루기 위해서 문자열을 다루는 함수를 쓰거나, 정수를 다루면서 실수를 다루는 함수를 쓰는 것도 일종의 낭비입니다. 함수는 다 제 나름대로의 용도가 있습니다. 제 용도에 적절하게 사용하는 것이 프로그램을 잘 짜는 사람입니다.


17.4.ESC따름부호(\ 기호)


17.4.1.ESC따름부호와 ESC문자열의 종류


\기호는 ESC따름부호입니다.

줄바꿈문자 \n처럼 \ 기호를 앞에 붙인 문자를 확장문자, 또는 확장열, ESC코드, ESC 문자, ESC 문자열 등으로 다양하게 부릅니다. \ 기호가 의미하는 것은 'ESC sequence code'를 의미하므로 가장 정확한 표현은 'ESC따름부호'가 됩니다. 그리고 ESC따름부호를 이용하여 표현하는 문자들의 집합을 가리킬 때 ESC문자열 또는 ESC문자라는 표현을 많이 사용합니다.

ESC따름부호는 특수한 문자를 표시할 때 주로 사용합니다. 보통 우리가 사용하는 A~Z, a~z까지의 문자나 숫자 등은 타자를 쳐서 바로 나타낼 수 있습니다. 그러나 줄바꿈 문자를 비롯해서 backspace문자, tab문자, 삑 소리, 라인피드기호, 괘선문자 등은 타자를 쳐서 나타낼 수 없습니다. 그래서 이런 특수한 문자를 표시하기 위해서 \ 기호를 사용합니다.

\ 기호는 특수 문자를 입력하기 위해 사용합니다.

삑소리나 탭처럼 눈으로 보기 어려운 이런 특수 문자는 키보드를 통해서 바로 입력할 수 있는 문자가 아닙니다. 그래서 ESC따름부호를 이용하여 입력하는 것입니다. 그러니까 \ 기호는 ASCII코드(아스키코드) 중에서 우리가 키보드로 입력할 수 없는 기호들을 표현하고자 할 때 사용하는 형식입니다.

\ 기호를 이용해 약속된 형식에 맞게 표현식을 사용하면 원하는 특수문자를 표시할 수 있습니다. 아래의 표는 일반적으로 많이 사용하는 ESC문자입니다. 이 표에 제시된 것 외에도 더 많은 문자가 있지만 가장 많이 사용하는 문자들만 정리했습니다.


**표: C언어에서 사용하는 \기호(ESC문자)의 종류
\a : 삑(bell) 소리를 냅니다. 이 기호를 사용하면 컴퓨터에서 오류를 나타내기 위해서 '삑'하고 울리는 소리가 납니다. 컴퓨터에서는 '삑' 하는 소리도 일종의 문자에 해당하는 셈입니다.
\b : 백스페이스를 뜻합니다. 그러니까 화면에 글씨를 출력했다면 커서를 다시 앞으로 한 칸 이동시킵니다.
\n : 라인피드를 뜻하므로 줄을 바꾸어 새로운 줄을 시작하라는 뜻입니다. 원래는 커서를 다음 줄로 이동시키는 일만 합니다. 그런데 터보C에서는 특별한 조건이 달지 않을 경우 다음 줄의 첫 번째 칸으로 이동시킵니다.
\r : 캐리지 리턴을 뜻합니다. 그러니까 커서를 현재 줄의 첫 번째 칸으로 이동시킵니다.
\t : 탭을 뜻하는 기호입니다. 탭을 설정한 크기만큼 커서를 이동시킵니다. 당분간은 탭을 사용할 일이 없으므로 탭에 대한 설명은 생략하겠습니다.
\\ : 역빗금(\,back slash)문자를 표시하라는 뜻입니다.
\' : 작은따옴표(single quotation)를 표시합니다.
\" : 큰따옴표(double quotation)를 표시합니다.


'\n'은 라인피드를 나타내지만 예외적으로 C언어에서는 '\r\n'의 값으로 출력해줍니다.

ESC문자를 보면 \n이 라인피드이고, \r이 캐리지 리턴이므로 다음줄 첫 번째 칸으로 이동하기 위해서는 \r\n이라고 써야하지 않을까 하고 생각하는 분이 있을 겁니다. 맞습니다. 제대로 쓴다면 먼저 캐리지리턴을 하고 라인피드를 해야 하므로 \r\n이라고 써야 맞습니다. 그러나 터보C는 특별한 약속이 없는 한 \n이라는 기호를 만나면 캐리지리턴하고 라인피드 동작을 동시에 해서 화면에 커서를 이동시킵니다. 저장할 때는 \n이라고 저장하고 화면이나 프린터로 문장을 보여줄 때는 \r\n처럼 행동하는 겁니다. 그 까닭은 \r\n이라고 저장하다보니 자료의 크기가 많아지기 때문입니다. 그래서 저장할 때는 라인피드를 뜻하는 \n으로만 저장하고, 이를 화면에 출력할 때는 \r\n으로 출력하는 겁니다. 가능하면 자료를 저장할 때 적은 바이트수로 저장하려다보니 이런 예외 규칙을 만든 겁니다.

\ 기호를 표시하려면 '\\'이라는 특수문자를 이용해야 합니다.

\기호가 ESC따름문자로 사용하기 때문에 printf() 함수에 아무 생각 없이 사용하면 특수 기호로 인식하게 됩니다. 따라서 일반 문자로서 \를 표현하려면 \\라고 표기해야 합니다.

\ 기호는 화폐 단위로 대체되어 표시되므로 ₩ 기호로 표시됩니다.

이 부분에서 한글윈도를 사용하는 국내 사용자들이 주의할 점이 있습니다. \ 기호는 원래 각 나라의 화폐단위를 대신할 수 있도록 설정된 기호입니다. 때문에 영문도스나 영문윈도에서는 \ 기호 모습 그대로 보이지만 한글도스나 한글윈도에서는 우리나라의 화폐단위인 ₩ 기호로 나타납니다. 따라서 컴퓨터에서 ₩ 기호로 표시되는 부분은 \ 기호와 같은 기호임을 숙지하기 바랍니다.

다음과 같은 문장을 화면에 출력하고자 한다고 합시다.

[보기1]
C:\ 는 C 드라이브의 루트 디렉토리입니다.

이때 C:\이라는 글자에 \가 들어갑니다. 만약 아무런 생각 없이 C:\라고 쓰면 이상한 결과가 나올겁니다. 한 번 시험삼아서 써보시기 바랍니다. 아마 \ 글씨가 화면에 출력되지 않을 겁니다. C:\이라는 부분에 \ 기호가 들어가는데 아무런 조치 없이 그대로 \ 기호를 사용하면 화면에 \ 기호가 출력되지 않습니다.


** 따라하기:
(1) 다음의 내용을 c170401.c로 저장합니다.


/* c170401.c - / 기호를 사용 안할 경우 */

#include <stdio.h>

void main(void)
{
printf("C:\ 는 C 드라이브의 루트 디렉토리입니다.");
}




**사진: c170401.c 파일 내용

(2) 의도와는 달리 \ 기호가 표시되지 않습니다.



**사진: \ 기호가 표시되지 않습니다.


이럴 때는 다음과 같이 쓰면 됩니다.

printf("C:\\ 는 C 드라이브의 루트 디렉토리입니다.");

조금 번거롭기는 하지만 이렇게 해서 \ 글자를 화면에 출력할 수 있습니다.


** 따라하기:
(1) 다음의 내용을 c170402.c로 저장합니다.


/* c170402.c - / 기호를 사용 할 경우 */

#include <stdio.h>

void main(void)
{
printf("C:\\ 는 C 드라이브의 루트 디렉토리입니다.");
}




**사진: c170402.c 파일 내용

(2) 이번에는 C:\(C:₩)가 제대로 표시됩니다.


**사진: c170402.exe 실행 결과


큰따옴표를 비롯한 특수 문자도 \ 기호를 이용하여 표현할 수 있습니다.

\ 기호를 사용할 수 없다면 구두점으로 사용하는 " 기호나 ' 기호도 사용할 수 없다는 것을 눈치챌 수 있습니다. 큰따옴표는 출력할 문장의 처음과 끝을 나타내는 특수기호이며 ' 기호 역시 구두점으로 사용하는 특수 기호입니다. 따라서 " 기호를 사용하려면 \" 형식을 이용해야 합니다.

다음 보기처럼 큰따옴표가 들어가는 문장을 표시하는 경우를 생각합시다.

안녕하세요? "김중태"입니다.

이 문장을 표시하려면 printf() 함수 안에 \" 기호를 삽입해야 합니다.

[틀림]
printf("안녕하세요? "김중태"입니다.")

[맞음]
printf("안녕하세요? \"김중태\"입니다.")


** 따라하기:
(1) 다음의 내용을 c170403.c로 저장합니다.


/* c170403.c - / 기호를 사용 할 경우 */

#include <stdio.h>

void main(void)
{
printf("안녕하세요? \"김중태\"입니다.\n");
printf("안녕하세요? \'김중태\'입니다.\n");
}




**사진: c170403.c 파일 내용

(2) ESC따름부호를 사용한 까닭에 ' " 기호 등이 모두 제대로 표시됩니다.



**사진: c170403.exe 실행 결과


**요약: \ 기호를 붙여서 사용하는 문자를 ESC따름부호이라고 하는데, 특수문자를 출력하고자 할 때 주로 사용합니다. 따옴표나 역빗금을 표시하려면 앞에 \ 기호를 붙여서 사용합니다.


17.4.2.8진수와 16진수를 이용한 문자 상수 표기법


문자 상수를 사용할 때 16진수 표기법을 많이 사용합니다.

14장에서 간단하게 16진수를 이용한 문자 상수 표기법을 간단하게 소개하면서 문자 상수를 16진수로 표기하는 이유도 설명했습니다. 프로그래머가 16진수 표기법을 사용하는 이유는 가장 정확하게 원하는 문자를 표기할 수 있기 때문입니다. 그때 예를 든 보기를 다시 한 번 살펴봅시다.

[보기] 문자 상수의 16진수 표기법
'\x0d' /* ASCII 코드 13번인 [Enter]키 값을 표시 */
'\x1b' /* ASCII 코드 27번인 [ESC]키 값을 표시 */
'\x41' /* ASCII 코드 65번인 A자 표시 */
'\x42' /* ASCII 코드 66번인 B자 표시 */

보기를 보면 프로그래머가 16진수 표기법을 사용하는 이유를 쉽게 이해할 수 있습니다. 16진수 표기법을 사용하면 다음과 같은 장점이 있습니다.

[문자 상수의 16진수 표기법이 주는 장점]


1. 특수 문자도 문자 상수로 이용할 수 있습니다.

A자나 a, b, c처럼 키보드에 인쇄된 일반 문자는 일반적인 문자 상수 표기법으로 표시할 수 있지만 [Enter]키나 [ESC]키값은 표기할 수 없습니다. 그러나 ESC따름부호와 16진수 표기법을 이용하면 키보드에 인쇄되지 않은 특수 문자도 문자 상수로 사용할 수 있습니다.

즉 ASCII 코드로 32번 이하의 특수 문자나 127번 이후의 확장 문자를 사용할 경우 일반 문자처럼 키보드를 통합 입력으로는 사용이 불가능합니다. 오직 16진수 표기법만이 대안이 될 수 있습니다.

2. 정수 상수와 문자 상수를 혼동할 염려가 없습니다.

'1'의 경우 정수 1과 혼동될 염려가 있습니다. 그렇지만 '\x31'은 정수 1과 혼동되지 않습니다. 물론 초보자가 처음 '\x31'을 봤을 때 문자 상수 '1'을 떠올리기는 어렵지만 정수 1과 혼동하면서 발생하는 오류를 막을 수 있어 유용합니다.

3. 비슷한 기호를 혼동할 우려가 없으며, 특수 기호인지 여부를 고민할 필요가 없습니다.

표기상 혼동이 올 우려가 있는 특수 문자를 소스 파일에 사용할 경우 오타로 인한 논리적인 오류를 안을 가능성이 높습니다. 예를 들어서 다음 표기법을 보기 바랍니다.

[보기1]
1. ''' /* 작은 따옴표 세 개 연달아 표기한 경우 */
2. '"' /* 작은 따옴표, 큰따옴표, 작은따옴표를 표기한 경우 */

[보기1]의 경우 일단 시각적으로 볼 때 어떤 것을 표기하고자 했는지 명확하지 않습니다. 1번의 경우 작은따옴표 세 개(''')가 연달아 있는 것 같기도 하고, 큰따옴표와 작은따옴표("'), 작은따옴표와 큰따옴표('")가 있는 것처럼 보이기도 합니다.
2번의 경우는 작은따옴표 네 개('''')가 연달아 표기된 것 같기도 하고, 큰따옴표 두 개("")가 표기된 것 같기도 하고, 작은따옴표 작은따옴표 큰따옴표(''"), 큰따옴표 작은따옴표 작은따옴표("'')로 보이기도 합니다. 물론 정답은 이 중에 없습니다. 정답은 작은따옴표 큰따옴표 작은따옴표의 표기입니다.

[보기1]의 예는 우리가 자주 사용하는 표기법이지만 눈으로 봐서는 몇 가지의 표기법으로 잘못 착각하기 쉬운 표기법입니다.
이 표기법을 다음과 같이 했다면 혼동되지 않았을 겁니다.

[보기2]
1. '\x27' /* 작은 따옴표 세 개 연달아 표기한 경우 */
2. '\x22' /* 작은 따옴표, 큰따옴표, 작은따옴표를 표기한 경우 */

[보기2]의 1번처럼 16진수로 표기했다면 '\x27'을 보는 순간 작은 따옴표를 문자 상수로 표기한 것이라는 사실을 알 수 있고, 여러 가지 표기법으로 착각하지 않습니다.

다른 예를 한 번 봅시다.

[보기3]
1. /와 \
2. '(작은따옴표)와 `(모점,키보드에서 1번 왼쪽 문자)와 ,(쉼표)
3. :과 ;과 |
4. -(붙임표,빼기표)와 _(밑줄)

[보기3]은 혼동하기 쉬운 문자의 몇 가지 경우입니다. 이들 문자를 섞어쓸 경우 그야말로 혼동이 될 수밖에 없겠죠.

[보기4]
1. "'`'기호와 ''', |:;기호"
2. printf("\"이것이 \'C:\\'를 가리킵니다"");

보기4의 1번을 보면 큰따옴표 작음따옴표 모점 작은따옴표로 시작됩니다. 그런데 눈으로 봐서는 도대체 기호를 구분하기가 어렵죠. 더 큰 문제는 ESC따름부호의 사용 여부입니다. [보기4]의 2번 예를 보면 알 수 있습니다.

큰따옴표를 예로 듭시다. 작은따옴표를 문자 상수로 사용할 때는 '\''와 같이 ESC따름부호를 붙여서 사용해야 합니다. 반면 큰따옴표는 ESC따름부호를 붙이지 않습니다. 그렇지만 printf() 함수의 문장 안이라면이야기가 달라집니다. 문자열 형식의 문장 안에서는 큰따옴표도 ESC따름부호를 붙여서 사용해야 합니다. 이런 미묘한 차이는 종종 착각하기 쉽습니다. 그래서 2번의 경우처럼 어떤 경우처럼 잘못 표기하는 경우가 생기는 것입니다. 문자 상수에서는 작은따옴표 앞에 \ 기호를 붙여야 하는 반면 printf() 함수 안에서는 큰따옴표에 \ 기호를 붙여야 합니다. 이러니 혼란이 착각하기 쉬운 것입니다.

[보기5] 큰따옴표와 작은따옴표의 틀린 사용법
kim='''; /* 작은따옴표 앞에 \ 기호를 붙여야 함 */
kim='\"' /* 큰따옴표 앞에 \ 기호가 없어야 함 */
printf(""A""); /* 큰따옴표 앞에 \ 기호를 붙여야 함 */
printf("\'A\'"); /* 작은따옴표 앞에 \ 기호가 없어야 함 */
printf("'A'\"); /* format 형식의 끝을 나타내는 " 기호에 \를 붙인 것이 잘못임 */

[보기6] 큰따옴표와 작은따옴표의 올바른 사용법
kim='\'';
kim='"'
printf("\"A\"");
printf("'A'");

[보기5]와 [보기6]을 보니 문자를 이용한 표기법의 단점을 쉽게 알 수 있죠? 프로그램을 꽤 많이 짠 프로그래머도 자주 혼란을 겪습니다. kim='"';라는 명령을 쓰고도 우선 시각적으로 오타가 있는 것은 아닌지 확인해야 하고, 작은따옴표를 표시할 때 \ 기호를 붙여야 하는 상황인가 아닌가를 골똘하게 생각합니다. 왜냐하면 상황에 따라서 붙이기도 하고 안붙이기도 하기 때문에 혼란스러운 것이죠.

`'",;:|~!@#$%^&*()-_=\/<>[]{} 등의 기호문자를 표기해야 할 경우 특히 이 문제는 프로그래머를 곤혹스럽게 만듭니다. `'",;:|~!@#$%^&*()-_=\/<>[]{} 중에서 어떤 것이 \기호를 붙여서 표기해야 하는 문자일까요? 정말 고민이 됩니다.

그렇지만 16진수를 이용한다면 이런 고민을 할 이유가 없습니다.

[보기7] 16진수 표기법
kim='\x22' /* 큰따옴표 */
kim='\x27' /* 작은따옴표 */
kim='\x2f' /* / 기호 */
kim='\x5c' /* \ 기호 */

[보기7]의 경우처럼 ASCII 코드값을 이용하여 16진수로 표기하면 원하는 문자를 정확하게 표기할 수 있습니다.

이번에는 다음의 경우를 봅시다.

[보기8]
a='a';
b='\a';
printf("변수 b는 \\a로 표기되며 결과는 \a입니다.");

[보기8]처럼 printf() 함수를 사용했을 경우 \\a를 '역빗금 기호 표기(\\)+a자'로 인식할 것인지 '역빗금(\)+삑소리(\a)'로 인식할 것인지 여부도 혼동할 수 있습니다. '\a' 표기는 '\x07'표기보다 이해가 쉽습니다. 그래서 많은 사람들이 ESC따름부호를 이용한 ESC문자열 표기법을 사용합니다. 또한 대부분의 사람이 문자 상수로 삑소리를 사용할 때 '\a' 표기를 사용합니다. 그렇지만 '\\a' 표기에서 보여준 것처럼 논란의 여지는 있습니다.

4. 16진수 표기법은 시스템이나 컴파일러의 차이에 따른 영향을 받지 않습니다.

'\a' 표기법은 삑(bell)소리를 냅니다. 그렇지만 시스템이나 운영체제, 컴파일러에 따라서는 \a 표기법을 지원하지 않거나 다른 문자로 번역할 수 있습니다. 그렇지만 '\x07'은 ASCII 코드를 사용하는 시스템이라면 항상 7번 삑소리로 번역됩니다.

16진수 표기법은 문자 상수를 정확하게 사용하는 효과를 가집니다.

지금까지 말한 몇 가지 이유로 프로그래머들은 16진수 표기법을 많이 사용합니다. 정확하게 필요한 문자를 표기할 수 있고, 특수 문자를 사용할 수 있으며, 논리적 오류가 발생할 수 있는 여지를 크게 줄일 수 있기 때문입니다.

16진수로 표기할 때는 한 자리나 두 자리로 표기하는 것은 가능하지만 세 자리로 표기하는 것은 안됩니다. 이는 16진수 세 자리면 문자 상수의 범위를 넘어가기 때문입니다.

[보기9] 틀린 표기
kim='\x100' /* 세 자리로 표기해서 틀림 */
kim='\xffa' /* 세 자리로 표기해서 틀림 */

8진수로도 문자 상수를 표기할 수 있습니다.

정수 상수와 마찬가지로 문자 상수도 8진수를 이용한 표기법을 사용할 수 있습니다. 8진수로 표기하고자 한다면 \ 기호를 붙여 0으로 시작하면 됩니다.

[보기1] 팔진수로 문자 상수 표기하기
kimbell='\007';
kimbell='\07';
kimbell='\7'

8진수 표기 때 앞 부분의 0은 생략할 수 있습니다.

이때 십진수를 표시하는 앞머리의 0을 생략할 수 있습니다. 그래서 '\007' '\07' '\7'은 모두 같은 7번 ASCII 문자를 뜻합니다. 그렇지만 중간이나 뒷부분의 0을 생략하는 것은 안됩니다. 이런 경우 엉뚱한 숫자로 인식되기 때문입니다.
예를 들어 '\070'이라고 표기해야 할 문자를 '\07'이라고 표기한다면 8진수로 70번(십진수로는 56번) 문자가 아닌 7번 문자가 됩니다. 따라서 8진수 70번 문자를 표기할 때는 '\070'이나 '\70'으로 표기해야 합니다.

문자 상수를 8진수로 표기할 때는 1~3자리로 표기합니다.

또 한 가지 알아둘 점은 자료형에 따라서 8진수 표기법의 자리수를 정확하게 맞추어 써야 한다는 점입니다. 예를 들어 8진수의 경우 세 자리로 문자 상수를 표기해야 합니다. 따라서 다음과 같이 세 자리, 두 자리, 한 자리 표기는 맞습니다.

[보기2] 팔진수로 문자 상수 표기하기
aja='\101'; /* A자가 표시됨 */
aja='\102'; /* B자가 표시됨 */
thirdja='\003'; /* 8진수로 3번 문자 표기 */
thirdja='\03'; /* 8진수로 3번 문자 표기 */
thirdja='\3'; /* 8진수로 3번 문자 표기 */

그렇지만 네 자리로 표기하는 것은 잘못된 표기입니다. 이는 문자 상수의 범위를 넘어가는 수를 표기할 수 있기 때문입니다.

[보기3] 잘못 표기한 팔진수로 문자 상수 표기법
aja='\0101';
thirdja='\0003';

팔진수 표기법은 16진수 표기법처럼 많이 사용하지 않습니다. 따라서 팔진수 표기법으로 표기할 수도 있다는 정도만 알아두셔도 됩니다.

17.5.대체문자 % 기호의 종류와 의미


% 기호는 대체문자로 특정 자료를 대체할 수 있는 문자입니다.

이제 그 동안 사용한 %d의 의미에 대해서 알아볼 차례입니다. %d는 % 기호 사용법 중의 하나로 정수형을 나타내는 대체문자입니다. 대체문자 또는 치환문자라고 부르는 %기호는 특정 변수나 자료를 대체할 수 있는 문자를 뜻합니다. 다음 보기에서 %d는 변수 a를 대신하는 대체문자입니다.

[보기]
printf("입력한 수는 %d \n",a);

이처럼 % 기호는 다른 인수로부터 입력받은 변수나 상수로 대체시켜서 출력하라는 뜻입니다. 다른 말로 변수나 상수를 대입시켜서 출력한다고 합니다. 보기의 %d가 뜻하는 의미는 이 자리에 변수의 내용을 정수로 바꾸어 출력하라는 뜻입니다. 그리고 쉼표 뒤에 a자를 써놓았으니 대입할 내용은 변수 a의 내용이라는 것을 알 수 있습니다.

% 기호의 종류는 꽤 많은 편인데 다음과 같습니다.


**표: % 기호의 종류
%c 매개변수를 문자 상수(글자)로 출력합니다.
%d 매개변수를 10진수 형태의 정수로 출력합니다.
%ld 매개변수를 10진수 형태의 long형 정수로 출력합니다.
%lu 매개변수를 부호 없는 10진수 형태의 long형 정수로 출력합니다.
%e 매개변수를 float나 double의 실수로 출력하는데 지수 표시 방법으로 출력합니다. 예를 들어서 123.45 라는 수는 1.23450e+02 라는 형태로 출력됩니다.
%f 매개변수를 float나 double의 실수로 출력하니다.
%g 매개변수를 %e나 %f의 형식으로 출력하는데 출력하는 글자수가 적은 쪽을 택해서 출력합니다.
%o 매개변수를 8진수 형태의 정수로 출력합니다.
%s 매개변수를 문자열(문장) 형태로 출력합니다.
%u 매개변수를 부호 없는 10진수 형태의 정수로 출력합니다.
%x 매개변수를 16진수 형태의 정수로 출력합니다.
%% %문자를 출력하고자 할 때 사용합니다.


%가 나오면 특수기호로 알아듣습니다. 따라서 %를 특수기호가 아닌 일반 글자로 출력하고자 할 때는 %%라고 써주면 됩니다.

[보기1]
This is 100%

위와 같은 문장을 화면에 출력하고 싶다면 다음과 같이 쓰면 됩니다.

[보기2]
printf("This is 100%% \n");

위와 같이 고쳐서 한 번 출력해보시기 바랍니다. 원하는 결과를 얻을 수 있을 겁니다.
% 기호의 사용법은 생각보다 까다롭습니다. 이 중에서 우리들이 배워야 할 기호 몇 가지만 간단하게 배우도록 하겠습니다. %기호 중에서 가장 많이 사용하는 대체문자는 %c, %d, %f, %s의 네 가지입니다. 여기에 long형 정수를 다룰 때 사용하는 %ld를 가끔 사용하는 정도입니다.

다음 예제는 대체문자의 용도를 보여줍니다.


** 따라하기:
(1) 다음의 내용을 c170501.c로 저장합니다.


/* c170501.c - 대체문자 사용법 */

#include <stdio.h>

void main(void)
{
printf(" 1. 이것은 영문 %c \n",'b'); /* 문자 b를 보여줌 */
printf(" 2. 이것은 정수 %d \n",99 ); /* 정수 99를 보여줌 */
printf(" 3. 이것은 실수 %f \n",12.34); /* 실수 12.34를 보여줌 */
printf(" 4. 이것은 문장 %s \n","김중태입니다."); /* '김중태입니다' 문장을 보여줌 */
}




**사진: c170501.c 파일 내용

(2) 프로그램을 실행하면 % 기호를 사용한 자리에 해당 매개변수가 출력됩니다.



**사진: c170501.exe 실행 결과


다음과 같은 내용이 화면에 출력됩니다.

[실행 결과]
1. 이것은 영문 b
2. 이것은 정수 99
3. 이것은 실수 12.340000
4. 이것은 문장 김중태입니다.

이제 %기호를 어떻게 쓰는지 알 수 있을 겁니다. %c는 글자 하나만 화면에 출력하고자 할 때 사용합니다. %d는 정수를 출력하고자 할 때 사용합니다. %f는 실수를 화면에 출력할 때 사용합니다. %s는 문장을 출력할 때 사용합니다.
실수 출력 때 12.34로 나오지 않고 12.340000으로 나온 이유는 컴파일러에서 실수를 출력하는 자릿수가 소숫점 여섯째 자리까지로 설정된 까닭입니다.

17.6. 자료형의 변환과 캐스트 연산자


자료형을 변환하여 계산해야 할 때 형변환을 이용합니다.

지금까지 우리는 자료형의 사용법에 대해 배웠습니다. 변수나 상수는 각각의 자료형에 맞게 사용해야 한다는 점은 물론입니다. 정수형에 1,000,000이라는 큰 수를 넣어도 안되고 3.14라는 소수점을 넣어도 안됩니다. 그런데 프로그램을 만들다보면 정수형으로 선언한 변수를 잠시 실수형으로 변환해서 계산을 해야할 때가 생깁니다. 이럴 경우에는 형변환을 해야 합니다. 형변환은 자동적으로 이루어지기도 하고 강제로 하기도 합니다.

형변환은 자동으로 이루어지기도 하지만 자동 형변환이 안될 때도 있습니다.

printf() 함수를 사용할 때는 형변환이 자동으로 이루어집니다. 아래의 보기를 실행시켜 보면 알 수 있습니다. 아래 보기를 실행시키기 전에 결과를 미리 예상해보기 바랍니다.


** 따라하기:
(1) 다음 내용을 c170601.c로 저장합니다.


/* c170601.c -자료형을 형변환 하여 출력하는 예제 */

#include <stdio.h>

void main(void)
{
printf(" 결과=%c\n",'A'); /* 문자형 자료 A를 문자형으로 출력 */
printf(" 결과=%d\n",'A'); /* 문자형 자료 A를 정수형으로 출력 */
printf(" 결과=%f\n",'A'); /* 문자형 자료 A를 실수형으로 출력 */
printf(" 결과=%c\n",70); /* 정수형 자료 70을 문자형으로 출력 */
printf(" 결과=%d\n",70); /* 정수형 자료 70을 정수형으로 출력 */
printf(" 결과=%f\n",70); /* 정수형 자료 70을 실수형으로 출력 */
printf(" 결과=%c\n",70.0); /* 실수형 자료 70.0을 문자형으로 출력 */
printf(" 결과=%d\n",70.0); /* 실수형 자료 70.0을 정수형으로 출력 */
printf(" 결과=%f\n",70.0); /* 실수형 자료 70.0을 실수형으로 출력 */
}




**사진: c170601.c 파일 내용

(2) 프로그램의 실행 결과는 아마 여러분의 예상과 다를 겁니다. C언어 고수가 아닌 이상 이번 예제의 결과를 예상하기는 쉽지 않습니다.



**사진: c170601.exe 실행 결과


자료형과 대체문자의 기호가 정확하게 일치해야 예상한 결과가 나옵니다.

위의 프로그램을 만들어 실행시키면 아래와 같은 결과가 나옵니다. 자료형과 대체문자의 기호가 일치할 경우에는 예상한 결과가 나옵니다. 그렇지만 자료형이 일치하지 않을 때는 예상하기 힘든 결과가 나옵니다.

[실행 결과]
결과=A
결과=65
결과=0.000000
결과=F
결과=70
결과=0.000000
결과=
결과=0
결과=70.000000

위의 보기 프로그램을 한 줄 씩 살펴보겠습니다.

[보기1]
printf(" 결과=%c\n",'A');

[실행 결과]
결과=A

%c라는 기호에 문자형 상수인 'A'글자를 치환(대입)해서 화면에 보여주라는 명령문입니다. 이 경우 %c는 문자형으로 표시해주는 형변환 기호이므로 그대로 A자로 치환해서 바꾸어줍니다.

문자 상수 'A'는 정수형으로 자동 형변환됩니다.


[보기2]
printf(" 결과=%d\n",'A');

[실행 결과]
결과=65

역시 문자형 상수 'A'를 화면에 보여주는데 이번에는 형 변환 기호가 %d입니다. 이 기호는 정수형으로 치환하라는 기호입니다. 그래서 A자의 아스키코드에 해당하는 숫자인 65를 보여준 것입니다. 이를 통해서 문자형 상수는 정수형으로 화면에 출력할 때는 자동변환이 된다는 사실을 알 수 있습니다.

문자 상수 'A'는 실수형으로 형변환되지 않습니다.


[보기3]
printf(" 결과=%f\n",'A');

[실행 결과]
결과=0.000000

문자 A를 실수형 자료로 출력하라고 하자 0이 나왔습니다. 문자형 상수를 실수형으로 자동 형변환 해주지 않는다는 사실을 이 명령문의 결과로 알 수 있습니다.

정수 상수는 문자형으로는 자동 형변환되지만 실수형으로는 변환되지 않습니다.


[보기4]
printf(" 결과=%c\n",70);
printf(" 결과=%d\n",70);
printf(" 결과=%f\n",70);

[예제 실행 결과]
결과=F
결과=70
결과=0.000000

예제의 세 문장은 정수형 상수 70이라는 수를 각각 문자형과 정수형, 실수형으로 출력하라는 명령문입니다. 그 결과 정수형 상수 70을 문자형으로 자동 형변환하여 아스키코드 70번에 해당하는 F자를 출력했습니다. 그러나 실수형으로는 형변환되지 않았습니다. 아마 70.000000으로 출력될 것으로 예상한 분이 있을 겁니다. 그렇지만 예상하지 못한 0이라는 엉뚱한 값이 출력되었습니다.

C언어에서 정수 70과 실수 70은 완전히 다른 자료입니다.

따라서 숫자라고 하여 정수나 실수 어떻게 사용해도 결과는 같겠지 하는 자세는 버려야 합니다. 사람들은 정수 70과 실수 70을 같은 수로 알고 계산하지만 컴퓨터는 정수 70을 실수 70으로 변환하지 못합니다. 이런 차이점을 모르고 프로그램을 짰다가는 완전히 엉뚱한 결과를 얻게됩니다.

실수 상수는 정수형이나 문자형으로 형변환되지 않습니다.


[보기5]
printf(" 결과=%c\n",70.0);
printf(" 결과=%d\n",70.0);
printf(" 결과=%f\n",70.0);

[실행 결과]
결과=
결과=0
결과=70.000000

마지막 세 문장을 통해서는 실수형 상수를 정수형이나 문자형으로 자동 형변환하지 않는다는 것을 알 수 있습니다. 실수형 자료를 정수형 변수에 넣어서 계산할 경우 원하지 않는 결과가 나온다는 사실을 지금의 예제를 통해서 알았습니다. 따라서 자신이 사용하는 변수와 상수의 정확한 자료형을 기억하면서 프로그램을 짜나가야 합니다.

자동 형변환이 안될 경우에는 사용자가 강제로 형변환을 시켜주어야 합니다.

프로그램을 짤 때는 이런 자동 형변환이 되는 것과 되지 않는 관계를 잘 파악해두었다가 활용해야 합니다. 형변환은 printf() 함수에서만 되는 것이 아니고 여러 함수와 연산에서 자동으로 이루어집니다. 예를 들어서 정수와 실수를 곱하면 그 결과값은 자동적으로 실수로 변환됩니다. 따라서 그 결과값을 C라는 변수에 넣을 경우 C는 실수형 변수여야 합니다. 만약 C가 실수형 변수가 아니라면 잠시 실수형으로 강제 형변환을 해주어야 합니다.

형변환기호는 printf() 함수에서 많이 사용합니다. 이미 예제로 몇 번 설명을 드렸지만 표로 정리한 내용을 참고하여 정확하게 알아두시기 바랍니다.


**표: 형 변환 기호
기호 인수의 수형 변환 내용
%d 정 수 형 인수를 부호있는 10진수로 출력합니다.
%u 정 수 형 인수를 부호없는 10진수로 출력합니다.
%ld 배정도 정수형 인수를 부호있는 배정도(long) 정수로 출력합니다.
%lu 배정도 정수형 인수를 부호없는 배정도(long) 정수로 출력합니다.
%o 정 수 형 인수를 부호없는 8진수로 출력합니다.
%x 정 수 형 인수를 부호없는 16진수로 출력하는데 소문자로 출력합니다.
%X 정 수 형 인수를 부호없는 16진수로 출력하는데 대문자로 출력합니다.
%c 문자 인수를 단일문자로 출력
%s 문자열 포인터 널문자(\0) 앞까지의 문자열을 출력합니다.
%f 실수형 고정 소숫점 형식으로 출력합니다.
%e 실수형 부동 소숫점 형식으로 출력합니다.
%E 실수형 부동 소숫점 형식으로 출력합니다.
%g 실수형 %f와 %e 의 표현방식 중에서 간단한 형식을 택해 출력합니다.
%G 실수형 %f와 %e 의 표현방식 중에서 간단한 형식을 택해 출력합니다.



자료의 형명을 바꿀 때는 typedef 명령어를 사용합니다.

그리고 가끔은 자료의 형명, 즉 키워드를 바꾸어야 할 때가 있습니다. 먼저 자료의 형 이름을 바꾸고자 한다면 다음과 같은 형식을 사용합니다.

[사용 형식]
typedef 기존자료형 이름 새로운 이름

기존 자료형 이름이 char, int, long 등일 때, 새로운 자료형 이름은 사용자가 정해서 붙이는 이름인 셈입니다.

[보기]
typedef int kimint;

int money;
kimint rate;

위와 같이 하면 kimint가 int라는 자료형을 나타내는 키워드가 됩니다. 물론 이전에 사용하던 int라는 것도 유효합니다. 따라서 'typedef int kimint;' 명령어를 쓴 뒤에는 'int money;' 라고 기존의 방식대로 정수형 변수를 선언하는 것도 가능하고, 'kimint rate;'와 같이 kimint라는 형명을 이용하여 정수형 변수를 선언하는 것도 가능합니다.

형변환이 자동으로 이루어질 때는 작은 쪽에서 큰 쪽으로 변합니다.

형변환이 자동으로 이루어질 때는 보통 작은 쪽에서 큰 쪽으로 변합니다. 물론 이 말은 절대적이지 않습니다. 그러나 대부분의 경우 문자와 정수를 더하면 정수형으로 결과값이 나오고 정수와 실수를 함께 계산하면 실수형으로 결과값이 나옵니다.

예를 들어서 아래의 경우를 보시기 바랍니다.

[사용 형식]
char + int 의 결과는 int
[보기]
'A' + 10 의 결과는 75

문자형 상수 A와 정수형 상수 10을 더하면 정수형상수로 값이 나옵니다. 즉 문자형과 정수형을 함께 연산하면 정수형으로 결과값이 나옵니다. 형변환은 정수형으로 변하는 것입니다.

[사용 형식]
char + int + double 의 결과는 double
[보기]
'A' + 10 + 3.3 의 결과는 78.3

이번에는 문자형과 정수형, 실수형을 한꺼번에 더해봤습니다. 결과값은 실수형으로 나옵니다. 이처럼 보통 형변환은 작은 쪽에서 큰 쪽으로 변합니다. 그러니까 정수와 실수를 연산하면 실수형으로 형변환이 이루어진다는 이야기입니다.

강제로 형변환을 할 때는 캐스트 연산자를 사용합니다.

강제로 형변환을 할 때는 캐스트 연산자라는 것을 사용합니다. 캐스트 연산자는 둥근괄호를 기호로 사용합니다.

[사용 형식]
char + (int)float 의 결과는 int
[보기1]
'A' + (int)2.5 의 결과는 67

위의 보기는 2.5라는 실수형 자료를 잠시 int형으로 바꾸어서 계산한 것입니다. 그래서 결과값도 int형이 된 겁니다.

[사용 형식]
(int)(float + float) 의 결과는 int
[보기2]
(int)(3.14 + 3.14)의 결과는 6

만약 위의 보기를 그대로 연산했다면 다음과 같은 결과가 나왔을 겁니다.

[사용 형식]
float + float 의 결과는 float
[보기3]
3.14 + 3.14 의 결과는 6.28

**요약: 각기 다른 형태의 자료를 이용해서 연산할 때는 자동 형변환에 유의해야 합니다. 자동변환이 자동으로 이루어질 때는 보통 큰 쪽으로 변환이 이루어집니다. 즉 문자형->정수형->실수형의 순서로 변환이 이루어집니다. 필요할 경우에는 캐스트 연산자를 이용하여 강제로 자료형을 바꿀 수 있습니다.


17.7.함수에 매개변수 입력하는 요령


매개변수로 사용하는 문자형 상수 옆에는 작은따옴표를 붙입니다.

함수에 매개변수를 삽입하는 요령을 좀더 자세하게 알아봅시다. 다음 보기를 살펴봅시다.

[보기1] 문자 상수를 매개변수로 사용할 때
printf(" 1. 이것은 영문 %c \n",'b');

%c는 한 글자를 출력하라는 뜻입니다. 그리고 매개변수로는 'c'라는 문자를 사용했습니다. 여기에서 c 라는 글자 좌우에 작은따옴표를 붙이는 것을 잘 기억해두시기 바랍니다. C언어에서는 하나의 글자를 표시할 때 글자 좌우에 작은따옴표를 붙입니다. 다시 말해 문자 상수는 작은따옴표를 붙여 변수와 구별합니다.
만약 작은따옴표를 붙이지 않는다면 무엇으로 인식하겠습니까? c라는 변수로 받아들일 겁니다. 그러면 오류가 나오고 컴파일이 되지 않습니다.

매개변수로 사용하는 숫자는 작은따옴표 안붙이고 숫자 그대로 적어줍니다.


[보기2] 정수 상수를 매개변수로 사용할 때
printf(" 2. 이것은 정수 %d \n",99 );

%d는 정수로 변환해서 보여준다는 뜻입니다. 인수로는 10을 사용하고 있습니다. 이때 10 좌우에는 작은따옴표를 붙이지 않습니다. 10은 숫자로 인식하기 때문입니다. 만약 '5'라고 썼다면 5라는 수가 아닌 5라는 글자로 인식하게 될 겁니다.

실수는 기본적으로 소숫점 이하 6자리까지 표시됩니다.


[보기3] 실수 상수를 매개변수로 사용할 때
printf(" 3. 이것은 실수 %f \n",12.34);

%f는 실수를 표현하고자 할 때 사용합니다. 역시 매개변수로 사용할 수 있는 것은 숫자이므로 12.34라는 실수를 사용했습니다. 그런데 결과는 조금 이상하게 나왔습니다.

3. 이것은 실수 12.340000

12.340000으로 결과를 출력했습니다. 그러니까 소숫점 이하 자리수를 소수 6번째 자리까지 표시한 겁니다. 이것은 터보C나 볼랜드C++의 기본값입니다. 따라서 소숫점 둘째 자리까지만 표시하도록 하고 싶다면 별도로 특수기호와 조건식을 더 넣어주어야 합니다.

매개변수로 사용하는 문자열은 큰따옴표로 싸줍니다.


[보기4] 문자열을 매개변수로 사용할 때
printf(" 4. 이것은 문장 %s \n","김중태입니다.");

%s는 문자열(=문장)을 출력하라는 뜻입니다. 그리고 매개변수로는 "김중태입니다."를 사용했습니다. 앞의 %c의 매개변수로 사용한 것과 차이점을 알 수 있을 겁니다. 문자열은 앞뒤로 큰따옴표를 붙인다는 사실입니다. 그러니까 작은따옴표를 붙이면 글자 하나를 뜻하고, 큰따옴표를 붙이면 여러 개의 글자를 나열한 문장으로 인식하는 겁니다.

**요약: %기호는 변수의 내용을 %기호에 대입하라는 뜻을 지닌 특수기호입니다. %c는 글자 하나를 대입할 때, %d는 정수를 대입할 때, %f는 실수를 대입할 때, %s는 문장을 대입시킬 때 사용합니다. 인수로 사용하는 문자는 작은따옴표로, 문자열은 큰따옴표로 감싸줍니다.


17.8.쉼표를 이용해 여러 개의 매개변수 사용하기


함수 안에 사용하는 매개변수가 여러 개일 경우에는 쉼표로 매개변수 사이를 구별합니다.

함수에 사용할 수 있는 매개변수는 여러 개일 수 있습니다. 이 때 각각의 매개변수는 쉼표로 구분합니다.

[보기]
printf("변수1= %d 변수2= %d 변수3=%d \n", b1, b2, b3);

보기의 문장은 b1, b2, b3라는 세 개의 변수를 쉼표로 구분하고 세 변수를 printf() 함수의 문장 안에 대입시킨 것입니다.


** 따라하기:
(1) 다음의 내용을 c170801.c로 저장합니다.


/* c170801.c - 여러 개의 매개변수 사용하기 */

#include <stdio.h>

void main(void)
{
int b1=0, b2=1, b3=2;
printf("변수1= %d 변수2= %d 변수3=%d \n", b1, b2, b3);
}




**사진: c170801.c 파일 내용

(2) 쉼표로 구분한 세 개의 변수 내용이 모두 화면으로 출력됩니다.



**사진: c170801.exe 실행 결과


대체문자와 변수의 수를 정확하게 일치시켜야 합니다.

프로그래머는 큰따옴표 안의 문장 안에 사용하는 대체문자(%기호)의 수와 쉼표로 구분하는 변수의 수를 맞추어주어야 합니다. 문장 안의 대체문자 수와 변수의 수가 맞지 않을 경우 문제가 발생합니다. 대체문자보다 변수가 적으면 문장 안의 대체문자는 엉뚱한 내용을 표시하게 됩니다. 반대로 대체문자보다 변수가 많으면 남는 수만큼의 변수를 사용되지 못하는 문제가 발생합니다.


** 따라하기:
(1) 다음의 내용을 c170802.c로 저장합니다.


/* c170802.c - 매개변수 개수 맞추기 */

#include <stdio.h>

void main(void)
{
int b1=1, b2=2, b3=3;
printf("변수 2개 출력: 변수1= %d 변수2= %d \n", b1, b2, b3);
printf("변수 3개 출력: 변수1= %d 변수2= %d 변수3= %d \n", b1, b2, b3);
printf("변수 4개 출력: 변수1= %d 변수2= %d 변수3= %d 변수4= %d \n", b1, b2, b3);
}




**사진: c170802.c 파일 내용

(2) c170802.exe를 실행시키면 네 번째 %d에는 엉뚱한 숫자가 대입된다는 사실을 확인할 수 있습니다.



**사진: c170802.exe 실행 결과


대체문자가 변수보다 많으면 남는 대체문자는 쓰레기값으로 표시합니다.

문장(=format형식) 안에 대체문자를 두 개 사용할 경우에는 b1, b2 변수만 표시해줍니다. b3 변수는 사용하지 않습니다. 문장 안의 대체문자와 변수의 수가 세 개로 같을 경우에는 제대로 보여줍니다.

그런데 대체문자가 네 개일 경우 마지막 네 번째 %d는 이상한 숫자로 표시되었습니다. 네 번째 대체문자에 해당하는 변수가 없을 경우 문장 안의 대체문자는 아무 값이나 넣어서 화면에 표시합니다. 다시 말해 쓰레기값을 대입하여 화면에 출력합니다. 이 때문에 이상한 숫자가 화면에 출력된 것입니다.

하나의 문장에 여러 개의 매개변수를 삽입하는 방법을 알았다면 각기 다른 자료형으로 삽입하는 방법도 이해하실 겁니다. 대체문자의 자료형 기호와 변수의 자료형만 일치시켜주면 됩니다.

C는 문자열 자료형이 없기 때문에 문자 배열로 문자열을 다룹니다.

문제는 문자열을 어떻게 만드냐 하는 점입니다. 자료형을 말할 때 문자열이라는 자료형은 없다는 말씀 드렸습니다. 따라서 문자열을 자료형으로 선언할 수는 없습니다. 대신 문자 배열이라는 방법을 통해 문자열을 만듭니다. 문자열을 선언할 때는 배열이나 포인터를 이용하여 선언합니다. 문자열에 대한 자세한 내용은 배열과 문자열에 관한 부분에서 다시 자세하게 다루겠습니다. 일단 여기서는 가장 간단한 문자열 선언 방법만 알려드리겠습니다.

[사용 형식]
char 배열 이름[];

[보기]
char myname[]="joongtae";


** 따라하기:
(1) 다음의 내용을 c170803.c로 저장합니다.


/* c170803.c - 문자열 사용법 */

#include <stdio.h>

void main(void)
{
int n1=99;
float f1=12.34;
char c1='k';
char s1[]="내 이름은 김중태(joongtae)입니다.";
printf(" 1. 이것은 정수 %d \n",n1);
printf(" 2. 이것은 실수 %f \n",f1);
printf(" 3. 이것은 문자 %c \n",c1);
printf(" 4. 이것은 문장 %s \n",s1);
}




**사진: c170803.c 파일 내용


(2)



**사진: c170803.exe 실행 결과


문자열은 배열을 이용하기 때문에 사용법이 변수와 다릅니다.

예제에서 문자열을 자료형으로 정의할 때 방법을 잘 살펴보기 바랍니다. 문자형을 선언할 때처럼 char 키워드를 자료형의 키워드로 사용하는 것은 같습니다. 다만 배열을 이용한 방법이기 때문에 문자 변수를 선언하는 방법과 두 가지 점이 다릅니다.

1. 배열인 관계로 [] 기호가 추가됩니다.

문자 변수 c1을 선언할 때는 [] 기호가 없이 바로 변수 이름을 사용했습니다. 그렇지만 문자열 배열 s1은 배열을 뜻하는 기호인 [] 기호를 붙여주어야 합니다.

[보기1] 문자 변수와 문자열 배열의 선언 방법
char c1; /* 문자 변수 c1 선언 */
char c2[]; /* 문자열 배열 c2 선언 */

2. 문자열인 관계로 변수 내용을 큰따옴표로 묶습니다.

문자 변수 c1에 k자를 대입할 때는 작은따옴표로 묶었습니다. 반면 문자 배열에 자료를 대입할 때는 큰따옴표로 묶었습니다.

[보기2] 문자 상수와 문자열 상수의 차이
c1='k'; /* 문자 변수 c1에 문자 상수 k를 대입 */
c2="k"; /* 문자 배열 c2에 문자열 상수 k를 대입 */

보기의 변수 c1과 c2는 큰 차이점이 있습니다. 둘 다 변수의 내용으로 k라는 문자를 가지는 점은 동일합니다. 그렇지만 c1은 문자 상수인 k를 값으로 가지는 것이고, c2는 문자열 상수 k를 값으로 가지는 차이점이 있습니다. 이는 c1에 값을 대입할 때는 작은따옴표로 상수 값을 감쌌고, c2에 값을 대입할 때는 큰따옴표로 감싼 차이가 있기 때문입니다.

3. 문자열을 출력할 때는 %s 기호를 사용합니다.

printf() 함수 안에서 문자열을 사용하고자 할 때는 대체문자로 %s 기호를 사용합니다. %c 기호를 사용하면 문자 상수로 판단하므로 문자열 출력이 되지 않습니다. 문자열을 출력할 때는 꼭 %s 기호를 사용합니다.

17.9.printf() 함수로 자료 출력할 때 자릿수 조정하기


실수의 자릿수를 조정할 때는 - . 등의 기호를 사용합니다.

앞서 실수형 자료 12.34를 화면으로 출력한 적이 있습니다. 이때 의도한 바와 달리 12.3400이라는 숫자로 출력되어 보기에 좋지 않았습니다. 이는 자릿수를 조정하지 않았기 때문에 벌어진 일입니다. 자릿수를 조정하면 원하는 위치에 원하는 자릿수로 숫자를 출력할 수 있습니다.

%f로 출력되는 숫자의 칸이나 자릿수를 조절하고 싶다면 어떻게 하면 되는지 알아보겠습니다. %기호와 f 사이에 출력 조정용 명령을 삽입하면 됩니다. 다음 보기처럼 % 기호 바로 뒤에 다음과 같은 형식을 사용하면 자릿수가 조정됩니다.

[보기1]
printf(" This is %-10.2f \n",12.34);

[실행 결과1]
This is 12.34

%기호 다음에 나오는 빼기(-) 기호는 출력할 때 그 줄의 왼쪽부터 출력을 시작하라는 뜻입니다. 그러니까 왼쪽 정렬을 하라는 뜻입니다. 다음의 숫자 10은 출력할 때 10칸짜리로 출력하라는 뜻입니다. 다음의 마침표(.)는 소숫점 이하의 자릿수를 구별하기 위해서 사용합니다. 그 뒤의 2라는 숫자는 소숫점 2번째 자리까지 출력하라는 뜻입니다. 그래서 이 문장을 실행하면 12.34로 출력됩니다.

그런데 빼기(-) 기호를 사용하지 않을 경우에는 터보C가 보통 오른쪽정렬을 기준으로 맞춥니다. 그렇다면 명령문을 다음과 같이 바꾸어서 출력하면 어떻게 나올까요?

[보기2]
printf(" This is %10.1f \n",12.34);

그러면 다음과 같은 출력이 나옵니다.

[실행 결과2]
This is 12.3

10칸으로 출력하는데 오른쪽으로 붙여서 정렬하기 때문에 'This is'라는 문장 사이에 빈 칸이 6칸 들어간 겁니다. 그리고 .1f라고 했으니 소수 첫째 자리까지만 출력한 겁니다. 그래서 12.34의 둘째 자리인 4는 탈락해버린 겁니다.

자릿수를 조정할 때 사용하는 형식은 다음과 같습니다.

[사용 형식]
%부호a.b자료형

[형식 설명]
% : %기호
부호 : -가 붙으면 왼쪽 정렬, 안붙으면 오른쪽 정렬
a : 전체 자릿수를 지정하는 숫자
. : 소숫점 이하 자릿수를 구분하기 위한 표시
b : 소숫점 이하 자릿수
자료형 : d, ld, f 등의 자료형을 나타내는 문자

[보기]
%5.3f : 실수를 전체 자릿수 5자리, 소수점 이하 3자리까지 오른쪽 정렬로 출력하라
%10.5f : 실수를 전체 자릿수 10자리, 소수점 이하 5자리까지 오른쪽 정렬로 출력하라
%-5.3f : 실수를 전체 자릿수 5자리, 소수점 이하 3자리까지 왼쪽 정렬로 출력하라
%-10.5f : 실수를 전체 자릿수 10자리, 소수점 이하 5자리까지 왼쪽 정렬로 출력하라
%5d : 정수를 전체 자릿수 5자리로 오른쪽 정렬로 출력하라.
%-5d : 정수를 전체 자릿수 5자리로 왼쪽쪽 정렬로 출력하라.

실수는 기호의 조합에 따라서 화면에 나타나는 모양이 다릅니다.

이제 이 형식에 맞추어서 몇 가지 출력을 해보도록 하겠습니다. 아래와 같이 프로그램을 작성하고 실행해보기 바랍니다.


** 따라하기:
(1) 다음의 내용을 c170901.c로 저장합니다.


/* c170901.c - 출력할 때 자릿수 맞추기 */

#include <stdio.h>

void main(void)
{
printf(" This is %10.1f \n",123.456);
printf(" This is %10.2f \n",123.456);
printf(" This is %-10.1f \n",123.456);
printf(" This is %-10.2f \n",123.456);
printf(" This is %5.1f \n",123.456);
printf(" This is %5.5f \n",123.456);
printf(" This is %3d \n",12345);
printf(" This is %5d \n",12345);
printf(" This is %10d \n",12345);
printf(" This is %15d \n",12345);
printf(" This is %-3d \n",12345);
printf(" This is %-10d \n",12345);
}




**사진: c170901.c 파일 내용

(2) 프로그램을 실행시키면 지정된 명령에 따라 숫자의 표시 형태가 달라진다는 사실을 알 수 있습니다.



**사진: c170901.exe 실행 결과


프로그램의 결과를 예측하면 이렇습니다.

[예상 내용]
printf(" This is %10.1f \n",123.456);
123.456을 오른쪽 정렬을 해서 10칸에 맞추어서 소수점 첫째 자리까지만 출력하라.

printf(" This is %10.2f \n",123.456);
123.456을 오른쪽 정렬을 해서 10칸에 맞추어서 소수점 둘째 자리까지만 출력하라.

printf(" This is %-10.1f \n",123.456);
123.456을 왼쪽 정렬을 해서 10칸에 맞추어서 소수점 첫째 자리까지만 출력하라.

printf(" This is %-10.2f \n",123.456);
123.456을 왼쪽 정렬을 해서 10칸에 맞추어서 소수점 둘째 자리까지만 출력하라.

printf(" This is %5.1f \n",123.456);
123.456을 오른쪽 정렬을 해서 5칸에 맞추어서 소수점 첫째 자리까지만 출력하라.

printf(" This is %5.5f \n",123.456);
123.456을 오른쪽 정렬을 해서 5칸에 맞추어서 소수점 다섯째 자리까지 출력하라.

printf(" This is %3d \n",12345);
12345를 오른쪽 정렬로 세 자리까지 출력하라.

printf(" This is %5d \n",12345);
12345를 오른쪽 정렬로 다섯 자리까지 출력하라.

printf(" This is %10d \n",12345);
12345를 오른쪽 정렬로 열 자리까지 출력하라.

printf(" This is %15d \n",12345);
12345를 오른쪽 정렬로 열다섯 자리까지 출력하라.

printf(" This is %-3d \n",12345);
12345를 왼쪽 정렬로 세 자리까지 출력하라.

printf(" This is %-10d \n",12345);
12345를 왼쪽 정렬로 열 자리까지 출력하라.

예제를 실행시키면 아래와 같은 출력이 화면에 나옵니다.

[실행 결과]
 This is      123.5 
 This is     123.46 
 This is 123.5      
 This is 123.46     
 This is 123.5 
 This is 123.45600 
 This is 12345
 This is 12345
 This is      12345
 This is           12345
 This is 12345
 This is 12345

실수를 연산할 때는 반올림 기능에 주의해야 합니다.

이렇게 출력이 나왔다면 제대로 프로그램을 작성한 겁니다. 자 이 화면에서 무엇인가 이상한 것을 발견했을 겁니다. 123.456을 지정했으므로 123.4나 123.45가 나와야 할 것 같은데 123.5와 123.46이 나왔습니다. 왜 그럴까요? 반올림을 했기 때문입니다. 즉 소수 첫째 자리만 표시하기 위해서 소수 둘째 자리 이하를 계산한 겁니다. 그래서 소수 둘째 자리에서 반올림을 해서 첫째 자리에 표시한 것입니다.

따라서 C언어를 이용해서 숫자를 계산할 때는 숫자의 오차가 발생하는 현상에 주의해야 합니다. 비록 소수점 아래의 숫자지만 오차가 나올 수 있기 때문입니다. 그래서 컴퓨터언어로 프로그램을 짜서 정밀한 숫자를 다룰 때는 항상 컴파일러의 프로그램이 가지는 반올림을 염두에 두고 짜야 합니다. 안 그러면 엉뚱한 계산결과가 나올 수 있습니다.

정수형은 숫자의 크기에 변화가 없는 한도 안에서 자릿수를 조정합니다.

정수로 출력한 부분도 주목할 점이 있습니다. %3d 부분의 예상 결과로 123을 예상한 분이 계실지 모릅니다. 12345에서 세 자리만 출력하므로 123까지만 출력하고 45를 제거할 것으로 예상할 수 있습니다. 그렇지만 이렇게 되면 만 단위인 12345가 백 단위인 123으로 바뀌기 때문에 숫자 자체가 달라지는 결과를 보입니다. 그래서 정수형의 경우 숫자가 변화하는 경우에는 자릿수 조정을 하지 않습니다. 그래서 %3d라고 썼지만 12345라는 다섯 자리를 모두 출력한 것입니다.

좀더 자세한 printf() 함수 사용법은 라이브러리 책을 참고하기 바랍니다.

이제 이 정도면 기본적인 printf() 함수의 사용법을 배운 셈입니다. 사실 printf() 함수의 사용법은 더욱 복잡하지만 지금까지 배운 내용이면 기본적인 사용법은 익힌 셈입니다.좀더 자세한 사용법은 다음 기회에 다루도록 하겠습니다. 그리고 이 책에서 배운 내용을 바탕으로 터보C의 라이브러리 책을 보신다면 printf() 함수의 사용법을 쉽게 이해할 수 있을 것으로 생각합니다.

**요약: 실수는 특수기호의 조합에 따라서 출력결과가 완전히 다르게 출력됩니다. 또한 반올림 기능이 있어 예상했던 결과와 다른 계산결과가 나올 수 있다는 점을 염두에 두어야 합니다.



**웃으며 배우는 C언어 습관: 때로는 손해 볼 줄도 알아야 한다

2차 대전 때 독일군이 프랑스를 점령했을 때 기차를 타고 가는 네 사람이 있었습니다. 독일장교, 프랑스 청년, 아름다운 프랑스 아가씨, 프랑스 노인.
차가 캄캄한 굴을 지나는 순간 키스소리가 나더니 뺨을 힘껏 때리는 소리가 났습니다.
터널을 나오니 독일장교가 뺨을 어루만지고 있었습니다. 이때 네 사람의 생각은
노인: 저 독일놈이 아가씨에게 키스하다 맞았군.
처녀: 저 독일군이 나한테 키스한다는게 청년에게 잘못해 맞은거로군.
독일장교: 저 프랑스놈이 처녀에게 키스하니깐 아가씨가 뺨을 친다는게 잘못해서 나를 때린게 분명해.
청년: 저 독일놈 뺨 한대 때릴려고 내가 내 손에 키스를 하다니.

세상 살다보면 하나를 얻을 때 하나를 포기해야 한다는 사실을 깨닫습니다. 프로그램을 짤 때도 마찬가지입니다. 짜는 사람이 편하고자 하면 쓰는 사람이 불편해지고, 쓰는 사람이 편하게 짜고자 하면 짜는 사람이 힘들어집니다. 알아보기 쉽게 짜려니 프로그램이 길어지고, 프로그램을 짧게 짜자니 알아보기가 힘들고. 함수를 사용할 때도 어떤 함수를 쓰면 어떤 기능이 안되어서 불만입니다.
모든 것을 다 얻기를 바라지 마십시요. 하나쯤은 포기할 줄 알아야 편하게 프로그램을 짤 수 있습니다.


[17장. 연습 문제]


(01) 변수 n의 값으로 99을 대입하고 변수 n의 값을 화면으로 출력하는 프로그램을 작성하시오.

(02) 사용자로부터 정수를 세 개 입력받아 이 수를 화면으로 출력하는 프로그램을 작성하시오.

(03) 두 개의 정수를 입력받아 두 수와 두 수의 덧셈을 화면으로 출력하는 프로그램을 작성하시오.

(04) '안녕하세요? 여러분.'이라는 문장을 printf() 함수를 한 번만 사용하여 다음과 같이 출력되도록 만드시오.

안녕하세요?
여러분.

(05) printf() 함수를 한 번만 사용하면서 첫 번째 줄에 '대한민국', 두 번째 줄에 'Korea', 세 번째 줄에 '만세.'를 출력하는 프로그램을 작성하시오.

(06) 다음 명령이 화면에 어떻게 출력될 것인지 말하시오.

printf("This is...\n\n\nLove\nLove...");

(07) 다음 예제의 출력 결과를 말하시오.

#include <stdio.h>

void main(void)
{
printf("D:\의 \기호는 루트 디렉토리를 뜻합니다.");
}

(08) 다음 문장을 화면에 출력하는 프로그램을 작성하시오.

빗금은 / 이고, 역빗금은 \ 입니다.

(09) 다음 문장에서 잘못된 곳은 어디인가?

printf("안녕하세요? "C언어 이야기" 독자 여러분.\n");

(10) 다음 문장을 화면에 출력하는 프로그램을 작성하시오.

저는 'C언어 이야기'의 지은이 "김중태"입니다.

(11) 다음 예제의 출력 결과를 말하시오.

#include <stdio.h>

void main(void)
{
printf("안녕하세요?");
printf("여러분께");
printf("감사드립니다.");
}

(12) 다음 예제의 출력 결과를 말하시오.

#include <stdio.h>

void main(void)
{
printf("This is...");
printf("Love\nn\nn");
printf("Love...");
}

(13) '여러분 감사합니다.'라는 문장을 printf() 함수의 매개변수로 사용하여 화면에 출력하는 프로그램을 작성하시오.

(14) '99%의 노력이 필요합니다.'라는 문장을 화면에 출력하는 프로그램을 작성하시오.

(15) ASCII 코드 65번이 A라는 사실을 기억하고, 다음 예제의 화면 출력 결과를 말하시오.

#include <stdio.h>

void main(void)
{
printf(" 결과=%c\n",'B');
printf(" 결과=%d\n",'B');
printf(" 결과=%f\n",'B');
printf(" 결과=%c\n",67);
printf(" 결과=%d\n",67);
printf(" 결과=%f\n",67);
printf(" 결과=%c\n",68.0);
printf(" 결과=%d\n",68.0);
printf(" 결과=%f\n",68.0);
}

(16) ASCII 코드 65번이 A라는 사실을 기억하고, 다음 예제의 화면 출력 결과를 말하시오.

#include <stdio.h>

void main(void)
{
printf("%c",65+1);
}

(17) ASCII 코드 65번이 A라는 사실을 기억하고, 다음 예제의 화면 출력 결과를 말하시오.

#include <stdio.h>

void main(void)
{
printf("%c",'A'+1);
}

(18) ASCII 코드 65번이 A라는 사실을 기억하고, 앞으로 나올 예제를 풀어가시오. 다음 예제의 화면 출력 결과를 말하시오.

#include <stdio.h>

void main(void)
{
printf("%d",'A'+'A');
}

(19) 다음 예제의 화면 출력 결과를 말하시오.

#include <stdio.h>

void main(void)
{
printf("%c",'A'+1+1.3);
}

(20) 다음 예제의 화면 출력 결과를 말하시오.

#include <stdio.h>

void main(void)
{
printf("%d",'A'+1+1.3);
}

(21) 다음 예제의 화면 출력 결과를 말하시오.

#include <stdio.h>

void main(void)
{
printf("%f",'A'+1+1.3);
}

(22) 다음 예제의 화면 출력 결과를 말하시오.

#include <stdio.h>

void main(void)
{
printf("%c",'A'+(int)2.3);
}

(23) 다음 예제의 화면 출력 결과를 말하시오.

#include <stdio.h>

void main(void)
{
printf("%c",'A'+(int)(1.2+2.2));
}

(24) 다음 예제의 화면 출력 결과를 말하시오.

#include <stdio.h>

void main(void)
{
printf("%d",'A'+(int)(1.3+1.3));
}

(25) 한 줄의 문장으로 변수 세 개를 선언하여 11, 22, 33이라는 값을 대입하고 printf() 함수를 한 번만 사용하여 변수 내용을 화면으로 출력하시오.

(26) 다음 예제에서 잘못된 부분을 말하시오.

#include <stdio.h>

void main(void)
{
int b1=1, b2=2, b3=3;
printf(" %d %d %d %d \n", b1, b2, b3);
}

(27) 정수를 매개변수로 사용한 printf() 함수를 이용하여 화면에 E자를 출력하시오.

(28) 다음 예제에서 잘못된 부분을 말하시오.

#include <stdio.h>

void main(void)
{
char c1='kim';
char s1[]="joongtae";
printf(" %c \n",c1);
printf(" %s \n",s1);
}

(29) 문자 배열 book을 이용하여 'C언어 이야기'라는 문장을 화면에 출력하시오.

(30) 다음 예제에서 잘못된 부분을 말하시오.

#include <stdio.h>

void main(void)
{
char s1[]='joongtae';
printf(" %c ",s1);
}

(31) 다음 예제의 출력 결과를 말하시오.

#include <stdio.h>

void main(void)
{
printf(" This is %5.f \n",123.456);
printf(" This is %10.3f \n",123.456);
printf(" This is %15.5f \n",123.456);
printf(" This is %15.9f \n",123.456);
printf(" This is %-5.f \n",123.456);
printf(" This is %-10.3f \n",123.456);
printf(" This is %-15.5f \n",123.456);
}

(32) 12.345를 소수점 다섯 자리까지 출력하고 왼쪽에 정렬시키는 프로그램을 작성하시오.

(33) 12.345를 열 칸의 자리를 마련하여 출력하되 소수점 여섯 자리까지 출력하시오.

(34) printf() 함수를 각각 사용하여 'Korea'와 'Worldcup'을 두 줄에 걸쳐 출력하는 프로그램을 작성하시오.

(35) printf() 함수를 한 번만 사용하여 'Korea'와 'Worldcup'을 두 줄에 걸쳐 출력하는 프로그램을 작성하시오.

(36) printf() 함수를 한 번만 사용하여 'Korea'를 보여주고 빈 줄을 두 줄 삽입하고 세 번째 줄에 'Worldcup'을 보여주는 프로그램을 작성하시오.

(37) 첫 번째 printf() 함수로는 'Korea'를 출력하고 두 번째 printf() 함수로는 'Worldcup'을 출력하되 다음과 같이 한 줄로 출력하는 프로그램을 작성하시오.

Korea Worldcup

(38) printf() 함수를 각각 사용하여 'Korea'와 'Worldcup' 'Asia'를 세 줄에 걸쳐 출력하는 프로그램을 작성하시오.

(39) printf() 함수를 각각 사용하여 'Korea'와 'Worldcup' 'Asia'를 세 줄에 걸쳐 출력하는 프로그램을 작성하시오. 단 소스 파일 안에 '2002년 한국 월드컵'이라는 문장을 주석문으로 추가하시오.

(40) 문자 변수 a, b, c를 선언하고 문자 상수 1, 9, C를 대입한 다음에 각 문자 상수를 ASCII 코드값으로 출력하는 프로그램을 작성하시오.

(41) 정수형 변수 a, b, c를 선언하고 65, 70, 80을 각각 대입한 다음에 문자 상수 형태로 출력하는 프로그램을 작성하시오.

(42) 정수형 변수 a, b, c에 각각 ASCII 코드값을 대입한 다음에 printf() 함수를 한 번만 이용하여 화면에 'ABC'가 출력되도록 프로그램을 작성하시오.

(43) printf() 함수만을 사용하여 문자 상수 'k', 'i', 'm'을 ASCII 코드값으로 출력하시오.

(44) printf() 함수만을 사용하여 정수 98, 99, 199를 16진수로 출력하도록 하시오.

(45) printf() 함수만을 사용하여 정수 98, 99, 199를 8진수로 출력하도록 하시오.

(46) printf() 함수만을 사용하여 실수 123.456과 3.14159를 지수 형태로 표시하도록 하시오.

(47) printf() 함수만을 사용하여 실수 0.00123456을 지수 형태로 표시하도록 하시오.

(48) 사용자로부터 16진수 형태로 입력받은 정수형 자료를 화면에 출력하는 프로그램을 작성하시오.

(49) 사용자로부터 16진수 형태로 입력받은 정수형 자료를 10진수와 8진수, 16진수로 화면에 출력하는 프로그램을 작성하시오.

(50) 사용자로부터 8진수 형태로 입력받은 정수형 자료를 10진수와 8진수, 16진수로 화면에 출력하는 프로그램을 작성하시오.

(51) 사용자로부터 10진수 형태로 입력받은 정수형 자료를 10진수와 8진수, 16진수로 화면에 출력하는 프로그램을 작성하시오.

[17장. 연습 문제 해답]


(01)

#include <stdio.h>

void main(void)
{
int n=99;
printf("변수 n의 값은 = %d \n",n);
}

(02)

#include <stdio.h>

void main(void)
{ int a, b, c;
printf("숫자를 세 개 입력하세요(보기: 3 5 8) : ");
scanf("%d %d %d",&a,&b,&c);
printf("입력한 수는 %d과 %d, %d입니다. \n",a,b,c);
}

(03)

#include <stdio.h>

void main(void)
{ int a, b, c;
printf("숫자를 두 개 입력하세요(보기: 3 5) : ");
scanf("%d %d",&a,&b);
c=a+b;
printf("입력한 수 : %d, %d \n",a,b);
printf("두 수의 합: %d \n",c);
}

(04)

#include <stdio.h>

void main(void)
{
printf("안녕하세요?\n여러분.");
}

(05)

#include <stdio.h>

void main(void)
{
printf("대한민국\nKorea\n만세.");
}

(06)
This is...


Love
Love...

(07) D:의 기호는 루트 디렉토리를 뜻합니다.

(08)

#include <stdio.h>

void main(void)
{
printf("빗금은 / 이고, 역빗금은 \\ 입니다.");
}

(09) printf() 함수의 문장 형식 안에 큰따옴표를 직접 사용한 것이 잘못입니다.

printf("안녕하세요? "C언어 이야기" 독자 여러분.\n");


(10)

#include <stdio.h>

void main(void)
{
printf("저는 \'C언어 이야기\'의 지은이 \"김중태\"입니다.");
}

(11) 다음과 같이 출력됩니다. 이때 빈 칸이 없다는 점에 주의합니다. 만약 빈 칸이 있는 것으로 예상했다면 틀린 것입니다.

안녕하세요?여러분께감사드립니다.

(12)
This is...Love
n
nLove...

(13)

#include <stdio.h>

void main(void)
{
printf("%s","여러분 감사합니다.");
}

(14)

#include <stdio.h>

void main(void)
{
printf("99%%의 노력이 필요합니다.");
}

(15)

결과=B
결과=66
결과=0.000000
결과=C
결과=67
결과=0.000000
결과=
결과=0
결과=68.000000

(16) B

(17) B

(18) 130

(19) 아무 것도 표시되지 않습니다.

(20) 0

(21) 67.300000

(22) C

(23) D

(24) 67

(25)

void main(void)
{
int b1=11, b2=22, b3=33;
printf("변수1= %d 변수2= %d 변수3=%d \n", b1, b2, b3);
}

(26) printf() 함수에서 %d는 네 개인데 매개변수가 세 개만 사용한 점이 잘못입니다.

(27)

#include <stdio.h>

void main(void)
{
printf("%c",69);
}

(28) char c1='kim'; 부분이 잘못입니다. c1이 char형이므로 한 글자의 문자 상수만 대입시켜 초기화 가능합니다. kim이라고 세 글자를 사용하면 안됩니다.

(29)

#include <stdio.h>

void main(void)
{
char kim[]="C언어 이야기";
printf("%s",kim);
}

(30) 두 가지가 잘못되었는데 첫 번째로 배열 선언과 초기화 부분에서 큰따옴표가 아닌 작은 따옴표로 joongtae를 감싼 것입니다. 두 번째는 printf() 함수 안의 대체문자로 %s를 사용해야 하는데 %c를 사용한 점입니다.

(31)

 This is   123
 This is    123.456
 This is       123.45600
 This is   123.456000000
 This is 123
 This is 123.456
 This is 123.45600


(32)

#include <stdio.h>

void main(void)
{
printf(" This is %-10.5f \n",12.345);
}

(33)

#include <stdio.h>

void main(void)
{
printf(" This is %10.6f \n",12.345);
}

(34)

#include <stdio.h>

main()
{
printf("Korea\n");
printf("Worldcup\n");
}

(35)

#include <stdio.h>

main()
{
printf("Korea\nWorldcup\n");
}

(36)

#include <stdio.h>

main()
{
printf("Korea\n\n\nWorldcup\n");
}

(37)

#include <stdio.h>

main()
{
printf("Korea ");
printf("Worldcup");
}

(38)

#include <stdio.h>

main()
{
printf("Korea\n");
printf("Worldcup\n");
printf("Asia\n");
}

(39)

/*2002년 한국 월드컵*/
#include <stdio.h>

main()
{
printf("Korea\n");
printf("Worldcup\n");
printf("Asia\n");
}

(40) 출력할 때 %d를 이용합니다.

#include <stdio.h>

void main(void)
{ char a='1', b='9', c='c';
printf("a=%d, b=%d, c=%d",a,b,c);
}

(41) 출력할 때 %c를 이용합니다.

#include <stdio.h>

void main(void)
{ int a=65, b=70, c=80;
printf("a=%c, b=%c, c=%c",a,b,c);
}

(42)

#include <stdio.h>

void main(void)
{ int a=65, b=66, c=67;
printf("%c%c%c",a,b,c);
}

(43)

#include <stdio.h>

void main(void)
{
printf("%d %d %d",'k','i','m');
}

(44)

#include <stdio.h>

void main(void)
{
printf("%x %x %x",98, 99, 199);
}

(45)

#include <stdio.h>

void main(void)
{
printf("%o %o %o",98, 99, 199);
}

(46)

#include <stdio.h>

void main(void)
{
printf("%E , %E",123.456, 3.14159);
}

(47)

#include <stdio.h>

void main(void)
{
printf("%E",0.00123456);
}

(48)

#include <stdio.h>

void main(void)
{
int a;
scanf("%x",&a);
printf("a=%x",a);
}

(49)

#include <stdio.h>

void main(void)
{
int a;
scanf("%x",&a);
printf("10진수a=%d, 8진수a=%o, 16진수a=%x, ",a,a,a);
}

(50)

#include <stdio.h>

void main(void)
{
int a;
scanf("%o",&a);
printf("10진수a=%d, 8진수a=%o, 16진수a=%x, ",a,a,a);
}

(51)

#include <stdio.h>

void main(void)
{
int a;
scanf("%d",&a);
printf("10진수a=%d, 8진수a=%o, 16진수a=%x, ",a,a,a);
}

출처:http://www.dal.kr/chair/c/c1701.html
제주삼다수, 2L,... 오뚜기 진라면 매운... 상하목장 유기농 흰... 남양 프렌치카페 카... 고려인삼유통 홍삼 ... 종근당건강 오메가3... 요이치 카링 유무선...