3.5. 기억장소의 종류
기억장소는 변수를 저장하는 방식과 특성에 따라 여러 가지로 구분됩니다.
기억장소(Storage Class)라는 것은 변수나 배열 함수를 메모리의 어디에 저장을 하느냐에 따라서 변수를 나누는 방법입니다. 기억장소를 다른 말로 기억부류라고 말합니다. 요즘은 기억부류라는 말을 더 많이 사용하므로 여기에서도 편의상 기억부류라는 말을 자주 사용하도록 하겠습니다. 더 기억장소는 변수가 프로그램의 전체에서 사용할 수 있느냐 일부 구간에서만 사용할 수 있냐에 따라서 전역 변수(global variable)와 지역 변수(Local variable)로 나누며, 기억장소의 위치(즉 종류)와 기억방식에 따라, 자동변수(auto) 외부변수(extern) 정적변수(static) 레지스터(register) 변수로 나눕니니다.
또한 const라는 기억 부류 지정자를 이용하여 값을 바꿀 수 없는 변수를 만들 수도 있습니다. 다시 말해서 const라는 키워드를 이용하여 정한 변수는 프로그램 내에서 변수의 값을 바꿀 수 없습니다. 따라서 const라는 키워드를 이용할 경우에는 프로그램 안에서 바꾸어서는 안되는 변수에 주로 사용합니다. 예를 들어서 원주율인 파이의 값을 다음과 같이 정의하여 사용하면 프로그램 내에서 PI 변수의 값을 바꿀 수 없습니다. 그러므로 const는 실수로 프로그램 안에서 값을 바꿀 수 있는 경우를 방지하고자 할 때 사용합니다.
보기
const int cdsize=12;
const float PI=3.14159;
3.5.1. 지역변수와 전역변수
지역변수는 하나의 모듈에서만 선언되고 사용하는 변수입니다.
지역변수란 하나의 모듈(module)에서만 선언된 프로그램을 말합니다. 모듈이란 어떤 작업의 단위를 뜻합니다. 예를 들어서 성적관리 프로그램의 경우 점수를 내는 과정, 합계를 내는 과정, 평균 점수를 계산하는 과정, 등수를 매기는 과정으로 구성된다고 합시다. 이때 각 과정은 하나의 단위 즉, 하나의 모듈이 됩니다. 또한 이런 작은 단위의 모듈이 모여 성적관리 프로그램이라는 좀더 큰 단위를 이룹니다. 이처럼 모듈은 크기에는 차이가 있지만 일련의 작업을 수행하는 하나의 단위를 뜻하는 낱말입니다. C언어에서 모듈이라고 하면 하나의 명령어나 함수가 될 수도 있고 하나의 블럭, 또는 소스파일이 될 수도 있습니다.
따라서 하나의 모듈에서만 선언된 변수라는 말은 하나의 함수 안에서 선언된 변수를 말하며, 그 함수를 벗어나면 변수로서의 효력을 상실하는 변수입니다. 하나의 함수는 {}로 둘러싸인 블럭을 가지고 있고, 여기에 함수의 본체에 해당하는 각종 변수를 선언하고 명령문을 넣습니다. 이 블럭 안에서 선언된 변수는 블럭 안에서만 사용할 수 있습니다.
블럭의 안쪽에서 선언된 변수는 블럭의 바깥쪽에는 영향을 미치지 못합니다.
그리고 블럭이 중첩된 경우에는 맨 바깥쪽 블럭에서 선언된 변수는 안쪽의 블럭에도 영향을 미치지만 안쪽의 블럭에서 선언된 변수는 바깥쪽에 영향을 미치지 않습니다. 쉽게 말하면 현재의 블럭에서만 영향을 미친다는 것입니다.
같은 블럭 안에서는 같은 이름의 변수를 사용할 수 없지만 블럭이 다르다면 다른 이름의 변수를 사용할 수 있습니다. 같은 만약 여러 개의 블럭에서 같은 이름의 변수를 선언했다면 당연히 현재의 블럭에서 선언된 변수가 선택됩니다.
때문에 혼동을 피하기 위하여 블럭이 중첩되었을 경우에는 변수이름이 같지 않도록 주의해야 합니다. 특히 바깥쪽 블럭에서 선언한 변수는 안쪽 블럭까지 영향을 미치므로 혼동되지 않도록 주의해야 합니다.
지역변수는 auto라는 키워드를 가지며 키워드는 보통 생략됩니다.
그러나 블럭이 다를 경우에는 변수이름이 같다 해도 큰 지장이 없는데 이처럼 현재의 블럭에서만 통용되는 변수를 지역변수라고 말합니다. 지역변수를 선언하기 위해서는 특별하게 키워드를 사용할 필요가 없습니다. 보통은 auto라는 키워드를 가진 변수가 지역변수에 해당하는데 auto라는 키워드는 생략해도 되기 때문입니다. 즉 변수의 선언 앞에 별다른 키워드가 없다면 C++언어는 auto로 변수를 만들어주는 것입니다.
**요약: 지역변수는 특정 블럭이나 함수, 모듈 안에서만 사용할 수 있는 변수를 말하면 자동변수는 지역변수에 해당합니다. 블럭 안에서 선언된 변수는 블럭 바깥 쪽에 영향을 미치지 못하지만 블럭 바깥에서 선언된 변수는 블럭 안쪽에 영향을 미칠 수 있음에 주의
해야 합니다.
전역변수는 프로그램 전체에서 사용가능한 변수입니다.
지역변수가 일부 블럭에서만 사용할 수 있는 변수라면 전역변수는 지역변수보다 훨씬 넓은 지역에서 사용하는 변수를 말합니다. 즉 프로그램 전체에 걸쳐서 사용할 수 있는 변수입니다. 때문에 전역변수는 프로그램 첫부분에서 선언합니다.
보기
#include <라이브러리 파일>
전역 변수의 선언;
main()
...
전역 변수는 모든 함수에서 사용할 수 있습니다. 따라서 프로그램 안의 어떤 함수에서 값을 바꾸더라도 전역 변수의 값이 바뀝니다. 즉 모든 함수가 사용할 수 있는 변수가 되는 겁니다. 그렇기 때문에 변수의 값이 변화되는 과정을 잘 추적해나가야 합니다.
전역변수를 사용하기 위해서는 변수의 선언문 앞에 extern이라는 키워드를 써주면 됩니다. 또는 모든 프로그램의 블럭 밖에서 선언해줍니다.
사용형식
extern 자료형 변수이름;
extern이라는 명령은 생략할 수는 있지만 가능한 써주는 것이 좋습니다.
extern은 external이라는 뜻으로 외부에서 선언된 변수임을 나타내는 예약어입니다. extern은 함수의 앞에서 선언된 경우에는 생략할 수 있습니다. 그러나 함수가 main() 앞에 오는 경우라면 반드시 기술해야 하므로 가능하면 생략하지 않는 것이 좋습니다.
그리고 가능하면 전역변수보다는 지역변수나 auto변수를 사용하도록 권장합니다. 그래야만 C++언어의 장점인 모듈화가 가능해지기 때문입니다.
**요약: 전역변수란 프로그램 전체에서 사용할 수 있는 변수를 말합니다. extern이라는 키워드는 생략 가능하지만 프로그램의 안정성을 위하여 써주는 것이 좋습니다.
3.5.2. 기억장소의 선언방법
변수는 기억장소의 종류와 방법에 따라서 네 가지로 분류합니다.
그럼 기억장소의 종류와 기억방법에 따른 네 가지 변수의 분류방법도 살펴보겠습니다. 변수는 auto변수를 제외하고는 변수를 선언할 때 키워드를 써주는 것으로 기억장소를 선택할 수 있습니다. 즉 auto 키워드는 생략이 가능합니다. 그러나 static과 register 키워드는 생략할 수 없습니다. extern 키워드는 함수의 앞에서 사용할 경우에는 생략할 수도 있습니다. 단 extern 키워드는 변수의 선언에만 사용합니다.
일반적인 함수는 기억장소로 따지자면 원래 외부형입니다. 때문에 함수를 정의할 때 함수형 앞에 static을 덧붙여서 그 함수를 정적함수로 만들 수 있습니다.
함수는 외부함수와 정적함수의 두 가지 부류밖에 없지만 변수는 다양한 종류가 있습니다. 변수는 여러가지 기억부류를 조합해서 사용할 수 있기 때문입니다. 그러니까 여러 가지 기억부류 관련 키워드를 조합해서 사용할 수 있다는 뜻입니다.
보기
int n; // 외부변수 a의 선언.
extern int a; // 외부변수 b의 선언
static int i; // 외부정적변수 c의 선언
void main(void)
{
int m; // 자동변수 m의 선언
auto int b; // 자동변수 b의 선언
static int j; // 정적변수 j의 선언
register int r; // 레지스터변수 r의 선언
......
}
표: 네 가지 기억부류와 해당 기억부류 지정자
기억부류지정자
변수
함수
auto
extern
static
register
자동변수
외부변수
정적변수
레지스터변수
.
(외부)함수
정적함수
.
변수는 가능한 자동변수를 사용하는 것이 좋습니다.
기억부류의 종류가 많기 때문에 아마 어떤 기억부류를 선택해야 할 지 고민이 될 겁니다. 어렵게 생각하실 필요가 없습니다. 변수나 함수를 사용하다보면 자동적으로 기억부류의 선택기준을 스스로 판단할 수 있기 때문입니다. 일단은 모든 변수는 자동변수를 이용하는 것이 좋다고 생각하고 있으면 됩니다. 즉 가능하면 늘 자동변수를 이용하는 것이 좋습니다. 만약 자동변수의 값을 함수의 실행이 끝난 뒤에도 계속해서 보존할 필요가 있을 경우에는 내부정적변수로 정의해서 사용하면 됩니다.
외부변수를 사용할 때는 꼭 초기화를 해두어야 합니다.
외부변수는 가능하면 사용하지 않는 것이 좋습니다. 그러나 모든 함수에서 사용해야 할 변수가 생기는데 이때는 외부 변수를 사용해야겠죠. 그리고 모든 외부변수는 가능하면 초기화를 해두어야 합니다. 안그러면 쓰레기값을 가질 수 있기 때문입니다.
배열도 가능하면 자동배열로 사용해야 합니다. 단 초기화가 꼭 필요하거나 공용성을 가지는 배열을 사용해야 할 때는 주로 외부형으로 사용합니다.
그리고 함수의 형식매개변수(즉 인수)는 기억부류로 따지자면 자동변수에 해당되며, 상수 중에서 문자열 상수는 정적상수에 해당하는 것으로 알고 있으면 됩니다.
물론 이럼 기억부류를 사용할 때도 일정한 규칙을 따라야 합니다.
표: 기억부류의 사용규칙
자동변수이름은 선언 또는 정의된 블럭이나 함수 안에 하나뿐이어야 합니다.
외부변수이름은 프로그램 전체에 걸쳐서 하나뿐이어야 합니다.
내부정적변수이름은 선언 정의된 블력이나 함수 안에 하나뿐이어야 합니다.
함수이름은 프로그램 전체에 걸쳐 하나뿐이어야 합니다.
정적함수이름은 정의된 모듈 안에서 하나뿐이어야 합니다.
3.5.3. 자동변수
자동변수는 함수 내부에서만 사용되며 자동으로 생성 소멸됩니다.
자동변수는 말할 것도 없이 가장 많이 사용하는 변수입니다. 그리고 가능하면 자동변수를 가장 많이 사용해야 합니다. 자동변수는 함수 내부의 선언을 하고, 선언된 함수 내부에서만 사용이 가능합니다. 따라서 함수가 실행됨과 동시에 생성되며, 함수의 종료와 동시에 자동으로 사라지는 변수입니다. 함수가 종료되면서 자동으로 소멸되므로 메모리를 차지하지 않습니다. 그래서 메모리의 효과적인 관리를 위해서도 자동변수는 매우 유용합니다.
만약 변수의 선언 때 기억부류 지정자를 생략할 경우에는 자동변수가 자동으로 생성되며 함수의 실행이 끝나면서 자동변수도 소멸됩니다.
자동변수는 함수 실행 때마다 쓰레기값을 가지며 생성되므로 매번 초기화해주어야 합니다.
자동변수는 함수가 실행될 때마다 매번 새롭게 초기화되는데 생성될 때 불확실한 쓰레기 값을 가지고 만들어집니다. 때문에 한 번은 초기화를 시켜주어서 쓰레기 값을 제거해야 합니다. 이때 말하는 쓰레기값이란 아무나 버리는 쓰레기처럼 어떤 값이 들어있는지 모른다는 소리입니다.
따라서 어떤 값이 들어있는지도 모른 상태에서 이 변수를 사용해서는 안됩니다. 자동변수를 초기화하지 않은 상태에서 자동변수를 어떤 수와 비교하는 행위는 하면 안됩니다. 초기화되지 않은 변수를 사용하는 것은 뜻하지 않은 결과를 초래합니다.
자동변수는 자동으로 생성되고 소멸되기 때문에 동적스택에 만들어지고 저장됩니다.
**요약: 기억부류 지정자를 생략하면 자동변수가 만들어집니다. 자동변수는 함수 내부에서만 사용가능하며 자동으로 생성소멸됩니다. 생성시에는 쓰레기값이 대입되므로 자동변수는 사용 전에 반드시 한 번은 초기화해주어야 합니다. 자동변수는 동적인 스택에 저장
됩니다.
3.5.4. 외부변수
외부변수를 함수 외부에서 선언하며 프로그램 전체에서 사용가능합니다.
외부변수는 프로그램 전체에서 사용가능한 변수를 말합니다. 외부변수를 선언하는 이유는 분할별로 컴파일할 수 있도록 하기 위함입니다. 외부 변수는 extern이라는 명령어를 앞에 붙여주고 선언합니다. 변수가 아닌 배열의 경우에는 그 크기를 생략할 수 있습니다. 외부변수를 정의하는 방법은 자동변수를 선언하는 방법과 같으며 단지 선언하는 위치가 함수 함수 내부가 아니고 함수 외부라는 점이 다릅니다.
보기
int func(int x); // 함수를 선언했습니다다
......
int n; // 여기에서 외부변수를 선언했습니다. n이라는 변수는
// 이후에 나오는 모든 함수에서 사용할 수 있습니다.
void main(void)
{
......
}
int second; // 외부변수를 선언했습니다. 이후의 모든 함수에서는
// 사용할 수 있으나 먼저 나온 main 함수에서는 사용할 수 없습니다.
int func(int x)
{
...
}
외부변수는 프로그램 전체에서 사용이 가능하지만 선언한 이후에 나오는 함수에서만 사용이 가능합니다.
외부변수를 선언하면 선언한 이후에 나오는 함수에서는 외부변수를 참조할 수 있으나 그 이전에 나온 함수에서는 참조할 수 없으므로 외부변수는 파일의 앞부분에서 선언하는 것이 좋습니다.
외부변수는 프로그램이 실행되는 동안 계속 존재, 유지되며 프로그램이 실행될 때 단 한번 초기화됩니다. 그리고 모두 0으로 자동 초기화되며 정적 데이터 영역에 저장됩니다. 외부변수는 프로그램이 끝날 때 같이 종료됩니다.
외부변수는 모듈별 분할 컴파일을 위해 사용합니다.
외부변수는 모듈별 분할 컴파일을 위하여 사용하는 변수입니다. 이미 목적파일과 라이브러리를 설명할 때 모듈별 분할컴파일의 장점을 말씀드렸지만 다시 한 번 말씀드리겠습니다.
예를 들어서 만 줄 정도 되는 프로그램을 짠다고 합시다. 이 경우 한 줄을 고치고도 만 줄을 다시 컴파일 하려면 꽤나 많은 시간이 소모될 겁니다. 그러나 이중에서 현재 개발중인 함수가 100줄 정도라면 이 100줄만 떼어내서 컴파일을 하는 것이 분할 컴파일이고, 100줄 정도만 떼어내서 컴파일하므로 컴파일 시간이 100분의 1로 줄어들 겁니다. 물론 라이브러리 파일을 찾고 항상 하는 기본적인 동작이 있기 때문에 프로그램의 길이가 100분의 일로 줄었다고 해서 컴파일시간까지 정확하게 100분의 일로 줄어들지는 않지만 만 줄 짜리를 컴파일할 때와 비교하면 엄청나게 시간이 줍니다. 이런 이유로 프로그램을 짤 때는 여러 개의 소스파일로 나누어서 프로그램을 짜고, 모듈별로 컴파일을 합니다. 그리고 링크과정을 거쳐서 이를 합칩니다. 이런 모듈컴파일 방법은 프로그램의 컴파일 시간을 획기적으로 줄여줄 뿐만 아니라 강력한 기능의 라이브러리와 함수의 출현을 가능하게 만듭니다.
C는 원래부터 모듈별 분할 컴파일을 지원해오던 언어입니다. 모듈별로 프로그램을 짜므로 프로그램에 에러가 생겼을 경우에도 전체프로그램을 다시 컴파일 하는 것이 아니라 에러가 난 모듈만 컴파일하면 됩니다. 프로그램의 벌레를 잡는데도 매우 유리한 것입니다.
그러나 이렇게 모듈별로 컴파일 할 경우에는 모듈간에 사용할 변수에 대한 정보교환이 필요해집니다. 즉 각각의 모듈이 사용할 변수에 대한 정보를 각각의 모듈에게 알려주어야 합니다. 이를 위해서 외부변수를 사용하는 겁니다.
변수의 선언부분만 모아서 헤더파일로 만들어놓으면 사용이 편리합니다.
그런데 외부변수의 종류가 많을 경우에는 각 모듈마다 변수를 선언해주는 일이 어렵습니다. 예를 들어서 어떤 모듈에서 man이라는 외부변수를 정의했다면 나머지 모듈에서도 man이라는 외부변수를 선언해주어야 합니다. 그런데 man을 woman으로 바꾸었을 경우에는 다른 모듈을 저장한 소스파일을 전부 찾아서 man 변수의 선언문을 woman 변수의 선언문으로 고쳐야 합니다. 만약 고쳐야 할 변수가 100쯤 되고 모듈이 100개쯤 된다면 100개나 되는 파일을 찾아서 100개나 되는 변수이름을 일일이 고쳐야 합니다.
이런 일은 매우 번거로우므로 이럴 때는 헤더파일을 이용합니다. 즉 변수의 선언부분만 모아서 헤더파일로 만든 뒤에 각각의 모듈에는 헤더파일만 포함시켜 놓습니다. 이렇게 하면 헤더파일의 변수선언문을 고치는 것으로 100개의 모듈파일에 자동적으로 변경된 변수이름이 새롭게 선언되는 것입니다.
**요약:
외부변수는 함수 외부의 아무 곳에서나 선언할 수 있으며 프로그램 전체에 걸쳐 모든 함수 안에서 사용이 가능하지만 선언이 된 이후의 함수에서만 사용이 가능합니다. 외부변수는 프로그램이 실행되면서 모두 0으로 자동 초기화 됩니다. 프로그램이 실행되는 동안
외부변수도 존재하며 프로그램의 종료와 함께 소멸됩니다. 외부변수는 정적 데이터 영역에 저장됩니다.
3.5.5. 내부정적변수
내부정적변수는 함수 내부에서 선언되지만 함수 종료 후에도 소멸되지 않습니다.
내부정적변수는 함수 내부에서 선언되는 정적변수라는 특성을 가지고 있습니다. static 이라는 키워드에 의에 선언되는데 함수 내부에서 선언되었지만 함수 종료 후에도 소멸되지 않고 그 값이 남아있는다는 점이 다릅니다. 따라서 내부정적변수는 변수가 소멸되지 않고 계속 남아있어야 할 때 사용합니다.
내부정적변수는 함수 내부에서 선언하므로 선언된 함수 내부에서만 사용 가능합니다. 그러나 프로그램이 실행되는 동안 존재합니다. 내부정적변수는 프로그램이 실행됨과 동시에 단 한 번만 초기화되는데 초기값을 주지 않으면, 모두 0 으로 초기화됩니다. 변수는 정적 데이터 영역에 저장됩니다.
내부정적변수를 사용할 때는 함수 안에서 static라는 키워드를 붙여서 변수를 선언해주면 됩니다. 사용형식은 다음과 같습니다.
사용형식
static 자료형이름 변수명1, 변수명2, ......;
보기
static int n=1;
static double a[3];
**요약:
내부정적변수는 함수 내부에서 선언하며, 선언된 함수 내부에서만 사용 가능합니다. 그러나 프로그램이 실행되는 동안 존재하며, 프로그램이 종료되면서 소멸됩니다. 프로그램이 실행됨과 동시에 단 한 번만 초기화되는데 초기값을 주지 않으면, 모두 0 으로 초기화
됩니다. 정적 데이터 영역에 저장됩니다.
3.5.6. 외부정적변수
외부정적변수는 다른 소스파일에서는 참고할 수 없는 외부변수입니다.
외부정적변수는 외부변수와 같으나 자신이 속한 모듈에서만 사용할 수 있다는 점이 다릅니다. 즉 다른 소스파일에서는 참고할 수 없다는 점이 다릅니다. 따라서 외부정적함수는 특정 모듈에서만 사용가능한 외부변수인 셈입니다. 외부정적변수는 함수 외부에서 선언되며, static 키워드를 사용합니다.
사용형식
static 자료형 변수명1, 변수명2, ......;
보기
static int n = 1;
static int x[3];
main() {
...
}
보기를 통해 알 수 있는 것처럼 내부정적변수와 선언방법은 내부정적변수와 같으나 다만 선언하는 위치가 다릅니다. 따라서 정적변수가 함수 내부에서 선언되면 내부정적변수이고 함수 외부에서 선언되면 외부정적변수입니다.
**요약: 정적변수가 함수 외부에서 선언된 것이 외부정적변수인데 다른 소스파일에서는 참고할 수 없는 외부변수입니다. 즉 선언된 모듈에서만 사용이 가능한 외부변수입니다.
3.5.7. 정적함수
정적함수는 다른 소스파일에서 사용할 수 없는 함수입니다.
정적함수는 함수라는 점만 다를 뿐 외부정적변수와 성질은 같습니다. 즉 어떤 함수를 특정 모듈(소스파일) 안에서만 사용하고 다른 모듈(소스파일)에서는 사용하지 않을 때 정적함수로 정의합니다. 그러므로 다른 모듈에서는 사용해서는 안되는 함수를 만들 때 정적함수로 정의합니다.
선언 형식
static 함수형 함수명(매개변수 리스트);
정의 형식
static 함수형 함수명(매개변수 리스트)
{
...
}
정적함수는 함수이므로 함수의 선언 뒤에 정의가 따라야 합니다. 물론 정적함수의 선언은 그 모듈의 앞부분에서 행하는 것이 가장 바람직합니다.
**요약: 정적함수는 특정한 모듈에서만 참고하는 함수를 만들 때 사용합니다. 따라서 다른 소스파일에서는 사용할 수 없는 함수입니다.
3.5.8. 레지스터변수
레지스터변수는 변수를 메모리가 아닌 레지스터에 저장한다는 점이 특징입니다.
레지스터변수는 메모리에 변수를 저장하지 않고 CPU에 여분으로 남아 있는 레지스터라는 곳을 이용한다는 점이 다릅니다. 따라서 다른 변수와는 달리 매우 빠른 연산을 할 수 있습니다. 따라서 빠른 계산을 필요로 하는 변수를 사용할 때 많이 사용하는데, 레지스터의 갯수가 한정되어 있고 비어있는 레지스터가 있어야 사용할 수 있다는 점 때문에 레지스터 변수는 프로그램 전체에서 몇 개 사용할 수 없습니다.
레지스터변수를 선언했는데 사용가능한 레지스터가 없으면 자동변수로 변환됩니다.
또한 레지스터 변수는 CPU를 사용하는 변수이므로 메모리상의 주소를 알려주는 번지연산자 &를 사용해서는 안됩니다. 레지스터 변수로 선언했는데 사용 가능한 레지스터가 없다면 자동 변수로 변환되어 선언됩니다.
**요약: 자동변수나 함수의 형식매개변수만 레지스터변수로 선언할 수 있습니다. 레지스터변수의 자료형으로 2바이트 크기의 자료형만 사용할 수 있습니다. 예를 들면 정수형이 속합니다. 레지스터변수는 메모리에 저장되는 것이 아니라 레지스터에 저장되므로 번지
연산자 &를 사용해서는 안됩니다.
표: 변수의 기억장소와 종류
-------------------------------------------------------------------
기억부류 변수 저장 장소 지정자(키워드) 사용범위
------------------------------------------------------------------
자동변수 스택 없음 또는 auto 지역변수
내부정적변수 정적 테이터 영역 static 지역변수
외부변수 정적 데이터 영역 없음 전역변수
외부정적변수 정적 데이터 영역 static 전역변수
레지스터변수 레지스터 SI와 DI register 지역변수
-------------------------------------------------------------------
레지스터변수를 사용해 제곱수를 구하는 프로그램을 만들어봅시다.
아래의 내용을 test021.cpp로 만들어서 실행해보기 바랍니다.
// test021.cpp
// 레지스터 변수를 사용하는 예제
#include
#include
int jegob(int a,int b); // 사용자정의 함수인 jegob()을 선언함
void main(void)
{
int a=0, b=0;
cout<<"원하는 수는: ";
cin>>a; // 첫번째 수를 입력받음
cout<<"몇 제곱을 계산합니까: ";
cin>>b; // 두번째 수를 입력받음
if (b<=0) return; // 입력된 수가 0보다 작으면 계산이 안되므로 끝냄
jegob(a,b); // 사용자정의 함수인 jegob()을 호출해 실행함
}
int jegob(int a,int b) // 사용자정의 함수인 jegob()의 정의 부분
{
register int n; // 레지스터 변수로 n을 선언
long c=1;
for (n = 1;n<=b;n++) {
c*=a; // 이전의 c가 가진 값에 a를 곱한 값을 다시 c에 대입함
printf(" %d의 %d제곱은 %d입니다. \n", a,n,c);
}
return 0; // 0을 값으로 돌려줌
}
**그림: test021.cpp의 소스파일 내용
보기의 프로그램은 두 개의 수를 입력받아서 n 제곱을 구하는 함수입니다. test021.exe를 실행시키면 다음과 같이 '원하는 수는:'이라는 문장이 나오고 커서가 깜박입니다. 여기에서 제곱을 구하려는 수를 입력합니다.
보기와 같이 3을 입력했습니다.
**그림: 원하는 수를 물을 때 3을 입력합니다.
이번에는 '몇 제곱을 계산합니까:'라는 문장이 나타납니다. 여기에서는 지수에 해당하는 수를 적어줍니다.
보기 화면에서는 3을 입력했습니다. 즉 3을 세 번 곱하고 싶다는 뜻입니다.
**그림: 제곱할 수(지수)로 3을 입력합니다.
그러면 아래 화면과 같이 3의 1제곱부터 3제곱까지 곱해서 그 결과를 화면으로 보여줍니다.
**그림: 3의 3제곱까지 계산과정을 보여줍니다.
창을 닫고 다시 한 번 test021.exe를 실행시킵니다. 이번에는 원하는 수로 2를 입력하고 제곱할 지수로 8을 입력합니다. 그러면 다음 화면처럼 2의 8제곱까지 계산하여 그 결과를 화면으로 보여줍니다.
**그림: 2의 8제곱을 계산하여 보여주는 화면
test021.exe는 이처럼 제곱수를 쉽게 구해줍니다. 이 프로그램의 논리구조를 살펴봅시다. 먼저 a라는 수를 입력받습니다. 그리고 b라는 변수에 두번째 입력받은 수를 대입합니다. 그리고 jegob()라는 함수에 a, b 두 개의 수를 인수로 대입합니다. jegob()라는 함수는 두 수를 받은 뒤에 b번 동안 a을 곱하는 과정을 반복합니다.
반복을 위한 변수인 n으로 레지스터 변수를 사용했다는 점만 제외하면 특별하게 다른 점이 없습니다. 예제프로그램을 잘 분석해보면 어지간한 수학 함수는 손쉽게 만들 수 있을 겁니다. 위의 예제에서 숫자를 입력받는 부분과 사용자정의함수를 만들어서 제곱수를 구하는 과정을 잘 기억해두시기 바랍니다.
test021.exe는 2의 20제곱을 정확하게 계산하지 못합니다.
이 test021.exe의 경우 계산결과를 저장하는 변수인 c로 long형 변수를 사용했습니다. long형은 32비트로 저장되는 정수형 변수이기 때문에 다룰 수 있는 숫자의 범위가 -2147483648 ~ 2147483647까지입니다. 그러므로 2의 16제곱인 65536이라는 숫자를 결과값으로 출력할 수 있다는 예상을 할 수 있습니다. 그러나 test021.exe를 실행시켜보면 예상했던 것과 다른 결과가 나옵니다.
예를 들어서 test021.exe를 실행시킨 후에 2의 20제곱을 계산해보기 바랍니다. 그러면 다음처럼 2의 15제곱은 엉뚱하게도 음수로 표현되고 16제곱부터는 계산 자체가 안됩니다.
**그림: 2의 15제곱부터는 계산이 엉뚱하게 나옵니다.
변수는 출력과정까지 일관된 자료형을 유지해야 예상했던 계산결과를 얻을 수 있습니다.
왜 이런 엉뚱한 결과가 나온 것일까요? 이렇게 된 까닭은 printf() 함수에 사용된 문장이 잘못되었기 때문입니다. 'printf(" %d의 %d제곱은 %d입니다. \n", a,n,c);'라는 명령문의 세번째 %d를 고쳐야 합니다. %d는 정수형만 받을 수 있습니다. 따라서 %d를 %ld로 바꾸어야만 long형 자료를 받아서 출력할 수 있습니다.
그러므로 이 부분만 %ld로 바꾸면 2의 20제곱이 제대로 계산되어 나옵니다. test021.cpp의 printf() 함수에서 세번째 %d만 %ld로 바꾸어 test0212.cpp로 저장한 후 실행하기 바랍니다.
// test0212.cpp
// 레지스터 변수를 사용하는 예제
#include
#include
int jegob(int a,int b); // 사용자정의 함수인 jegob()을 선언함
void main(void)
{
int a=0, b=0;
cout<<"원하는 수는: ";
cin>>a; // 첫번째 수를 입력받음
cout<<"몇 제곱을 계산합니까: ";
cin>>b; // 두번째 수를 입력받음
if (b<=0) return; // 입력된 수가 0보다 작으면 계산이 안되므로 끝냄
jegob(a,b); // 사용자정의 함수인 jegob()을 호출해 실행함
}
int jegob(int a,int b) // 사용자정의 함수인 jegob()의 정의 부분
{
register int n; // 레지스터 변수로 n을 선언
long c=1; // long형 변수인 c를 선언
for (n = 1;n<=b;n++) {
c*=a;
printf(" %d의 %d제곱은 %ld입니다. \n", a,n,c); // 세번째 %d를 %ld로 고침
}
return 0;
}
**그림: test0212.cpp의 소스파일 내용. 세번째 %d를 %ld로 고쳤습니다.
test0212.exe를 실행시키면 다음과 같이 2의 20제곱도 정확하게 화면에 출력됩니다. 이처럼 자료형은 선언과 정의만 제대로 했다고 계산결과가 정확하게 나오는 것이 아닙니다. 출력이나 값을 돌려주는 각종 과정에서도 정확한 자료형을 써야만 예상했던 계산결과를 얻을 수 있음을 유념해야 합니다.
**그림: test0212.exe는 2의 20제곱을 제대로 계산해 출력해줍니다.