모두의 코드
씹어먹는 C 언어 - <3. 변수가 뭐지? >
이번 강좌에서 배우게 될 것은
변수란 무엇인가?
정수형, 실수형 변수
16 진법, 메모리 주소
변수 이름 짓기

안녕하세요? 여러분. 잘 지내셨나요. 지난 번에 처음으로 C 코드를 분석한 것은 이해가 잘 되셨나요? 이해가 잘 안되셨다도 괜찮습니다. 점점 C 언어를 배워감에 따라, 기존이 이해가 안 되었던 것들도 언젠가는 '아 이래서 그랬구나' 하는 순간이 오게 됩니다. 이 단계에서 여러분이 취해야 할 자세는 일단 이해가 안되는 것은 일단, 암기 하고, 포기하지 않는 것이 필요합니다.
변수란 무엇인가?
컴퓨터는 많은 내용을 기억 해야 합니다. 정확히 말하면, 컴퓨터의 '메모리' 라는 부분에 전기적인 신호를 써 놓는 것이죠. 컴퓨터가 무엇을 기억해야 되냐고 생각할 수 있지만, 우리가 많이 하는 게임인 스타크레프트만 보아도 일단, 각 유닛의 체력과 마나, 그리고 실시간으로 바뀌는 미네랄과 가스, 뿐만 아니라 유닛의 위치, 유닛의 데미지 등 모든 것을 기억해야지 우리가 게임을 제대로 즐길 수 있게 되겠지요. 만약 컴퓨터가 미네랄의 양을 제대로 기억 못한다면 미네랄이 갑자기 100 에서 0 이 되거나 10 에서 9999 로 바뀌는 참사가 발생합니다.
그렇다면 컴퓨터는 이러한 데이터들을 어떻게 기억할까요? 바로 컴퓨터의 메모리, 즉 램(RAM) 이라는 특별한 기억공간에 이를 기록합니다. 보통 우리는 흔히 램 을 설명할 때 아래 처럼 표시합니다.

마치, 각 방에 데이터들이 저장됩니다. 이 때, 컴퓨터는 각 방에 이름을 붙이는데 단순하게 숫자로 이름을 붙입니다. 0 번, 1 번, 2 번, .. 와 같이 말입니다. 우리 대부분이 사용하는 32 비트 CPU
에서는 최대 2³² 개(4GB) - 총, 42 억개 달하는 방을 가질 수 있게 되겠지요. 참고로 32 비트 숫자를 매번 쓰는게 매우 힘들기 때문에, 대개 16진법으로 주소값을 나타냅니다.
예를 들어서, 컴퓨터가 0x12345678
부터 0x1234567B
부분에 내가 캔 미네랄의 양에 관한 정보를 저장했다고 합시다. (이 한칸에는 1 바이트, 즉 -128 부터 127 까지의 수 데이터를 저장할 수 있습니다) 만약 우리가 건물을 지을 때, 내가 가진 미네랄의 양이 충분한 지 확인하기 위해, 내가 캔 미네랄의 양에 관한 정보가 필요합니다. 그런데, 이렇게 미네랄에 관한 정보가 필요로 할 때 마다 이 길고 알아보기 힘든 복잡한 주소를 일일이 써야 한다면 상당히 힘들겠지요.
하지만 다행히도 C 언어에는 변수 라는 것이 있어서, 이 모든 작업을 쉽게 할 수 있습니다. 예를들어, 내가 캔 미네랄의 양을 mineral
이라는 변수에 저장했다고 합시다. 그렇다면 컴퓨터는 '알아서' 메모리의 어딘가에 mineral
의 방을 주고 그 내용을 저장합니다. 예를들어서, 컴퓨터가 이 mineral
이라는 변수에게 4 칸의 자리를 할당해 주었다고 합시다. 이는 아래 그림처럼 메모리 상에 표시됩니다.

