지나간 삶 ::

'포인터'에 해당되는 글 2건

  1. 2007/03/27 3.27(화) 포인터배열 && 배열포인터
  2. 2007/03/25 3.25(일) void형 포인터에 대해서..

'배열 포인터' 왠지 포인터 배열을 떠오르지만 2007/03/22 - [Study] - 이차원배열과 포인터 익히기(참고) type(*변수)[]type*변수[x] 를 확연히 구분 짓는 ( ) 괄호를 생각해보면 쉽게 구분 짓을 수 있다.

1. type*변수[]

이 선언문에 사용된 *와 []는 둘 다 구두점이다. *가 앞쪽에 있으므로 변수는 먼저 정수형 포인터가 되고 다음으로 []에 의해 그런 포인터 변수 5개를 모아 배열을 선언하게 된다. 즉, 포인터배열은 포인터 타입의 모임을 정의한 것이라 할 수 있다. 이것의 쓰임새를 살펴보면  

사용자 삽입 이미지



*메모리를 아껴쓰기 위해 태어난 포인터라 생각해도 좋을 것이다. 2차원 배열을 쓴다면 행*열*타입 으로 메모리를
차지하는 byte를 계산 하겠지만 포인터배열에서는 행은 똑같지만 열에서 큰 차이를 보인다. 가령 1반의 학생수가 100명이고 2반의 1명이라면 어떠할까??

2차원 배열에서는 ar[2][100]; 이라고 선언해야 할 것이고 포인터배열에서는 *ar[2] ; 이란 선언을 통해 동적인 메모리 할당을 할 수 있는 것이다. 이러한 개념만 확실히 느끼고 있다면 앞으로 더 느끼는게 많을 듯 싶다.

여기서 또 하나 집고 가야 부분은 포인터배열을 통해 문자열을 입력 받았을 때이다.

사용자 삽입 이미지


arps[0]은 주소를 저장할 수 있는 포인터 변수라 생각하면 된다. *arps[]은 포인터 타입의 배열이라고 생각하기 바란다. 이 포인터 변수는 단지 상수영역(constant)에 있는 문자열 "고양이"등의 시작주소를 가리키는 거라 생각해야 한다. 이러한 문자열은 하나의 상수이기 때문에 변경을 하지 못한다. 이차원배열을 통해 입력 받는 문자열은 스택영역(stack)에 저장되어 얼마든지 접근하여 변경가능 하는 거랑 다른 점이라 할 수 있다.
참고 : 포인터배열

2. type(*변수)[2차 첨자 크기]

변수를 포인터형으로 변환한다. 그리고 나서 [2차첨자크기]만큼의 크기를 갖는 이차원 배열의 번지를 담는 것이다. 2차 첨자 크기는 반드시 기재해야 가리킬 배열의 전체 크기를 구할 수 있다.

*2차원배열을 포인터로 받고 싶을 때 사용한다고 보면 된다.물론 그 이상의 배열도 가능하다.

사용자 삽입 이미지

함수의 인수가 pi[][3]은 (*pi)[3]과 동일하다. 다만 인수가 포인터인지 배열을 받을 포인터인지 무엇을 강조하느냐의 차이 있을 뿐이다.

**포인터 배열은 결국은 배열이고 배열 포인터는 결국은 포인터이다.**
Tag |

C를 공부하다 중간고지인 포인터를 익히기 되면 void형 포인터라는 복병을 만나게 된다.

void *vp;    //대상체의 타입을 명시하지 않는 특별한 포인터형 이다.


  1. 임의의 대상체를 가리킬 수 있다.
    1. 대상체가 정해져 있지 않다는 말은 어떠한 대상체도 가리키지 못한다는 뜻이 아니라 임의의 대상체를 가리킬 수 있다는 얘기와도 같다. 선언할 때 대상체의 타입을 명시하는 일반적인 포인터는 지정한 타입의 대상체만 가리킬 수 있지만 void형 포인터는 어떠한 대상체라도 가리킬 수 잇다.
      void형 포인터는 임의의 포인터를 대입 받을 수 있지만 반대로 임의의 포인터에 void형 포인터를 대입 할 때는 반드시 캐스팅을 해야 한다.
      pi = (int* )vp;    //int*pi
      pd=(double*)vp;    //double* pd

  2. *연산자를 쓸 수 없다.
    1. void형 포인터는 임의의 대상체에 대해 번지값 만을 저장하며 이 위치에 어떤 값이 들어 있는지는 알지 못한다. 따라서 *연산자로 이 포인터가 가리키는 메모리의 값을 읽을 수 없다. 대상체의 타입이 정해져 있지 않으므로 포인터가 가리키는 위치에서 몇 바이트를 읽어야 할지, 또 읽어낸 비트를 어떤 식으로 해석해야 할지를 모르기 때문이다. 만약 vp번지에 저장된 값이 정수형이라는 것을 확실히 알고 읽고 싶다면,

      *(int *)vp;        
      //vp를 잠시 정수형 포인터로 바꾼 후 번지의 정수값을 읽는다.

  3. 증감연산자를 쓸 수 없다.
    1. 대상체의 타입이 정해져 있지 않으므로 증감 연산자도 곧바로 사용할 수 없다.

      vp=(int *)vp + 1;    
      //vp를 잠시 int*로 캐스팅한 후 1을 더하면 4바이트를 더한다.

void형 포인터의 특징에 대해 간단하게 요약해 보면 대상체가 정해져 있지 않으므로 임의의 번지를 저장할 수 있지만 *연산자로 값을 읽거나 증감연산자로 이동할 때는 반드시 캐스트 연산자가 필요하다. 순수하게 메모리의 한 지점을 가리키는 기능만 가지는 포인터 이기 때문이다.

참고 : 이중포인터(winapi)

Tag |