프로그램이 말을 걸기 시작할 때
앞 장까지 우리는 값을 저장하는 방법을 배웠습니다. int에는 정수를, double에는 더 정밀한 실수를, char에는 문자 하나를 담을 수 있었습니다. 그런데 변수만으로는 프로그램이 조금 외롭습니다. 값을 담아도 밖으로 보여 주지 않으면 사용자는 알 수 없고, 사용자가 값을 넣을 수 없으면 프로그램은 늘 같은 일만 반복합니다.
입력과 출력은 프로그램이 세상과 연결되는 통로입니다. 출력은 프로그램이 사용자에게 말하는 일이고, 입력은 사용자가 프로그램에게 대답하는 일입니다.
printf("안녕하세요!n");
scanf("%d", &age);이 두 줄은 아주 짧지만, 그 안에는 C언어다운 중요한 감각이 들어 있습니다. printf는 값을 어떤 모양으로 보여 줄지 정하고, scanf는 사용자가 입력한 글자를 어떤 자료형의 값으로 바꿔 변수에 저장합니다. 여기서 중요한 질문이 하나 나옵니다.
"프로그램은 사용자가 입력한 값을 어디에 넣어야 하는지 어떻게 알까?"
이 질문은 나중에 포인터를 배울 때 다시 만납니다. 이번 장에서는 그 예고편으로 & 기호를 만나게 됩니다.

