소프트웨어/C 언어

[C언어]29. 메모리를 직접 관리하는, 포인터에 대하여 알아보자 ( 포인터 변수 )

리습 2013. 7. 10. 15:06


 안녕하십니까. 리습입니다.


 포인터는 메모리를 직접 제어할 수 있는 방법이며 그 방법으로써 포인터 변수를 언급했습니다. 이번시간엔 포인터 변수에 대해서 자세히 알아보도록 하겠습니다.


 포인터 변수와 타입 

 

포인터 변수는 메모리 주소를 저장할 수 있는 '특별한'변수입니다. 변수이므로 마찬가지로 메모리 공간을 차지하죠. (32bit 운영체제를 기준으로 4byte를 차지합니다. 64bit의 운영체제 라면 8byte 를 차지) 그리고 일반적인 변수와 마찬가지로 타입(형식)을 가지고있습니다. 하지만 포인터 변수에서의 타입은 일반적인 변수의 타입과 의미가 다릅니다. 일반적인 변수의 타입이 '저장하는 데이터 타입과 크기를 지정' 해주는 것이였다면 포인터 변수에서의 타입은 '가리키고 있는 메모리 공간에 저장되어있는 데이터의 타입을 미리 표시해놓은 것' 입니다. 


 미리 표시한다는게 잘 이해가 안되실 겁니다. 그런데 이렇게 생각을 해봅시다. 변수의 종류에 따라 각 변수는 각기 다른 메모리 공간을 점유하고 있습니다. 어떤 변수는 1byte, 어떤 변수는 4byte, 또 어떤 변수는 수십byte의 메모리공간을 점유하고 있겠죠. 이렇게 각각의 데이터는 다른 크기를 가지고 있으며, 포인터 변수는 단순히 특정 메모리 주소만을 저장하는 것이 아닌 메모리 공간에 접근하여 값을 읽어내는 기능 또한 가지고 있기 때문에 어느정도의 크기만큼 변수값을 읽어내야 하는지 미리 알려줘야 하는 것입니다.(연산자를 통해서 메모리 주소에서 값을 읽어 낼수 있습니다.) 그리고 포인터의 타입은 단지 '알려주는것 뿐'이기 때문에 실제 메모리 공간에 저장되어있는 데이터 타입과 일치할 필요가 없습니다. 몇몇 C언어에 대한 책에서는 특정 변수의 메모리 주소를 저장하려면 포인터 변수의 타입과 변수의 타입과 일치해야 한다 라고 하지만 꼭 그럴 필요가 없다는 것입니다. 

(포인터에 좀 익숙해 진다면 한번 해보도록 하겠습니다.)

포인터 변수의 선언 


 읽어낼 포인터 형식, * , 이름 이 세가지를 가지고 포인터 변수를 만들게 됩니다. 일반적인 변수 선언과 같습니다. 단 형식과 이름 사이에 * 이 들어간다는 것이 다를 뿐이죠. *는 이것이 포인터 변수다. 라고 알려주는 기호와도 같습니다. 예를 들어 1byte의 크기에 접근하는 포인터 변수는 char *ptr 과 같이 작성해주면 되는 것입니다. 


 포인터 변수를 선언하면서 *의 위치에 대해서 고민을 많이 하시는데 위치 자체는 상관이 없습니다. 


①char *ptr ② char* ptr ③ char * ptr ④ char*ptr


모두 사용 가능합니다. 굳이 분류하자면 1번은 ptr 이 포인터 변수이다. 라는 것을 강조한 것이며 2번은 char타입의 포인터 변수를 선언한다. 라는 것을 강조한것이고 3번과 4번은 그냥 자유롭게 작성한 것입니다. 자유롭게 작성하셔도 괜찮지만 가능하면 1번 방식을 선언합니다. 코드는 가독성이 매우 중요하며 1번 형식으로 해야 여러개의 포인터 변수를 선언할때 햇갈리지 않기 때문입니다. 한번에 여러개의 포인터 변수를 선언하려면

 ①char *ptr1, *ptr2 (O) - 두개의 포인터 변수 ptr1 , ptr2

 ②char* ptr1, ptr2   (X) - 한개의 포인터 변수 ptr1 , 한개의 일반 변수 ptr2

1번의 방법으로 선언하셔야 합니다.  


 포인터와 관련된 연산자 


 포인터와 관련된 연산자를 몇가지 알아보도록 하겠습니다. 


 1. & : 특정한 변수의 메모리 주소를 계산하는 연산자입니다. 예를들어 &name 이라고 작성한다면 name 이라는 변수가 존재하는 메모리상의 주소를 계산하여 줍니다. 포인터 변수와 함께 사용한다면 특정 변수의 주소를 포인터 변수에 쉽게 넣어줄 수 있습니다. 참고로 scanf 에서 사용하는 & 연산자가 메모리 주소를 계산하는 연산자 입니다. 

 ex : char *ptr = &name //ptr포인터 변수에 name의 주소를 저장하여라.


2. * : 포인터 변수에 저장되어 있는 값을 읽어오는 연산자 입니다. 또한 *연산자는 포인터 변수의 형식으로 데이터를 읽습니다. 예를들어 char 타입의 포인터 변수 ptr 에 연산자 * 를 사용하여 *ptr 이라고 작성한다면 ptr 의 메모리 주소로가서 char 형식으로 데이터를 읽어라 라는 의미를 가지게 되는 것입니다.  *모양의 경우 곱하기를 할때에도, 포인터를 나타낼때도, 포인터 변수에서값을 읽을때에도 사용하지만 각각은 모양만 같고 다른 연산자임을 잘 기억하시기바랍니다. 마치 동음이의어 같은 것이지요.

우선은 기본적인 포인터 연산자 두가지만 알아보고 나머지는 개념을 확장시켜가면서 같이 알아보도록 하겠습니다.


 포인터 변수와 연산자 모두 알아보았으니 이제 한번 예제를 만들어 보도록 하겠습니다. 


  코드

 #include <stdio.h>

 int main( void )

 {

       char a = 'a';

       char *ptr = &a; /* ptr에 a의 주소를 넣어줌*/

       printf("포인터 ptr 내부의 값은 %c 입니다. \n", *ptr);/* ptr에 *연산자를 이용 값을 넣음 */

       return 0;

 }

  결과

  포인터 ptr 내부의 값은 a 입니다. 


 포인터가 무엇인지 만을 알아보기위한 간단한 예제입니다. 단지 포인터 변수에 다른 변수의 주소를 넣어주고 포인터 변수를 이용해서 값을 출력해 준것입니다. 이 예제로는 포인터의 역활을 정확하게 보여줄순 없지만 포인터를 어떻게 사용하는지 감은 잡으실 수 있으실 겁니다.


 지금까지 포인터를 선언하고 사용하는 법을 알아보았습니다. 포인터는 약간 생소한 개념이기도 하고 굳이 왜 존재할까 부터 시작해서 필요없을 것 같다 라고 생각하실 수도 있습니다. 하지만 아직 처음이다 라고 생각하시고 차근차근 잘 이해하시기 바랍니다.