1. 주소의 개념


주소는 특정 메모리 위치의 번지이다.


변수에는 값이 저장된다. 이 값은 실제로는 특정 기억장소에 저장된다. 이 특정 기억장소의 주소가 변수 이름으로 표현된 것이다. 따라서 변수 이름은 기억장소 주소에 대한 추상화이다.


변수와 기억장소간의 관계는 2주차 강의 변수 항목에서 자세히 다루었다. 다음은 변수와 기억장소와의 관계를 보여준다.




프로그램에 선언된 각 변수에 대해서 값이 저장될 기억장소가 할당된다. 할당된 기억장소의 크기는 변수의 타입에 따라서 결정된다.


예를 들면, int 타입 변수에 대해서는 4바이트의 기억장소가 할당되고, double 타입 변수에 대해서는 8바이트의 기억장소가 할당될 것이다. 변수에 대해서 할당되는 기억공간의 크기를 알아보기 위해서 2주차 강의의 데이터 유형 단원을 참고하라.


변수에 대해서 할당된 기억공간에서 첫 번째 바이트의 주소를 그 변수의 주소라 한다. 앞서 설명하였듯이, 포인터가 변수의 주소 값을 가질 때, 그 변수를 가리킨다라고 말한다.


예를 들면, 다음의 선언문에서,    

   

int n;


n이 정수 타입이므로, 이 타입의 값을 저장할 수 있는 4개의 바이트가 할당되고, 할당된 기억공간의 첫 번째 바이트 주소가 n의 주소가 된다.




다음은 포인터, 변수, 주소, 기억장소간의 관계를 보여준다.



C 프로그램에서 sizeof 연산자를 사용하여 사용되는 변수에 할당된 기억공간의 크기를 알아낼 수 있다.


sizeof 연산자는 한 개의 피연산자를 갖는다. 이 피연산자는 타입 이름이거나 식일 수 있다. sizeof 연산자 사용을 위한 일반 형식은 다음과 같다.


타입 이름은 괄호로 둘러싸여 표현되는데, 이때 sizeof 연산자는 이 타입의 값을 저장하는데 필요한 기억공간의 크기를 바이트 단위로 계산하여 반환한다. 가령,

    sizeof (int)

int 타입의 값을 저장하는데 필요한 바이트 단위의 기억공간 크기를 반환한다.         



sizeof 연산자의 일반형식에서 살펴보았듯이, 피연산자가 식일 수 있다. 이 경우, 식의 값을 저장하는데 필요한 바이트 단위의 기억공간 크기가 반환된다. 가령,

    sizeof n

은 변수 n과 연관된 기억공간의 크기를 바이트 단위로 계산하여 반환한다.         

다음 프로그램은 sizefo 연산자를 사용하여 타입, 변수, 식에 대한 기억공간의 크기를 알아본다.



위의 프로그램에서 첫 번째와 두 번째 printf(), 세 번째와 네 번째 printf()는 동일한 값을 출력하는 것을 볼 수 있다. 이것은 식 a가 int 타입이고, 식 d가 double 타입이기 때문이다.


마지막 번째 printf()는 a*d의 식의 값은 double 타입이고, 따라서 double 타입의 값을 저장하는데 필요한 기억공간의 바이트 단위 크기 8을 출력할 것이다.





2. 주소의 저장


앞에서 변수, 기억공간, 주소간의 관계를 살펴보았다. C 언어는 변수에 할당된 기억공간의 주소를 알아내고, 이것을 다른 곳에 저장할 수 있는 방법을 제공한다.


변수의 주소를 알아내기 위해서 ‘&’ 연산자가 사용된다. 이 연산자는 변수나 배열과 같이 기억공간의 이름을 피연산자로 갖는다. 이 연산자의 수행 결과는 피연산자의 주소이다.


& 연산자의 사용 형식은 다음과 같다.


        


여기서 n은 변수나 배열 이름이다.


다음은 & 연산자의 사용 예를 기억장소와 연관하여 보여준다.


& 연산자를 사용하여 알아낸 주소는 배정문을 사용하여 다른 변수에 저장할 수 있다. 기억공간의 주소를 저장하는 변수는 반드시 포인터 변수여야 함을 유의하라.


p가 포인터 변수라고 가정할 때, 다음 배정문을 생각해보자.


   

        p = &a;


다음은 위 배정문의 수행 과정을 시각화하여 보여준다.



위 배정문의 수행 결과로, 변수 a의 기억공간 주소가 p에 저장되는 것을 알 수 있다. p도 변수이므로, 기억공간이 할당되고, 이 곳에 a의 주소가 저장된다. 이때 p는 a의 기억공간 주소를 가리킨다.



변수의 주소를 출력제어문자 p를 사용하여 출력할 수 있다. 다음 프로그램은 출력 제어문자 p를 사용하여 변수의 주소를 출력한다.



Visual C++ 프로그래밍 환경에서, 프로그램 11-2를 입력하고 실행시켜보시오.

 



3. 주소의 사용


C 언어는 포인터 변수에 저장된 주소를 사용하기 위해서 간접 참조 연산자 *를 제공한다. 이 연산자는 다음과 같이 포인터 변수 앞에 붙여서 사용된다.


        


여기서 p는 포인터 변수이다. * 연산자는 포인터 타입의 값 즉, 주소 값을 피연산자로 하며, 그 연산 결과는 피연산자의 주소가 가리키는 곳이다.


C 언어에서 데이터를 저장할 수 있는 기억공간을 lvalue라고 부른다. lvalue에서 'l' 이 붙여진 이유는 lvalue가 C의 배정문에서 왼쪽(left)에 올 수 있기 때문이다.


예를 들면, 다음과 같은 배정문에서 단순 변수나 배열의 선택 식은 lvalue이다.



이러한 관점에서 볼 때,  *p의 연산 결과는 p가 가리키고 있는 lvalue이다.




*의 연산 과정을 포인터를 역참조(dereferencing)한다 라고 부른다. 즉, 포인터에 저장해 두었던 주소, lvalue를 다시 참조하는 것으로 생각할 수 있다.


p가 포인터 변수일 때, 다음 상황을 생각해보자.


프로그램의 배정문 수행 결과로, p가 a의 주소 값을 갖게 되고, 따라서 p는 a의 기억공간을 가리킨다.


이때 *p의 연산 결과는 lvalue 즉, a의 참조이다. 따라서 *p는 단순 변수와 마찬가지로 배정문의 왼쪽이나 오른쪽 상에 나타날 수 있다.


*p가 배정문의 오른쪽 편에 나타나는 경우를 살펴보자.



프로그램의 두 번째 배정문의 수행 결과로, p가 가리키는 곳, 즉 a에 저장된 값을 가져와서 b에 저장한다. 따라서 두 번째 배정문은 다음의 배정문과 동일한 수행 효과를 갖는다.


   

      b = a;


이제 *p가 배정문의 왼쪽에 오는 경우를 살펴보자.

 



프로그램의 세 번째 배정문의 수행 결과로, p가 가리키는 곳, 즉 a가 참조되고, 이곳에 20이 배정된다. 따라서 세 번째 배정문은 다음의 배정문과 동일한 수행 효과를 갖는다.


   

      a = 20;


top으로... 다음페이지로.. 이전페이지로.. home으로..