printf 다시 보기
printf는 콘솔 화면에 글자와 값을 출력하는 함수입니다. 첫 번째 C 프로그램에서 이미 사용했습니다.
#include <stdio.h>
int main(void)
{
printf("Hello, C!n");
return 0;
}printf에서 따옴표 안에 들어가는 문자열을 형식 문자열이라고 부릅니다. 형식 문자열은 "무엇을 어떤 모양으로 출력할지"를 설명하는 안내문입니다.
printf("나이는 %d살입니다.n", 20);이 코드에서 %d는 정수를 출력할 자리입니다. printf는 형식 문자열을 왼쪽부터 읽다가 %d를 만나면, 뒤에 있는 값 20을 가져와 그 자리에 넣습니다. 그래서 출력 결과는 다음과 같습니다.
나이는 20살입니다.조금 더 여러 값을 출력해 봅시다.
#include <stdio.h>
int main(void)
{
int age = 20;
double height = 175.5;
char grade = 'A';
printf("나이: %dn", age);
printf("키: %fn", height);
printf("등급: %cn", grade);
return 0;
}출력은 대략 다음과 같습니다.
나이: 20
키: 175.500000
등급: A여기서 height를 출력했더니 175.500000처럼 소수점 아래 여섯 자리가 나왔습니다. C의 printf는 실수를 %f로 출력할 때 기본적으로 소수점 아래 여섯 자리까지 보여 줍니다. 꼭 필요한 만큼만 보여 주고 싶다면 잠시 뒤 배울 소수점 자리수 옵션을 사용하면 됩니다.
형식 지정자는 약속이다
%d, %f, %c처럼 값이 들어갈 자리를 표시하는 기호를 형식 지정자라고 합니다. 형식 지정자는 단순한 장식이 아닙니다. printf에게 "뒤에 오는 값을 이런 자료형으로 해석해서 출력해 줘"라고 알려 주는 약속입니다.
자주 쓰는 형식 지정자는 다음과 같습니다.
| 형식 지정자 | 의미 | 주로 연결되는 자료형 |
|---|---|---|
%d | 부호 있는 10진 정수 | int |
%u | 부호 없는 10진 정수 | unsigned int |
%f | 실수 출력 | float, double |
%lf | printf에서는 보통 %f와 같은 방식으로 동작 | double |
%c | 문자 하나 | char |
%s | 문자열 | 문자 배열 |
%zu | 크기 값 | sizeof 결과 |
앞 장에서 sizeof를 배울 때 이런 코드를 보았을 수 있습니다.
printf("int의 크기: %zu바이트n", sizeof(int));sizeof의 결과는 정수처럼 보이지만, 정확히는 size_t라는 크기 전용 자료형입니다. 그래서 sizeof 결과를 출력할 때는 %zu를 쓰는 것이 좋습니다.
형식 지정자가 실제 값의 자료형과 맞지 않으면 문제가 생길 수 있습니다.
int age = 20;
printf("나이: %fn", age); // 잘못된 예age는 int인데 %f는 실수처럼 해석하라는 뜻입니다. 사람이라면 "아, 실수했구나" 하고 알아차릴 수 있지만, C는 그렇게 친절하지 않습니다. printf는 형식 문자열을 믿고 값을 해석합니다. 정수로 저장된 값을 실수처럼 읽으려 하면 엉뚱한 값이 나오거나, 실행 결과를 예측하기 어려워질 수 있습니다.
C에서는 값이 메모리에 0과 1의 모양으로 저장됩니다. 같은 4바이트라도 그것을 정수로 읽을지, 실수로 읽을지에 따라 의미가 완전히 달라집니다. 형식 지정자는 바로 그 해석 방법을 정하는 표시입니다.
#include <stdio.h>
int main(void)
{
int n = 65;
char ch = 'A';
printf("n을 정수로 출력: %dn", n);
printf("n을 문자로 출력: %cn", n);
printf("ch를 문자로 출력: %cn", ch);
printf("ch를 정수로 출력: %dn", ch);
return 0;
}출력은 보통 다음과 같습니다.
n을 정수로 출력: 65
n을 문자로 출력: A
ch를 문자로 출력: A
ch를 정수로 출력: 65이 예제는 앞 장의 char와 잘 이어집니다. 문자 'A'는 컴퓨터 안에서 문자 코드 값으로 저장됩니다. 그래서 같은 값을 %c로 출력하면 문자처럼 보이고, %d로 출력하면 숫자 코드처럼 보입니다. 값은 하나인데, 해석하는 방식에 따라 화면에 나타나는 모습이 달라지는 것입니다.
printf로 보기 좋게 출력하기
프로그램은 계산만 잘한다고 끝이 아닙니다. 결과를 읽기 좋게 보여 주는 것도 중요합니다. 사람이 보는 프로그램에서는 출력 모양이 곧 친절함입니다.
다음 코드를 봅시다.
#include <stdio.h>
int main(void)
{
printf("%d %d %dn", 1, 20, 300);
printf("%d %d %dn", 4000, 50, 6);
return 0;
}출력은 다음처럼 조금 들쭉날쭉합니다.
1 20 300
4000 50 6값이 적을 때는 괜찮지만, 표처럼 보여 주고 싶다면 자릿수를 맞추는 편이 좋습니다.
printf("%5d %5d %5dn", 1, 20, 300);
printf("%5d %5d %5dn", 4000, 50, 6);%5d는 정수를 출력하되, 최소 5칸을 사용하라는 뜻입니다. 값이 5칸보다 짧으면 앞쪽에 공백을 넣어 오른쪽 정렬합니다.
1 20 300
4000 50 6왼쪽 정렬을 하고 싶다면 -를 붙입니다.
printf("%-5d %-5d %-5dn", 1, 20, 300);
printf("%-5d %-5d %-5dn", 4000, 50, 6);1 20 300
4000 50 6실수는 소수점 자리수를 정할 수 있습니다.
#include <stdio.h>
int main(void)
{
double pi = 3.1415926535;
printf("기본 출력: %fn", pi);
printf("소수점 둘째 자리: %.2fn", pi);
printf("소수점 셋째 자리: %.3fn", pi);
printf("전체 8칸, 소수점 둘째 자리: %8.2fn", pi);
return 0;
}출력은 다음과 같습니다.
기본 출력: 3.141593
소수점 둘째 자리: 3.14
소수점 셋째 자리: 3.142
전체 8칸, 소수점 둘째 자리: 3.14%.2f에서 .2는 소수점 아래 두 자리까지 출력하라는 뜻입니다. 이때 단순히 잘라 내는 것이 아니라 표시되는 자리에서 반올림되어 보입니다.
%8.2f는 전체 폭을 8칸으로 잡고, 소수점 아래는 2자리까지 보여 달라는 뜻입니다. 이런 기능을 쓰면 점수표, 영수증, 계산 결과 등을 훨씬 깔끔하게 출력할 수 있습니다.
#include <stdio.h>
int main(void)
{
char name1[] = "Kim";
char name2[] = "Lee";
char name3[] = "Park";
int score1 = 95;
int score2 = 87;
int score3 = 100;
printf("%-10s %5sn", "Name", "Score");
printf("%-10s %5dn", name1, score1);
printf("%-10s %5dn", name2, score2);
printf("%-10s %5dn", name3, score3);
return 0;
}Name Score
Kim 95
Lee 87
Park 100아직 문자열을 깊게 배우지는 않았지만, 여기서는 "Kim", "Lee", "Park"처럼 여러 글자로 된 값을 %s로 출력할 수 있다는 정도만 기억하면 됩니다.
scanf로 입력받기
이제 사용자가 직접 값을 넣게 해 봅시다. C에서 콘솔 입력을 받을 때 자주 사용하는 함수가 scanf입니다.
#include <stdio.h>
int main(void)
{
int age;
printf("나이를 입력하세요: ");
scanf("%d", &age);
printf("당신의 나이는 %d살입니다.n", age);
return 0;
}실행하면 프로그램은 사용자가 숫자를 입력할 때까지 기다립니다.
나이를 입력하세요: 20
당신의 나이는 20살입니다.scanf("%d", &age);를 천천히 읽어 봅시다. %d는 정수 형태의 입력을 읽겠다는 뜻입니다. 그런데 age 앞에 이상한 기호가 붙어 있습니다.
&age이 &는 주소 연산자입니다. 지금은 이렇게 이해하면 됩니다.
age는 변수 안에 들어 있는 값이고,&age는 그 변수가 메모리 어디에 있는지를 나타내는 주소입니다.
scanf는 사용자가 입력한 값을 변수에 저장해야 합니다. 그러려면 변수의 현재 값만 알아서는 안 됩니다. 값을 넣을 위치를 알아야 합니다. 택배 기사에게 "사과를 보내 주세요"라고만 말하면 배달할 수 없습니다. 주소를 알려 줘야 합니다. scanf에게도 마찬가지입니다.
scanf("%d", &age);이 코드는 scanf에게 이렇게 말하는 것과 같습니다.
"사용자가 입력한 값을 정수로 읽어서, age라는 변수의 주소에 저장해 줘."
포인터 장에서 이 주소 개념을 본격적으로 다룰 것입니다. 지금은 scanf로 일반 변수를 입력받을 때 변수 앞에 &를 붙인다고 기억해도 충분합니다.
int n;
double x;
char ch;
scanf("%d", &n);
scanf("%lf", &x);
scanf("%c", &ch);여기서 주의할 점이 있습니다. printf에서는 double을 출력할 때 보통 %f를 사용했습니다. 하지만 scanf에서 double을 입력받을 때는 %lf를 사용해야 합니다.
double height;
scanf("%lf", &height); // double 입력반면 float을 입력받을 때는 %f입니다.
float weight;
scanf("%f", &weight); // float 입력왜 이렇게 다를까요? printf와 scanf는 둘 다 형식 지정자를 쓰지만, 하는 일이 다릅니다. printf는 값을 읽어서 화면에 보여 주고, scanf는 입력을 읽어서 변수의 주소에 저장합니다. 저장할 공간의 크기와 종류가 정확히 맞아야 하므로, scanf에서는 float의 주소인지 double의 주소인지 구분해야 합니다.
정리하면 다음과 같습니다.
| 자료형 | printf 출력 | scanf 입력 |
|---|---|---|
int | %d | %d |
float | %f | %f |
double | %f | %lf |
char | %c | %c |
| 문자열 | %s | %s |
이 표에서 특히 double의 입력 형식 %lf를 눈여겨보세요. 초보자가 자주 틀리는 부분입니다.
scanf의 성공 여부 확인하기
scanf는 값을 입력받은 뒤, 성공적으로 읽은 항목의 개수를 반환합니다. 이 기능을 사용하면 사용자가 엉뚱한 값을 입력했을 때 조금 더 안전하게 처리할 수 있습니다.
#include <stdio.h>
int main(void)
{
int age;
printf("나이를 입력하세요: ");
if (scanf("%d", &age) == 1)
{
printf("입력된 나이: %dn", age);
}
else
{
printf("숫자를 입력해야 합니다.n");
}
return 0;
}아직 조건문을 배우기 전이라 if가 낯설 수 있습니다. 여기서는 흐름만 보면 됩니다. scanf("%d", &age)가 정수 하나를 제대로 읽으면 1을 돌려줍니다. 사용자가 hello처럼 숫자가 아닌 값을 입력하면 정수를 읽지 못하므로 1이 아닙니다.
실무에서는 입력이 항상 올바르다고 믿으면 안 됩니다. 사용자는 실수로 문자를 입력할 수도 있고, 빈 줄을 입력할 수도 있고, 프로그램이 기대한 것보다 긴 값을 입력할 수도 있습니다. 지금은 간단한 예제 위주로 진행하지만, "입력은 의심하면서 다룬다"는 습관을 들이면 좋습니다.
여러 값을 한 번에 입력받기
scanf는 여러 값을 한 번에 입력받을 수 있습니다.
#include <stdio.h>
int main(void)
{
int a, b;
printf("정수 두 개를 입력하세요: ");
scanf("%d %d", &a, &b);
printf("a = %d, b = %dn", a, b);
return 0;
}사용자는 다음처럼 공백으로 구분해서 입력할 수 있습니다.
정수 두 개를 입력하세요: 10 20
a = 10, b = 20줄을 나누어 입력해도 됩니다.
정수 두 개를 입력하세요: 10
20
a = 10, b = 20scanf에서 %d, %f, %lf, %s 같은 형식 지정자는 대체로 공백 문자, 즉 스페이스, 탭, 줄바꿈을 건너뛰고 값을 읽습니다. 그래서 10 20처럼 한 줄에 입력해도 되고, 10을 입력한 뒤 엔터를 치고 다시 20을 입력해도 됩니다.
하지만 모든 형식 지정자가 공백을 건너뛰는 것은 아닙니다. 특히 %c는 다릅니다. 이 차이 때문에 곧 입력 버퍼 문제가 등장합니다.
입력 버퍼라는 대기실
사용자가 키보드로 입력한 글자는 곧장 변수 안으로 순간이동하지 않습니다. 중간에 입력 버퍼라는 대기실에 잠시 머무릅니다. 버퍼는 데이터를 임시로 저장해 두는 공간입니다.
예를 들어 사용자가 다음처럼 입력했다고 해 봅시다.
123사람 눈에는 숫자 123을 입력한 것처럼 보이지만, 실제로는 1, 2, 3, 그리고 엔터를 눌렀다는 표시인 줄바꿈 문자 n까지 입력됩니다.
1 2 3 nscanf("%d", &num)은 여기서 숫자 부분 123을 읽어 정수로 바꿉니다. 그런데 줄바꿈 문자 n은 입력 버퍼에 남을 수 있습니다. 이 남은 줄바꿈이 다음 입력에서 문제를 일으킵니다.
다음 코드를 실행해 봅시다.
#include <stdio.h>
int main(void)
{
int age;
char grade;
printf("나이를 입력하세요: ");
scanf("%d", &age);
printf("등급 문자를 입력하세요: ");
scanf("%c", &grade);
printf("나이: %dn", age);
printf("등급: %cn", grade);
return 0;
}우리는 이렇게 진행되기를 기대합니다.
나이를 입력하세요: 20
등급 문자를 입력하세요: A
나이: 20
등급: A그런데 실제로는 등급 문자를 입력하세요:가 나오자마자 입력이 끝나 버리는 것처럼 보일 수 있습니다. 왜 그럴까요?
scanf("%d", &age)가 20을 읽은 뒤, 사용자가 누른 엔터의 줄바꿈 문자 n이 버퍼에 남아 있습니다. 다음 scanf("%c", &grade)는 문자 하나를 읽는데, %c는 공백이나 줄바꿈도 하나의 문자로 취급합니다. 그래서 사용자가 A를 입력하기도 전에 버퍼에 남아 있던 n을 읽어 버립니다.
이 문제를 해결하는 가장 간단한 습관은 %c 앞에 공백을 하나 넣는 것입니다.
scanf(" %c", &grade);전체 코드는 이렇게 바뀝니다.
#include <stdio.h>
int main(void)
{
int age;
char grade;
printf("나이를 입력하세요: ");
scanf("%d", &age);
printf("등급 문자를 입력하세요: ");
scanf(" %c", &grade);
printf("나이: %dn", age);
printf("등급: %cn", grade);
return 0;
}" %c"에서 %c 앞의 공백은 "문자를 읽기 전에 남아 있는 공백, 탭, 줄바꿈을 건너뛰라"는 뜻입니다. 이 작은 공백 하나가 초보자의 많은 밤을 구합니다.
비슷한 방법으로 getchar()를 사용해 남은 문자를 하나 읽어 버릴 수도 있습니다.
scanf("%d", &age);
getchar();
scanf("%c", &grade);하지만 입력 상황이 복잡해지면 getchar() 하나로 충분하지 않을 수 있습니다. 버퍼에 문자가 여러 개 남아 있을 수도 있기 때문입니다. 지금 단계에서는 숫자 입력 뒤 문자 하나를 입력받을 때 scanf(" %c", &ch);처럼 앞에 공백을 넣는 습관을 먼저 익히면 좋습니다.
주의할 점도 있습니다. 인터넷에서 fflush(stdin);으로 입력 버퍼를 비우는 예제를 볼 수 있습니다. 하지만 표준 C에서 fflush는 출력 스트림을 비울 때 쓰는 함수이고, 입력 스트림인 stdin에 사용하는 동작은 표준적으로 보장되지 않습니다. 특정 컴파일러에서는 되는 것처럼 보여도 다른 환경에서는 다르게 동작할 수 있으므로, 처음 배울 때는 피하는 편이 좋습니다.
문자 입력과 문자열 입력
문자 하나는 char 변수에 저장합니다.
char ch;
scanf(" %c", &ch);문자열은 여러 문자로 이루어진 값입니다. C에서는 문자열을 저장하기 위해 보통 문자 배열을 사용합니다.
char name[20];
scanf("%s", name);여기서 이상한 점이 보일 수 있습니다. int, double, char를 입력받을 때는 변수 앞에 &를 붙였는데, name 앞에는 붙이지 않았습니다.
scanf("%d", &age); // int 변수
scanf("%lf", &height); // double 변수
scanf(" %c", &grade); // char 변수
scanf("%s", name); // 문자 배열문자 배열 이름 name은 배열이 시작되는 위치를 가리키는 정보처럼 사용됩니다. 정확한 내용은 배열과 포인터를 배울 때 자세히 다루겠습니다. 지금은 문자열을 %s로 입력받을 때는 배열 이름을 그대로 쓴다고 기억하면 됩니다.
간단한 이름 입력 프로그램을 만들어 봅시다.
#include <stdio.h>
int main(void)
{
char name[20];
int age;
printf("이름을 입력하세요: ");
scanf("%s", name);
printf("나이를 입력하세요: ");
scanf("%d", &age);
printf("안녕하세요, %s님!n", name);
printf("당신은 %d살입니다.n", age);
return 0;
}실행 예는 다음과 같습니다.
이름을 입력하세요: Mina
나이를 입력하세요: 21
안녕하세요, Mina님!
당신은 21살입니다.하지만 %s에도 중요한 한계가 있습니다. %s는 공백을 만나면 입력을 멈춥니다.
이름을 입력하세요: Kim Mina이렇게 입력하면 name에는 Kim까지만 들어갑니다. 뒤의 Mina는 버퍼에 남을 수 있습니다. 공백이 포함된 한 줄 전체를 입력받는 방법은 뒤에서 문자열을 더 자세히 배울 때 fgets와 함께 다루겠습니다.
또 하나의 큰 문제가 있습니다. char name[20];은 문자를 저장할 수 있는 공간이 20칸이라는 뜻입니다. 그런데 사용자가 100글자를 입력하면 어떻게 될까요? 배열의 범위를 넘어 다른 메모리 공간을 침범할 수 있습니다. C에서는 이런 일이 실제로 벌어질 수 있고, 매우 위험합니다.
그래서 scanf로 문자열을 입력받을 때는 최대 폭을 지정하는 습관이 좋습니다.
char name[20];
scanf("%19s", name);왜 20이 아니라 19일까요? C 문자열은 마지막에 문자열의 끝을 표시하는 널 문자 0이 필요합니다. name[20]에는 실제 글자 최대 19개와 끝 표시 0 하나가 들어갈 수 있습니다. 문자열 장에서 이 원리를 자세히 배울 것입니다.
안전한 입력을 위한 작은 습관
C의 입력은 강력하지만, 그만큼 조심해야 합니다. Python이나 JavaScript에서는 입력값을 문자열로 받은 뒤 변환하는 과정에서 여러 안전장치가 따라오는 경우가 많습니다. 하지만 C에서는 개발자가 직접 더 많은 것을 확인해야 합니다.
안전한 입력을 위해 다음 습관을 기억해 둡시다.
scanf의 형식 지정자와 변수 자료형을 반드시 맞춥니다.일반 변수에 입력할 때는 변수 앞에
&를 붙입니다.double입력에는%lf,float입력에는%f를 사용합니다.숫자 입력 뒤 문자 입력을 받을 때는
" %c"처럼 앞에 공백을 넣습니다.문자열 입력에는 배열 크기를 고려해
%19s처럼 최대 폭을 지정합니다.가능하면
scanf의 반환값을 확인해 입력 성공 여부를 판단합니다.
Visual Studio를 사용하는 경우 scanf를 썼을 때 보안 관련 경고가 나올 수 있습니다. Microsoft 환경에서는 scanf_s라는 함수를 권장하기도 합니다. 이 책에서는 표준 C에서 널리 쓰이는 scanf를 중심으로 설명하되, 실습 환경에 따라 경고가 보이면 프로젝트 설정을 조정하거나, 문자열 입력에서는 scanf_s 사용법을 따로 확인해야 할 수 있습니다. 중요한 것은 함수 이름보다 원리입니다. 입력받을 공간의 크기와 자료형을 정확히 알고 있어야 한다는 사실은 어떤 환경에서도 같습니다.
입력, 처리, 출력의 흐름
대부분의 프로그램은 크게 세 단계로 움직입니다.
입력을 받습니다.
입력받은 값을 처리합니다.
처리 결과를 출력합니다.
예를 들어 두 수를 더하는 프로그램을 생각해 봅시다.
#include <stdio.h>
int main(void)
{
int a, b;
int sum;
printf("첫 번째 정수: ");
scanf("%d", &a);
printf("두 번째 정수: ");
scanf("%d", &b);
sum = a + b;
printf("%d + %d = %dn", a, b, sum);
return 0;
}이 코드는 아주 단순하지만 프로그램의 기본 구조를 잘 보여 줍니다.
첫 번째 정수: 10
두 번째 정수: 20
10 + 20 = 30scanf로 사용자의 값을 받아 변수에 저장합니다. sum = a + b;에서 계산합니다. printf로 결과를 보여 줍니다. 앞으로 조건문, 반복문, 함수, 배열을 배우더라도 이 큰 흐름은 계속 반복됩니다.
간단한 사칙연산 계산기 만들기
이제 이번 장의 내용을 모아 작은 계산기를 만들어 봅시다. 두 실수와 연산자 하나를 입력받아 계산 결과를 출력하는 프로그램입니다.
#include <stdio.h>
int main(void)
{
double a, b;
char op;
double result;
printf("첫 번째 숫자를 입력하세요: ");
scanf("%lf", &a);
printf("연산자를 입력하세요(+, -, *, /): ");
scanf(" %c", &op);
printf("두 번째 숫자를 입력하세요: ");
scanf("%lf", &b);
if (op == '+')
{
result = a + b;
printf("%.2f + %.2f = %.2fn", a, b, result);
}
else if (op == '-')
{
result = a - b;
printf("%.2f - %.2f = %.2fn", a, b, result);
}
else if (op == '*')
{
result = a * b;
printf("%.2f * %.2f = %.2fn", a, b, result);
}
else if (op == '/')
{
result = a / b;
printf("%.2f / %.2f = %.2fn", a, b, result);
}
else
{
printf("알 수 없는 연산자입니다.n");
}
return 0;
}아직 조건문을 배우기 전이므로 if, else if, else가 낯설 수 있습니다. 지금은 "연산자가 무엇인지에 따라 실행할 코드를 고르는 장치"라고 생각하면 됩니다. 조건문은 7장에서 차근차근 배웁니다.
실행 예는 다음과 같습니다.
첫 번째 숫자를 입력하세요: 10.5
연산자를 입력하세요(+, -, *, /): *
두 번째 숫자를 입력하세요: 3
10.50 * 3.00 = 31.50이 예제에는 이번 장의 핵심이 모두 들어 있습니다. double 값을 입력받기 위해 %lf를 사용했고, 문자 연산자를 입력받기 위해 " %c"를 사용했습니다. 결과를 보기 좋게 출력하기 위해 %.2f로 소수점 아래 두 자리까지 표시했습니다.
다만 이 계산기에는 아직 부족한 점이 있습니다. 나눗셈에서 두 번째 숫자로 0을 입력하면 문제가 됩니다. 잘못된 입력을 더 친절하게 처리하는 방법도 필요합니다. 이런 개선은 조건문을 배운 뒤 더 자연스럽게 할 수 있습니다.
형식 지정자가 틀릴 때 생기는 이상한 일
C를 배우다 보면 이런 실수를 자주 합니다.
int n;
scanf("%f", &n); // 잘못된 예n은 int 변수인데 %f는 float 값을 저장하겠다는 뜻입니다. scanf는 &n이 가리키는 공간을 float을 저장할 공간이라고 믿고 값을 써 넣으려 합니다. 그러나 실제 공간은 int 변수의 공간입니다. 이처럼 저장 방식이 어긋나면 변수 값이 이상해지거나 프로그램이 불안정해질 수 있습니다.
또 다른 실수도 있습니다.
int n;
scanf("%d", n); // 잘못된 예: &가 없음이 코드는 n의 주소가 아니라 n 안에 들어 있는 값을 scanf에게 넘깁니다. scanf는 그 값을 주소라고 착각하고 그 위치에 입력값을 저장하려고 합니다. 그 위치가 프로그램이 건드리면 안 되는 메모리라면 실행 중 오류가 날 수 있습니다.
이런 실수는 C가 컴퓨터 가까이에서 동작하는 언어라는 사실을 잘 보여 줍니다. C는 개발자에게 많은 권한을 줍니다. 하지만 주소와 자료형을 잘못 알려 주면 컴퓨터는 그 말을 그대로 믿고 실행합니다. C를 배운다는 것은 컴퓨터에게 정확히 말하는 법을 배우는 일이기도 합니다.
작은 실습: 나만의 프로필 카드
이번에는 입력과 출력을 이용해 프로필 카드를 만들어 봅시다.
#include <stdio.h>
int main(void)
{
char name[20];
int age;
double height;
char bloodType;
printf("이름을 입력하세요: ");
scanf("%19s", name);
printf("나이를 입력하세요: ");
scanf("%d", &age);
printf("키를 입력하세요(cm): ");
scanf("%lf", &height);
printf("혈액형을 입력하세요(A, B, O, AB 중 첫 글자): ");
scanf(" %c", &bloodType);
printf("n");
printf("====================n");
printf(" PROFILE n");
printf("====================n");
printf("이름 : %sn", name);
printf("나이 : %d세n", age);
printf("키 : %.1fcmn", height);
printf("혈액형 : %c형n", bloodType);
printf("====================n");
return 0;
}실행 예는 다음과 같습니다.
이름을 입력하세요: Jisu
나이를 입력하세요: 19
키를 입력하세요(cm): 162.7
혈액형을 입력하세요(A, B, O, AB 중 첫 글자): A
====================
PROFILE
====================
이름 : Jisu
나이 : 19세
키 : 162.7cm
혈액형 : A형
====================이 예제에서 scanf(" %c", &bloodType);를 사용한 이유를 다시 떠올려 봅시다. 앞에서 나이와 키를 입력하면서 엔터를 눌렀습니다. 문자 입력 전에 남아 있을 수 있는 줄바꿈을 건너뛰기 위해 %c 앞에 공백을 넣었습니다.
또 name은 char name[20];으로 만들었기 때문에 scanf("%19s", name);처럼 최대 입력 폭을 19로 제한했습니다. 아직 배열과 문자열을 본격적으로 배우기 전이지만, "공간보다 많이 입력받지 않는다"는 원칙은 지금부터 익혀야 합니다.
이번 장에서 기억할 것
입력과 출력은 프로그램을 살아 움직이게 합니다. printf가 없으면 프로그램은 자기 생각을 말하지 못하고, scanf가 없으면 사용자의 대답을 듣지 못합니다. 이 두 함수만 잘 다뤄도 프로그램은 계산기, 설문지, 점수표, 간단한 게임의 모습을 갖추기 시작합니다.
이번 장의 핵심을 정리해 봅시다.
printf는 형식 문자열과 형식 지정자를 사용해 값을 원하는 모양으로 출력합니다.형식 지정자는 실제 인자의 자료형과 맞아야 합니다.
scanf는 입력값을 변수에 저장하기 위해 변수의 주소를 필요로 하므로 일반 변수 앞에&를 붙입니다.double을scanf로 입력받을 때는%lf를 사용합니다.%c는 줄바꿈도 문자로 읽을 수 있으므로 숫자 입력 뒤 문자 입력에는" %c"를 자주 사용합니다.문자열 입력에는 배열 크기를 넘지 않도록 입력 폭을 지정하는 습관이 필요합니다.
좋은 프로그램은 입력, 처리, 출력의 흐름이 분명합니다.
다음 장에서는 입력받은 값으로 더 다양한 계산을 하기 위해 연산자를 배웁니다. 더하기와 빼기 같은 산술 연산뿐 아니라, 값을 비교하고 참과 거짓을 판단하는 연산자도 만나게 됩니다. 프로그램은 이제 단순히 말하고 듣는 단계를 넘어, 스스로 판단할 준비를 하게 됩니다.
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.
