2.4 Variables and Assignment
2.1장의 프로그램만큼 간단한 프로그램은 거의 없다. 대부분의 프로그램은 출력을 생성하기 전에 일련의 계산을 수행해야 하므로 프로그램 실행 중에 데이터를 일시적으로 저장할 수 있는 방법이 필요하다. C에서는 대부분의 프로그래밍 언어와 같이 이러한 저장 위치를 ''변수''라고 말한다.
Types
모든 변수에는 저장할 데이터의 종류를 지정하는 '형'이 있어야 한다. C는 형이 매우 다양한데, 지금은 int와 float 두개에 대해서만 공부할 것이다. '형'은 변수 저장 방법과 변수에 대해 수행할 수 있는 작업에 영향을 미치기 때문에 적절한 형을 선택하는 것이 중요하다. 숫자 변수의 형은 변수가 저장할 수 있는 가장 큰 숫자와 가장 작은 숫자를 결정한다. 또한 소숫점 이하의 자리수가 있는지의 여부에 따라 결정된다.
int(정수integer의 줄임) 변수는 0, 1, 392, -2533같은 정수 전체를 저장할 수 있다. 그러나, 가능한 값의 범위는 제한되어 있는데, 가장 큰 수는 보통 2,147,483,647(21억 4548만 3647)이지만, 32,767만큼의 오차가 있을 수 있다.(하드웨어에 따라서)
float(부동소수점 floating-point의 줄임) 변수는 int 변수보다 훨씬 큰 숫자를 저장할 수 있으며, 379.125같은 소수를 저장할 수 있다. 하지만 단점이 있는데, 소수의 연산은 int 숫자의 연산보다 느릴 수 있다. 가장 중요한 것은 종종 저장된 값이 원래 숫자의 근사치로 나올때가 있다는 것이다. 예를 들어 부동 변수에 0.1을 저장했을때 나중에 반올림 오류로 인해 0.099999997과 같은 값을 갖기도 한다.
Declarations
변수를 사용하려면 컴파일러를 위해서 먼저 변수를 선언해야 한다. 변수를 선언하기 위해 먼저, 변수의 유형, 변수이름을 지정한다. (변수 이름은 임의로 하되, 2.7장에 규칙을 적어두었다.) 예를 들면 다음과 같이 높이, 이익에 대한 변수를 선언할 수 있다.
int height;
float profit;
첫번째 선언문은 높이가 int형의 변수임을 나타내며, 높이가 정수값을 저장할 수 있음을 의미한다. 두번째 선언문도 float 형으로 마찬가지로 설명을 할 수 있다.
여러 변수의 형이 동일하면, 선언문을 합칠수 있다.
int height, length, width, volume;
float profit, loss;
각각의 선언은 세미콜론으로 끝난다.
첫번째 템플릿의 main함수에서는 선언을 포함하지 않았다. main에 변수를 포함할때, 선행해야할 문장이 있다.
int main(void)
{
declarations //변수
statements //문장
}
9장에서 보겠지만, 이것은 블록(임베디드 선언이 포함된 문장)에서와 마찬가지로 일반적인 함수에서 따라야한다. 스타일의 문제이지만, 선언과 문장 사이에 공백을 남기는 것도 좋은 방법이다.
C99에서는 선언문이 문장 앞에 나올 필요가 없다. 예를 들어 main은 선언-문장-또다른 선언이 허용된다. 이전 컴파일러와의 호환성을 위해, 이 책의 프로그램은 이번 룰을 따르지 않는다. 그러나 C++이나 Java 프로그램에서는 선언을 처음으로 필요할때까지 넣지 않는 것이 흔한 일이다.
Assignment
변수는 할당을 통해 값을 지정할 수 있다. 예를 들어, 다음 문장은 height, length, width에 대해 값을 할당한다.
height = 8;
length = 12;
width = 10;
8, 12, 10은 상수라고 부른다. 변수를 할당하거나, 다른 방법으로 사용하기 위해서는 먼저 변수를 선언해야한다.
그러므로 다음과 같이 쓸수 있다.
int height;
height = 8;
하지만 다음처럼은 쓸 수 없다.
height = 8; /*** WRONG ***/
int height;
float변수에 할당된 상수에는 일반적으로 소수점이 포함된다. 예를 들어 수익이 float변수일 경우 다음과 같이 쓸 수 있다.
profit = 2150.48;
float 변수에 숫자를 할당할때, 다음과 같이 소숫점이 있는 상수에 float을 뜻하는 f를 덧붙이는 것이 좋다.
profit = 2150.48f;
f를 포함하지 않으면 컴파일러에서 경고가 발생할 수도 있다.
일반적으로 int형 변수에는 int형 값이 할당되고, float형 변수에서는 float형 값이 할당된다. 4.2장에서 볼겠지만, 형을 혼합하는 것(예를 들면, float 변수에 int 값을 할당하거나 int 변수에 float값을 할당하는것)은 가능하지만, 안전하지 않다.
변수가 할당되면 다음 변수의 값을 계산하는데 사용할 수 있다.
height = 8;
length = 12;
width = 10;
volume = height * length * width; /* volume is now 960 */
C에서는 곱셈 연산자를 *로 표현한다. 그래서 이 문장은 height, length, width 에 저장된 값을 곱하고, 값을 변수 volume에 저장하는 문장이다. 일반적으로 할당의 오른쪽은 상수, 변수, 연산자를 포함한 수식(C에서는 이를, 표현식이라고 한다)이 될 수 있다.
원어로 읽다보니 헷갈리는 부분이 있었는데, 바로 이 부분이었다. statement와 expression 는 둘 다 코드의 의미로 쓰인다는 느낌이 있었는데 명확하게 하면 다음과 같다. the right side of an assignment can be a formula. (or expression) 에서 볼 수 있듯이, 할당의 오른쪽 부분에 사용될 수 있는 "수식"이 expression이다. statement는 2.3에서 설명이 되었지만, 프로그램이 동작할 수 있는 '명령단위'를 말한다. A statement is a command to be executed when the program runs. 즉, expression은 statement 의 부분집합이라고 볼 수 있다. 또한 expression의 경우 return 이 있어야 하지만, statement의 경우에는 return이 반드시 있어야 하는것은 아니다.
Printing the Value of a Variable
printf를 사용하면 변수의 현재값을 표시할 수 있다. 예를 들어
Height : h
이라고 작성하면 h는 height 변수의 현재 값이고, printf를 통해 다음처럼 불러낼수 있다.
printf("Height: %d\n", height);
%d는 프린트하는 동안 값이 채워질 위치를 표시하는 placeholder(자리표시자)이다. %d 바로 뒤에 있는 \n가 하는 역할은, printf가 height의 값을 출력한 후 다음줄에서 동작하도록 한다.
%d 는 int 변수에 대해서만 작동하며, float 변수를 프린트하려면 %f를 사용한다. 기본적으로 %f는 소숫점 뒤 6자리까지 표시한다. 소숫점 뒤에 p자리까지 표시하도록 하려면 %와 f사이에 .p를 넣어서 다음처럼 출력하면 된다.
Profit: $2150.48
printf("Profit: $%2.f\n", profit);
printf의 호출 한번으로 출력할 수 있는 변수의 개수는 무한대이다. height, length 변수를 모두 표시하기 위해 다음처럼 printf를 호출 할 수 있다.
printf("Height: %d Length: %d\n", height, length);
PROGRAM: Computing the Dimensional Weight of a Box
운송회사들은 부피가 크지만 가벼운 박스들을 좋아하지 않는다. 트럭이나 비행기의 공간을 낭비하기 때문이다 사실, 회사들은 그러한 상자들에 추가요금을 부과한다. 미국에서 주로 쓰는 방법은 부피를 166인치(파운드당 입방 인치 허용)로 나누는 것이다. 상자의 "dimensional", "volumable"한 무게가 "actual"한 무게를 초과하면 추가요금은 "dimensional"한 무게를 기반으로 한다. (166 디바이저는 국제 발송을 위한것이고, 국내 발송의 치수 중량은 194를 기준으로 계산한다.)
우리가 상자의 치수를 계산하는 프로그램을 작성하는 운송회사 직원이라고 가정해보자. C를 시작한 이후로 당신은 처음으로 12''X10''X8''크기의 입방체 박스의 dimensional weight를 계산하는 프로그램을 작성하려고 결심한다. 나눗셈은 C에서는 /(슬래시)로 나타내고, dimensional weight를 나타내려면 다음과 같이 할 수 있을 것이다.
weight = volume / 166;
weight와 volume은 정수변수로, 박스의 무게와 부피를 나타낸다. 안타깝지만, 이 공식은 우리가 필요한 공식과는 다르다. C에서 하나의 정수를 다른 정수로 나누면, 답이 "truncated"된다. (생략되다, 잘리다) 즉, 소수점 뒤의 모든 숫자를 잃게된다. 12''X10''X8''인 박스의 부피는 960 입방인치가 된다. 166으로 나누면 5.783대신 5라는 답이 나오게 되고, 운송회사가 요구하는 반올림이 아닌, 더 낮은 파운드로 내림하게 된다. (운송회사의 입장에서는 더 많은 이익을 추구한다.) 한가지 해결책은 166으로 나누기 전, 165를 더하는 것이다.
weight = (volume + 165) / 166;
166의 부피는 331/166이나 1의 중량을 표시하며, 167의 부피는 332/166이나 2로 산출된다. 이러한 방식으로 무게를 제공하면 다음과 같은 프로그램을 작성할 수 있다.
/* dweight.c
computers the dimensional weight of a 12" x 10" x 8" box */
#include <stdio.h>
int main(void)
{
int height, length, width, volume, weight;
height = 8;
length = 12;
width = 10;
volume = height * length * width;
weight = (volume + 165) / 166;
printf("Dimensions: % dx%dx%d\n", length, width, height);
printf("volume (cubic inches): %d\n", volume);
printf("Dimensional weight (pounds): %d\n", weight);
return 0;
}
결과는 다음과 같이 나온다.
Dimensions: 12x10x8
Volume (cubic inches): 960
Dimensional weight (pounds): 6
Initialization
일부 변수는 프로그램 실행 시작시 자동으로 0으로 설정되지만, 대부분은 그렇지 않다. 기본값이 없고 프로그램에서 아직 값을 할당하지 않은 변수를 초기화되지않은 변수라고 한다.
초기화되지 않은 변수 (예를 들면, 식에서 사용하거나 printf를 사용하기 위해 쓰는 변수) 의 값에 엑세스하려고 시도하면 2568, -30891과 같은 이상한 수가 나오며 예측 불가능한 결과가 발생할 수 있다. 일부 컴파일러에서는 프로그램 충돌과 같은 더 심각한 문제가 생길수도 있다.
물론, 항상 변수를 할당함으로써 초기값을 줄 수 있다. 하지만, 더 변수의 초기값을 선언문에 넣음으로 더 쉽게 할수 있다. 예를 들어 높이변수를 선언하고, 한단계로 초기화할 수 있다.
int height = 8;
C전문용어로는 값 8을 initializer(이니셜라이저)라고 한다.
변수는 모두 동일하게 선언하여 초기화할 수 있다.
int height = 8, length = 12, width = 10;
각 변수에는 자체 이니셜라이저가 필요하다. 다음 예에서 이니셜라이저 10은 초기화되지 않은 상태로 남아있는 height와 length가 아닌 width변수에만 사용된다.
int height, length, width = 10;
Printing Expressions
printf는 변수에 저장된 숫자를 표시할 뿐만 아니라, 숫자 식의 값을 표시할 수 있다. 이 속성을 사용하면 프로그램을 단순화하고 변수 수를 줄일 수 있다.
volume = height * length * width;
printf("%d\n", volume);
예를 들어, 위의 문장은 아래처럼 바뀔수 있다.
printf("%d\n", height * length * width);
표현식을 인쇄하는 printf의 능력은 C의 일반적인 원칙중 하나를 보여준다.
값이 필요한 모든 곳에서 동일한 유형의 식을 사용할 수 있다.