대학교에 다니면서 잠시나마 적었던 C언어 기초 강좌 입니다.
그나마 Pointer는 정성들여 썼길래 이 blog에 옮겨서 적어 놓습니다.
14강 1부 변수와 메모리
조금이나마 C언어책을 훑어본 사람이라면 제목만 읽고서도 짜증이 밀려오기 시작 할꺼다. 나도 처음에 혼자서 C언어를 공부하면서 참
재밌게했던 사람중에 한 사람이다. 하지만 포인터라는 단원을 공부할때 난 처음에 이길이 내길이 아닌 줄 알았다.(^^;) 내 머리의
한계를 느끼기도 하고 내가 이렇게 멍청한가라는 생각도 수 없이 많이 했을 정도로 이단원은이해하기 전에는 참 난해하고 어려운 큰 장벽과 같았다.
우선 어려운 정의를 말하기 전에 사람들이 쉽게 놓치고 있는 메모리와 프로그램에 대해서 알아보도록 하자.
모든 C언어 책 맨 앞에는 컴퓨터 구조와 프로그램이 어떻게 컴퓨터란기계에 실행이 되고 우리가 어떻게 이것을 모니터를 통해서 보고하는지 계략적인 개념이
나와있다. 이것을혹시 무심코 지나왔다면 다시한번 머리속에 생각 하면서 계속 이 글을 읽기 바란다.
아래와 같은 아주 심플한 프로그램이 하나 있다.
#include <stdio.h>
int main()
{
int a1, b1, sum;
a1 = 3;
b1 = 5;
sum = a1 + b1;
printf("sum = %d", sum);
return 1;
}
위 예제는 a1
, b1
이라는 변수에 각각 3, 5라는 숫자값을 저장해서 그합을 sum
이라는 변수에 저장 시키고이 sum
이라는 변수값을 화면
에 출력하는 프로그램 이다. 위프로그램은 지금까지 강좌를 읽어 왔다면 쉽게 머리속으로 충분히 컴파일 하고 실행까지 시킬수 있을 것이다.
그런데 과연 실제 우리가 머리속에서 실행시키는 방법 하고 실제 컴퓨터가 실행시키는 방법하고 똑같을까?
실제 이 프로그램을 실행시 킬때 그 과정을 우리 눈으로 볼수 있을까?
누구나 한번쯤 이런 생각을 가졌을 거라고 생각된다. 아래를 보자. 실제 프로그램이 실행되는 세세한 과정을 눈으로 보여 주겠다.
![c_14_1_1](https://i2.wp.com/scanhand.cafe24.com/wp-content/uploads/2016/07/c_14_1_1.jpg?resize=450%2C427)
지금이 화면은 VC++ 6.0의 디버깅 화면이다. VC++이란실제 우리가 만든 프로그램소스를 실행 파일로 만들어주는 프로그램이라고 생각 하면 쉽다.
지금 이화면에서는크게 프로그램소스를 보여주는곳
, 변수의값을 보여주는곳
, 실제 메모리를 보여주는곳
이렇게 3가지로 나눌수 있다.
프로그램소스를 보여주는 곳
에는 실제 우리가 구현했던 프로그램 소스가보이고, 변수의 값이 보이는곳
의 Name라는 항목에는
우리가 선언한 변수 세개(a1,b1,sum)가보이고 value에는 알수 없는 Error라는 것이 보인다. 지금은 Value에 Error라고표시가 되지
만 조금 후에 실제 각 변수에 들어가 있는 데이터 값이 보이게 된다. 왜 여기서 Error라고 보이는 지는 추 후에 설명하겠다. 마지막으로
실제 메모리를 보여주는 곳
에는 말 그대로 메모리에 저장 되어 있는 값을그대로 보여준다.
우선프로그램소스부분을 보자. 여기서 노란색 화살표는 지금 프로그램이 실행되려고 하는 위치를 뜻한다. 지금 이화면은 프로그램을 시
작하자 마자 멈춰놓은 상태이기에 우리가 배운대로main()이라는 시작위치에서 프로그램이 시작 된다는것을 눈으로 확인 할 수 있다.
![c_14_1_2](https://i0.wp.com/scanhand.cafe24.com/wp-content/uploads/2016/07/c_14_1_2.jpg?resize=580%2C518)
a1, b1, sum 이라는 변수를 선언한 문장까지의 상태다. 우리가 배운대로 a1, b1, sum에는 현재 변수가 선언 되기만 한 상태이기에 각 변
수에는 이상한값(쓰레기값)이 들어있다(-858993460)
![c_14_1_3](https://i2.wp.com/scanhand.cafe24.com/wp-content/uploads/2016/07/c_14_1_3.jpg?resize=580%2C518)
a1 = 3; b1 = 5; 이 두문장을 실행 한 후에 a1이라는 변수에는실제 3이라는 값이, b1이라는 변수에는 실제 5라는 값이 저장되어 있는것을
볼수 있다. sum에는 아직 아무런 값을 저장하지 않은 상태이기에 아무런 변화가 없다. 여기서 지금 화살표 문장을 실행하면 a1+b1이라
는 결과값인 8이라는 값이 sum1에 저장될 것이다. 실제로 그렇게 되는지 보자.
![c_14_1_4](https://i0.wp.com/scanhand.cafe24.com/wp-content/uploads/2016/07/c_14_1_4.jpg?resize=580%2C518)
역시우리 예상대로 sum이라는 곳에 8이라는 값이 저장이 된다. 그럼 당연히 printf()로 출력을 하면 아래와 같은 결과 화면을볼수 있다.
![c_14_1_5](https://i0.wp.com/scanhand.cafe24.com/wp-content/uploads/2016/07/c_14_1_5.jpg?resize=327%2C101)
여기까지 살펴본 결과 우리가 머리속으로 컴파일했던 것과 결과가 일치 한다.
그럼다음으로는 각변수가 실제 메모리상에서 어떻게 저장되는지 눈으로 보도록 하자.
메모리정보를 보기에 앞서 사전에 알고 있어야 할 몇가지를 짚고 넘어가도록 하겠다.
int a1 = 3;
위문장은 a1이라는 int형 변수를 선언하고 그변수에 3이라는 값을 저장한다.
이 말은내부적으로 메모리의 어딘가에 int형의 크기만큼(4byte) 주소를할당하고 그 메모리의 공간에 우리가 접근할수 있도록 이름표를
하나 달았다고 생각하면 쉽다. 말로는 이해 하기 어렵다.
아래 그림을 보자.
![c_14_1_6](https://i1.wp.com/scanhand.cafe24.com/wp-content/uploads/2016/07/c_14_1_6.jpg?resize=338%2C180)
여기서 그 변수의 주소값을 가져오고자 할경우 우리는 변수의 이름앞에 &(주소연산자)를 붙이게 된다.즉 a1이라는것은 3이라는 저장된
값을 의미하지만 &a1이라는 것은 a1의 주소를 뜻하게 된다. 여기서 주소란 실제 메모리의 주소를 뜻한다. 참고로 메모리의 주소는 아래
의 형식으로 표현된다.
0x00200100
0x : 16진수를 의미
00200100 : 실제 메모리 주소
주소 형식을보면 실제메모리 주소는 000000~FFFFFF 까지 표현 할 수 있다는 것을 알수있다.
즉 이론적으로 프로그램에서 사용할 수 있는 메모리가 4Gbyte인 이유가 여기에 있는것이다.
![c_14_1_7](https://i1.wp.com/scanhand.cafe24.com/wp-content/uploads/2016/07/c_14_1_7.jpg?resize=587%2C518)
이전의 실행 했던 프로그램과 동일한 프로그램을 실행시킨 상태이다.단 여기에 기존에는 변수의 값을 보여주는곳
에 &(주소연산자)를
붙여 각 변수의 주소를 볼 수 있도록 하였다.
즉 int형 변수 a1의 주소(&a1)는 0x0012FF7C라는 의미이다. 이것은 다시 반복하면 메모리의 0x0012FF7C 번지에 변수의 데이터값이 들
어가 있다는 것을 뜻한다. 눈치챗듯이 왼쪽 0012FF7C는 메모리의 주소를 그 오른쪽에는 실제 메모리에 저장된 값을 보여주는 것이다.
현재변수 a1의 메모리 주소 0x0012FF7C에는 CC CC CC CC 라는 4byte의 데이터 값이 들어있다. 실제 a1의 데이터 값은
CCCCCCCC를 10진수로 변환한 -858993460이라는 값이 들어있는것이다.변수를 선언한다는 것은 메모리 주소를 할당 받는다는 것을 뜻
한다. 하지만 할당받은 메모리의 안에는 초기화 전까지는 어떠한 값이 들어 있는지를 알수가 없다. 즉 쓰레기 값이 들어 있는 것이다.
a1이라는 변수의 메모리에 CCCCCCCC라는 쓰레기값이 들어 있듯이 말이다.
![c_14_1_8](https://i0.wp.com/scanhand.cafe24.com/wp-content/uploads/2016/07/c_14_1_8.jpg?resize=587%2C518)
다음은 sum = a1+b1; 까지 실행 한 상태이다. 참고로 메모리주소가 보이는곳
에 빨간색 글씨가 보일 것이다. 지금 우리는 메모리의
0x0012FF74번지에 있는 실제 데이터 값을보고 있다. 0x0012FF74는 int형 변수 sum의 주소 이기도 하다. 그렇다면 이 주소에 sum의
데이터 값인 8이라는 값이 들어 있어야 할 것이다. 실제 메모리상에서도 8이라는 값이 들어 있다.(빨간색글씨부분)
즉 0x0012FF74 ~ 0x0012FF77 까지의 총 4byte는 sum의 데이터 값인 8이 저장되어 있다라고 말할 수 있다. 그럼 이것을 응용해서
0x0012FF77의 다음 4Byte의 값을 보자.
05 00 00 00
이렇게 5라는 값이 저장되어있다. 이 4byte의 시작주소 값은 0x0012FF78(0x0012FF77+1) 이다.
5라는 숫자값 우리가 b1이라는 변수에 넣었던 것을 기억 할 것이다. 실제 b1의 주소값은 0x0012FF78 이다.
참고적으로변수의 주소값을 printf()를 이용해서 결과를 보고 싶다면 다음과 같은 방법으로 볼수 있다.
printf("a1의 주소값 = %x, b1의 주소값 = %x, sum의 주소값 = %x", &a1, &b1, &sum);
이 문장에서 %x는 16진수로 출력하는 것을 뜻하고, 각 변수에 주소연산자(&)를 붙여 그 변수의 주소값을 출력하도록하였다.
지금까지 프로그램 실행 중에 변수가 어떻게 변하는지, 실제 메모리에는 어떻게 들어가 있는지 등을 알아보았다. 혹시 포인터를 하는데 이
게 왜 필요한지 묻는 분이있다면, 포인터라는것은결국 변수의값이 아닌 메모리 주소를 이리저리 요긴하게 쓰기 위한 도구라고 생각 하면 수긍할 수 있을 것이다.