이 때, 우리가 미네랄을 더 캐서 8 을 추가해야한다고 봅시다. 만약 이전에 8 을 추가한다면 0x12345678
부터 0x1234567B
까지의 모든 내용을 불러와서 8 을 더한 후, 다시 집어넣는 작업을 일일이 손으로 써 주어야 되었을 것입니다.
하지만, 이제는 단순히 mineral = mineral + 8
과 같이 써 주기만 한다면 mineral
에 8 이 더해지는 것이죠. (만약 mineral = mineral + 8
이라는 식이 이해가 안되도 그냥 넘어가세요. 이 처럼 간단해 진다는 것을 말해주고 싶었을 뿐입니다)
이와 같이 C 언어에서, 바뀔 수 있는 어떤 값을 보관하는 곳을 변수 라고 합니다. 영어로는 Variable 이라 하는데, 말 그대로 바뀔 수 있는 것들 이라는 뜻입니다.
변수 선언하기
/* 변수 알아보기 */ #include <stdio.h> int main() { int a; a = 10; printf("a 의 값은 : %d \n", a); return 0; }
프로젝트를 만들어 위의 내용을 적은 후, 컴파일 해봅시다. 까먹었다면 1 강을 참조하세요. 만약 성공적으로 하였다면
실행 결과
a 의 값은 : 10
와 같이 나옵니다.
일단, 이번에도 역시 생소한 것들이 나왔기 때문에 한 문장씩 차근차근 살펴 봅시다.
int a;
음, 이게 무엇일까요? 이전에 int main()
에서 보았던 int
가 다시 나타났군요.사실 이 문장에 뜻은 a
라는 변수를 우리가 쓰겠다고 컴파일러에게 알리는 것입니다. 만약 이러한 문장이 없다면 우리가 x
가 뭐고 y
가 뭔지 알려주지도 않은 채, 친구에게 x + y
가 얼마냐? 하고 물어보는 것과 똑같은 격이 되는 것이지요.
이 때, a
앞에 붙은 int
라는 것은 int 형의 데이터를 보관한다는 뜻으로, a
에 -2147483648 에서 부터 2147483647 까지의 정수를 보관 할 수 있게 됩니다. (대략 20 억 정도라 기억하시면 됩니다) 따라서, 만약 중간의 문장을
a = 10000000000000;
와 같이 한다면 아마 a
의 값을 출력하였을 때, 이상한 결과가 나오게 됩니다. 왜냐하면 보관할 수 있는 범위를 초과하는 수를 보관했기 때문이죠.
그럼 이제, 걱정이 생깁니다. a
에 고작 10 밖에 안 넣을 거 면서, 굳이 2147483647 까지 표현할 수 있는 int
형의 변수를 왜 사용했냐고 물을 수 있습니다. 물론, int
형 보다 작은 범위의 숫자 데이터 만을 가지는 형식이 있기는 하지만 (char
등등), 일반적인 경우 정수 데이터를 보관할 때 int
형 변수를 사용합니다.
또한, 2147483647 보다 큰 수를 사용하려면 어떻게 해야되냐는 궁금증도 생기지요. 물론 이 보다도 훨씬 큰 숫자를 처리하는 데이터 형식이 있습니다. 아래의 표를 참조하세요.
타입 | 크기 | 범위 |
---|---|---|
| 1 바이트 |
|
| 최소 2 바이트 | 2 바이트일 경우 |
| 최소 2 바이트 이고 보통 시스템의 경우 4 바이트로 구현된다. | 4 바이트 일 경우 |
| 최소 4 바이트. 32 비트 시스템의 경우 4 바이트, 64 비트 시스템에선 보통 8 바이트 | |
| 최소 8 바이트 | 8 바이트일 경우 |
| 4 바이트 | 부터 까지. 정밀도는 대략 10진수로 6 자리 정도 |
| 8 바이트 | 부터 까지. 정밀도는 대략 10진수로 15 자리 정도 |
한 가지 중요한 점은 각 타입들의 크기는 char, float, double
말고 정확히 정해진 것이 없습니다. 예를 들어서 int
의 경우 C 표준을 읽어보면 최소 2 바이트 인 타입 이라고 써져 있지 몇 바이트로 해라~ 라고 써있지는 않습니다. 하지만 대부분의 시스템에서 int
는 4 바이트로 구현되어 있습니다.
세번째 열인 범위를 보시면, unsigned
와 signed
라고 나뉜 것이 있는데, 보통 int
라 하면 signed int
를 뜻합니다. 이는 음수와 양수 모두 표시할 수 있는 대신에 양수로 표현할 수 있는 범위가 줄어듭니다.
반면에 unsigned int
는 양수만을 표현할 수 있는 대신에, 양수로 표현할 수 있는 범위가 두 배로 늘어납니다. 또한 마지막에 보면 float, double, long double
이 있는데 이들은 '실수형' 자료형으로 소수(0.1, 1.4123
등) 을 표현 할 수 있습니다. 뿐만 아니라 double
의 경우, 의 수들을 표현 할 수 있습니다. (이에 대한 정확한 설명은 후에 다루겠습니다.)
a = 10;
위 문장은 무엇을 의미할까요? 언뜻 보기에도 감이 오시겠지만, 변수 a
에 10 을 집어넣는 다는 것입니다. 따라서 나중에 a
의 값을 출력한다면 10 이 나올 것입니다. 이와 같은 형태의 문장은 뒤에서 연산자에 대해 다룰 때 다시 알아보도록 하겠습니다.
printf("a 의 값은 : %d \n", a);
마지막으로, 지난번에도 보았던 printf 입니다. 그런데, 약간 다른 것이 있습니다. %d
가 출력되는 부분에 써져 있습니다. 그런데, 프로그램을 실행시켜 보았을 때 %d
는 컴퓨터에서 출력되지 않았습니다.
그 대신, %d
가 출력될 자리에 무언가 다른 것이 출력되었는데, 바로 a
의 값 입니다. 따라서,%d
는 a
의 값 (정확히는 처음 "" 다음에 오는 첫 번째 변수) 을 10 진수 로 출력하라 라는 뜻이 됩니다.
또 다른 예제를 봅시다.
/* 변수 알아보기 2*/ #include <stdio.h> int main() { int a; a = 127; printf("a 의 값은 %d 진수로 %o 입니다. \n", 8, a); printf("a 의 값은 %d 진수로 %d 입니다. \n", 10, a); printf("a 의 값은 %d 진수로 %x 입니다. \n", 16, a); return 0; }
프로그램을 제대로 짰다면 아래와 같은 결과를 볼 수 있을 것입니다.
실행 결과
a 의 값은 8 진수로 177 입니다. a 의 값은 10 진수로 127 입니다. a 의 값은 16 진수로 7f 입니다.
일단, 위 코드를 보고 생기는 궁금증은 2 가지 있습니다. %
달린게 2 개나 있는데, 이를 어떻게 해야되냐와, %d
말고도 %o
와 %x
는 무엇인가 입니다.
먼저, printf 의 작동 원리에 대해 봅시다.

printf 출력시에, 큰 따옴표로 묶인 부분 뒤에 나열된 인자들 (8, a)
가 순서대로 큰 따옴표 안의 %
부분으로 들어감을 알 수 있습니다. 따라서 , 예를들면 printf("%d %d %d %d", a,b,c,d);
와 같은 문장은 a, b, c, d
의 값이 순서대로 출력되겠죠.
이제, %o
와 %x
는 무엇일까요? 이는 인자(a
)의 값을 출력하는 형식 입니다. 즉, %o
는 a
의 값을 8 진수로 출력하라라는 뜻이고, %x
는 16 진수로 출력하라는 뜻 이죠.
실수형 변수
앞서 말했듯이, 실수형에는 float
와 double
이 있습니다. double
의 경우 int
형에 비해 덩치가 2 배나 크지만 그 만큼 엄청난 크기의 숫자를 다룰 수 있습니다. 그 대신, 처음 15 개의 숫자들만 정확하고 나머지는 10 의 지수 형태로 표현됩니다. 또한 float
과 double
의 장점은 소수를 표시할 수 있다는 점인데, 정수형 변수에서 소수를 넣는다면 (예를들어 int a; a = 1.234;
), 소수 부분은 다 잘린 채, 나중에 a
의 값을 표시해 보면 1 이 나올 것 입니다.
/* 변수 알아보기 3*/ #include <stdio.h> int main() { float a = 3.141592f; double b = 3.141592; printf("a : %f \n", a); printf("b : %f \n", b); return 0; }
실행해 본다면 아래와 같이 나오게 됩니다.
실행 결과
a : 3.141592 b : 3.141592
일단, 위 코드를 보면서 궁금한 점이 생기지 않았나요?
float a = 3.141592f; double b = 3.141592;
왜, float
형 변수 a
를 선언할 때 에는 숫자 뒤에 f
를 붙였는데 double
형 에서는 f
를 안 붙였는 지요. 왜냐하면, 그냥 f
를 안 붙이고 float a = 3.141592
로 하면 이를 double
형으로 인식하여 문제가 생길 수 있습니다. 따라서, float
형이라는 것을 확실히 표시해 주기 위해 f
를 끝에 붙이는 것입니다.
printf("a : %f \n", a); printf("b : %f \n", b);
이제, 마지막으로 %d, %o, %x
도 아닌 %f
가 등장하였습니다. 만약, 여기서 a
를 %d
형식으로 출력하면 어떻게 될까요? 한 번 해보세요. 아마 이상한 숫자가 나오게 될 것입니다. 왜냐하면 a
는 지금 정수형 변수가 아니기 때문 입니다. 설사, 우리가 a = 3f; b = 3;
라고 해도, 이미 a
와 b
를 실수형 변수로 선언하였기 때문에 컴퓨터는a ,b
를 절대 정수로 보지 않습니다.
따라서, 우리는 실수형 변수를 출력하는 형식인 %f
를 사용해야 합니다.
참고로 주의할 사항은 printf 에서 %f
를 이용해 수를 출력 할 때 다음과 같이 언제나 소수점을 뒤에 붙여 주어야 한다는 점입니다. 예를 들어서
printf("%f", 1);
을 하면 화면에 이상한 값 (아마도 0 이 출력될 것입니다) 이 나오지만
printf("%f", 1.0);
을 하면 화면에 제대로 1.0
이 출력됩니다.
printf 의 또 다른 형식
/* printf 형식 */ #include <stdio.h> int main() { float a = 3.141592f; double b = 3.141592; int c = 123; printf("a : %.2f \n", a); printf("c : %5d \n", c); printf("b : %6.3f \n", b); return 0; }
만약 위 소스를 성공적으로 쳤다면 실행시 아래와 같이 나오게 됩니다.
실행 결과
a : 3.14 c : 123 b : 3.142
printf("a : %.2f \n", a);
이번에는 %f
가 아니라 %.2f
로 약간 다릅니다. 그렇다면 .2
가 뜻 하는 것은 무엇일까요? 대충 짐작했듯이, 무조건 소수점 이하 둘째 자리 까지만 표시하라 란 뜻입니다. 따라서, 위의 경우 3.141592
중 3.14
까지만 출력되고 나머지는 잘리게 되죠.
여기서 '무조건' 이라는 것은 %.100f
로 할 경우에도, 3.141592000000....00
을 표시해서 무조건 100 개를 출력하게 합니다.
printf("c : %5d \n", c);
이번에는 %d
가 아닌 %5d
입니다. 여기서 .5
가 아님을 주의합시다. 이 말은, 숫자의 자리수를 되도록 5 자리로 맞추라는 것입니다. 따라서, 123 을 표시할 때, 5 자리를 맞추어야 하므로 앞에 공백을 남기고 그 뒤에 123 을 표시했습니다.
그런데, 123456 을 표시할 때, %5d
조건을 준다면 어떻할까요? 이 때는 그냥 123456 을 다 표시합니다. 앞서 .?f
는 ?
의 수 만큼 무조건 소수점 자리수를 맞추어야 하지만 이 경우는 반드시 지켜야 되는 것은 아닙니다
printf("b : %6.3f \n", b);
마지막으로, 위에서 썼던 두 가지 형식을 모두 한꺼번에 적용한 모습입니다. 전체 자리수는 6 자리로 맞추되 반드시 소수점 이하 3 째 자리 까지만 표시한다는 뜻입니다.
변수 작명하기
앞서, 보았듯이 변수를 선언하는 것은 어려운 일이 아닙니다. 단지, 아래의 형태로 맞추어 주기만 하면 됩니다.
(변수의 자료형) 변수1, 변수2, .....; /* 예를 들어 */ int a, b, c, hi; float d, e, f, bravo; double g, programming; long h; short i; char j, k, hello, mineral;
이 때, 변수 선언시 주의해야 할 점이 있습니다. 만약에 여러분이 오래된 버전의 C 언어 (C89) 를 사용한다면, 변수 선언시 반드시 최상단에 위치해야 합니다. 하지만, 여러분이 지금 사용하고 있는 최신 버전의 C 의 변수 사용하기 전 아무데나 변수를 선언해도 상관 없습니다.
/* 변수 선언시 주의해야 할 점 */ #include <stdio.h> int main() { int a; a = 1; printf("a 는 : %d", a); int b; // 괜찮음! return 0; }
두 번째로, 사람의 이름을 지을 때, 여러가지를 고려하듯이 변수의 이름에서도 여러가지 조건들이 있습니다. 아래 예제를 보세요.
/* 변수 선언시 주의해야 할 점 */ #include <stdio.h> int main() { int a, A; // a 와 A 는 각기 다른 변수 입니다. int 1hi; // (오류) 숫자가 앞에 위치할 수 없습니다. int hi123, h123i, h1234324; // 숫자가 뒤에 위치하면 괜찮습니다. int 한글이좋아; /* (오류) 변수는 오직 알파벳, 숫자, 그리고 _ (underscore)로만으로 이루어져야 합니다. */ int space bar; /* (오류) 변수의 이름에는 띄어쓰기하면 안됩니다. 그 대신 _ 로 대체하는 것이 읽기 좋습니다.*/ int space_bar; // 이것은 괜찮습니다. int enum, long, double, int; /* (오류) 지금 나열한 이름들은 모두 '예약어' 로 C 언어에서 이미 쓰이고 있는 것들입니다. 따라서 이러한 것들은 쓰면 안됩니다. 이를 구분하는 방법은 예약어들을 모두 외우거나 '파란색' 으로 표시된 것들은 모두 예약어라 볼 수 있습니다 */ return 0; }
이 안에 모든 내용이 들어 있습니다. 변수의 이름은 반드시
숫자가 앞에 위치하면 안됩니다. 그러나 중간이나 뒤는 괜찮습니다.
변수명은 오직 영어, 숫자,
_
로 만 구성되어 있어야 합니다.변수의 이름에 띄어쓰기가 있으면 안됩니다.
변수의 이름이 C 언어 예약어 이면 안됩니다. 보통 예약어를 쓰면 에디터에서 다른 색깔로 표시되어 예약어를 썼는지 안썼는지 알 수 있습니다.
또한 C 언어는 대소문자를 구분합니다(이를 영어로 case sensitive 하다고 합니다). 따라서, VARiable
과 Variable
은 다른 변수 입니다. 왠지, 조건이 많아 변수명을 지을 때, 까다로울 것 같지만 그냥 평범하게 짓다보면 예약어와 겹칠일 도 없고, 숫자가 앞에 오는 경우도 별로 없습니다.
좋은 변수 이름
프로그래밍을 하다보면 변수를 정의할 일이 굉장히 많습니다. 그리고 프로그램의 크기가 커지면 커질 수 록 지어야 할 변수의 이름의 양도 늘어나겠죠. 따라서 귀찮다고 변수의 이름을 아무렇게나 짓는 경우가 있습니다.
int a, b, c;
예를 들어서 위 처럼 변수들을 정의하였다고 생각해봅시다. 코드를 읽는 사람 입장에서 위 a
, b
, c
가 무슨 일을 하는지 알 수 있을까요? 아닙니다. 코드를 꼼꼼히 읽어보아야지 쟤네들이 무슨일을 하고 있는지 알 수 있겠죠.
하지만
int num_students, total_score;
위 처럼 정의한 경우 아 num_students
는 학생들의 수를 보관하는 변수구나. 아니면 total_score
는 전체 점수를 보관하는 변수구나 라고 단번에 이해할 수 있습니다. 그러면 그 뒤에 코드를 이해하는 것도 매우 편하구요. 이렇듯 변수들의 이름을 잘 짓는 것은 좋은 코드를 작성하는데 꿰어야할 첫 단추라 보시면 됩니다.
제가 생각할 때 좋은 변수 이름의 기준은 다음과 같습니다.
무슨 데이터를 보관하는지 알 수 있어야 한다.
(되도록이면) 영어로 읽히도록 해야 한다. 한국말을 영어로 풀어쓰는 경우도 종종 있는데 이해하기 어렵습니다.
한 가지 스타일을 고수하자.
여기서 한 가지 스타일이란, 흔히 변수들의 이름을 표현하는데 두 가지 방식이 사용됩니다. 하나는 띄어쓰기를 _
로 나타내는 방식으로
int this_is_some_variable;
위와 같습니다. 다른 하나는 Camel case 라는 방식으로, 대소문자로 이용해 구분하는 방식입니다.
int ThisIsSomeVariable;
글자의 높낮이가 마치 낙타의 등 같다고 해서 Camel case 라고 불리는데, 위 두 가지 방식 모두 많이 사용됩니다. 다만 한 프로그램에서 _
를 사용하겠다고 했으면 쭉 그 방식대로 가고, Camel case 를 사용하겠다고 했으면 쭉 그 방식으로 가야지 두 가지를 혼용하면 코드를 읽는 사람 입장에서 매우 혼란스럽습니다.
아무튼 위 점을 명시하고 코드를 작성한다면 읽기 쉬운 코드를 작성하는데 도움이 될 것입니다.
자, 이제 우리는 C 언어에서 중요한 부분인 변수에 대해서 알아보았습니다. 현재 우리는 수를 다루는 변수들만 다루었지만, 다음 강좌에서는 변수에 대한 산술 연산과, 문자를 다루는 변수에 대해 알아보도록 하겠습니다.
뭘 배웠지?
변수는 데이터를 임시로 저장하는 곳이며 자유롭게 쓰고 지울 수 있습니다.
각 변수에는 형(type) 이 있어서 해당 형에 맞는 데이터를 보관할 수 있습니다.
변수의 형으로는 정수값을 보관하는 char
, int
등이 있고, 실수값을 보관하는 float
과 double
이 있습니다. 각각의 형들은 저장하는 데이터의 크기가 다릅니다.
int a = 10;
의 문장의 의미는 a
라는 정수형 변수를 정의한 뒤에, 해당 변수에 10 의 값을 대입한다 라는 뜻입니다.
변수의 이름을 정하기 위해서는 여러가지 규칙이 있습니다. 이 규칙에 알맞게 변수의 이름을 정해야 되며 그렇지 않을 경우 컴파일 오류가 발생합니다.

댓글을 불러오는 중입니다..