ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 포인터의 이해
    C언어 2020. 3. 7. 21:15

    이번 포스트는 포인터에 대해서 조금더 확실하고 어떤식으로 포인터를 연산하는지에 대해서 더 자세하게 다룰 것이다.

    위의 자료는 포인터가 어떤 역할을 수행하는지 나타낸다.

    가장먼저 pn 변수를 강제 자료형 변환을 시켰을 때 이다 이때 변환한 자료형은 int *로 기술하였다. 다음과 같이 변수를 포인터로 형변환 시키면 변수에 담긴 (주소)에 해당하는 메모리에 내용을 int로 해석하겠다는 의미이다. 따라서 pn 변수에는 1이 있으므로 1을 주소로 인식하며 해당 주소에 있는 메모리의 값은 int로 해석하게된다.

    다음은 변수 a에 대한 주소를 강제 자료형 변환 시켰을 때 이다. 위와 마찬가지로 int *으로 기술. 따라서 &a에 대한 연산 결과인 a 변수의 주소가 주소인 형태로 상수화 되면서 해당 상수화 된 주소의 메모리를 int로 해석하게 된다.

    다음은 명시적으로 &주소 연산 없이 주소 상수를 기제하여 해당 상수를 int *로 강제형 변환 시켰을 때 이다. 따라서 해당 상수는 주소로 변환 되며 해당 주소의 메모리의 값을 int로 해석하게 된다.

    위의 사실을 요약하자면 int * => (*) 포인터 선언 시 뒤에 오는 값은 무조건 주소형태로 인식 되며 , (int) 해당 주소의 메모리를 int의 인스턴스화 시킨다는 의미이다. 즉 ' * ' 에 따라 뒤에 오는 값을 주소로 인식하며 해당 주소의 메모리를 ' int '의 인스턴스로 보겠다는 의미이다.

    이때 뒤에 오는 값으로 pn 변수가 기입 되면 해당 변수안에 담긴 값을 주소로 인식한다는 의미, 만약 &연산 or 직접 상수기제 같은 경우에는 주소가 직접적으로 쓰여있으므로 해당 주소의 메모리를 바로 int의 인스턴스로 인식한다. 따라서 '  *  ' 는 뒤에오는 정보를 주소로 변환시키며 해당 주소의 메모리를 (X 자료형)의 인스턴스로 만드는 역할이다. 

     

    다중 포인터 & 포인터 배열 & 다차원 배열

    포인터는 위에서 설명 한 것처럼 변수에 저장 되어 있거나, 상수화 된 주소를 포인터 자료형으로 선언함으로 써 해당 주소의 메모리에 (X 자료형)의 인스턴스 즉 해당 주소의 메모리를 변수로 만들어 주는 역할을 한다. 쉽게말해 사용자가 지정한 메모리를 사용가능하게 해주는 C의 문법적 요소이다.

    위의 자료를 보자 plist 변수를 (int *) 자료형으로 선언한 모습이다. 0x0018FF20 이라는 메모리에 0x005E6B50  이라는 값이 담겨있으며 해당 값을 앞서 선언한 (int *) 자료형에 따라 주소로 해석될 것이다. 또한 0x0018FF20 메모리 안에 있는 값은 malloc 함수를 통해 int 자료형의 크기 * 3개의 메모리 공간을 할당 받은 주소이다. 따라서 해당 plist 포인터에 접근 할 때는 ' * ' 간접지정 연산자를 통해서 접근 할 수 있다. 이때 주의 할 점이 있는데 아래 박스를 보자

    *plist + 1

    plist + 1

    *(plist) + 1

    이와같은 연산식의 결과가 제각기 다른 것을 볼 수있는데

    1.  *plist + 1 의 식은 (*plist)+1 과 같다. 따라서 plist의 간접지정연산자의 결과에 + 1 한 값이 출력 될 것이다. 과정에 대한 설명은 다음과 같다.

    plist 라는 변수에 담긴 값이 int * 자료형에 따라 주소로 해석 되어 ( 값 )005e6b50 => (int *)0x005E6B50 과 같이 변환 되어 인식 되며 따라서 0x005E6B50의 주소에 있는 메모리에 접근하게 된다. 그 뒤 '+ 1' 연산식의 결과에 따라 해당 메모리 요소의 값 + 1의 식이 수행되는 것이다.

    2. plist + 1 의 식은 '*' 해당 연산자가 없음으로 plist에 있는 값에 + 1 한 값 이 나타나게 될것이다. 이는 plist 변수에 담긴 005e6b50과 같은 값이 (int *)로 선언 한 자료형으로 인해 주소화 되어 (int *)0x005E6B50과 같이 해석되며 해당 주소에 +1한 값 즉 (int *)0x005E6B50 이라는 기준주소에서  + 1 칸 이동한  (int *)0x005E6B54의 메모리의 주소를 가리키게 된다.

    3. *(plist + 1) 의 식은 위에서 설명하였 듯 plist가 기존에 가지고 있던 주소 즉 기준주소에 + 1 한 값인 따라서 기준주소에 +1 즉 상대주소에 접근하여 '*' 연산자를 통해 해당 상대주소의 요소에 접근하게 된다.

     

    위의 설명이로 이제 단일 포인터에 대한 개념은 숙지했을 것이다. 이제 부터 다중포인터에 대해서 설명하겠다.

    다중포인터란 ? 

    다중포인터란 이름에서도 알 수 있듯이 포인터가 다중으로 있는 경우 즉 포인터 안에 포인터가 들어있는 구조라고 생각하면 된다.

     위의 자료를 보자 화살표를 통해 어느 주소를 가르키는지 알 수 있을 것이다. 정리하면 다음과 같다.

    & plist => 0x0018FF20 ( plist 포인터 변수의 주소 )

    & *plist =>0x00616B50 ( plist 포인터 변수에 들어있는 값 즉 동적할당 받은 메모리 주소에 대해서 접근한 요소의 주소 값 ) 따라서 동적할당 받은 주소는 기준주소가 됨으로 기준주소의 값이다 .

    & pplist => 0x0018FF14 ( pplist 포인터 변수의 주소 )

    & *pplist => 0x00619B48 ( pplist 포인터 변수에 담긴 값  즉 동적할당 받은 메모리의 주소에 대해서 접근한 요소의 주소 값 ) 따라서 기준주소에 대한 정보가 0x0018FF14 이다. 추가적으로 pplist를 선언 후 동적할당 받을 때 반환 값은   (void *) 이며 반환 받은 주소의 메모리 크기는 (int *) * 1 과 같다. 즉 주소가 하나 들어 갈 크기이다. 따라서 pplist 변수 안에 들어갈 값은 int * 이다. 즉 주소이다.

     

    위의 자료는 pplist 라는 포인터 변수의 0번째 요소 즉 동적할당 받은 메모리로 부터 0번째 위치 즉 동적할당 받은 메모리의 기준주소에 해당하는 메모리에 plist 변수에 담긴 int * 자료를 넘긴 것이다. 즉 plist에 동적할당 받은 주소를 pplist에 넘긴것이다. 따라서 pplist 안에 동적할당 받은 주소가 있고 ' * ' 연산자를 통해 해당 주소의 메모리에 접근하여 해당 주소의 메모리 안에 plist 가 동적할당 받은 메모리의 주소를 넣어준 것이다.

    이는 즉 plist 변수를 int * 자료형으로 선언함으로써 plist 변수 안에 있는 값을 주소로 식별하고 해당 주소의 메모리를 int로 해석 한 것과는 다르게 pplist 변수를 int ** 자료형으로 선언함으로써 pplist 변수 안에 있는 값을 주소로 식별 (int *) 하고 해당 주소의 메모리에 있는 값을 ( * ) 로 해석 한다는 의미이다. (int *) + (*)

    따라서 *pplist 와 같은 접근은 pplist 변수의 요소로써의 접근 즉 pplist 변수 안에는 동적할당 받은 주소가 있으며 해당 주소가 가리키는 메모리로의 접근을 의미한다. 이때 해당 메모리 안에는 plist가 동적할당 받은 주소가 있음 

    *( pplist + 0 ) = plist ; 

    이와같이 pplist의 값 (동적할당 받은 주소) + 0 에 해당하는 요소로 접근한다.

     

     

    정리하자면 다음과 같다.

    pplist 변수 안 에는 동적할당 받은 void * 주소가 담겨있고 *pplist 와 같이 해당 void * 주소의 메모리에 접근하면 cdcdcdcd 와 같이 채워져 있을 것이다. 이때 해당 메모리에 cdcdcdcd => 0x00FF1858 과 같이 plist에서 동적할당 받은 메모리의 주소를 넣어줌으로 써 *(pplist + 1)과 같은 연산은 0x00FF1858 주소로 부터 1칸 멀어진 상대주소가 나타난다.

    추가적으로 *pplist + 1과 같은 연산은 *pplist 가 먼저 수행 됨으로 *pplist의 결과은 pplist 변수 안에 있는 동적할당 받은 메모리에 접근한 값 따라서 plist 가 동적할당 받은 메모리의 주소가 반환되며 해당 메모리의 주소에 + 1 한 값이 연산 결과로 나타난다.

    위와 같이 * pplist => pplist 변수가 동적할당 받은 메모리 안에 plist가 동적할당 받은 메모리의 주소 ( 0x004E6B50 ) 이 담겨있으므로 해당  0x004E6B50 주소로 부터 1칸 멀어진 0x004E6B54 의 주소가 나타난다.

    또한 위의 과정을 보면 동적할당 받은 메모리안에 동적할당 받은 메모리의 주소가 들어가 있는 형태를 가지고 있다. 이는 동적할당 받은 메모리의 주소를 관리하는 변수인 포인터안에 포인터가 있는 형식이며 따라서 다중포인터를 사용한 개념이다.

     

    'C언어' 카테고리의 다른 글

    C 프로그램의 동작 과정  (0) 2020.03.16
    스택 프레임 & 재귀함수  (0) 2020.03.13
    배열의 이해  (0) 2020.03.05
    메모리 복사  (0) 2020.03.05
    메모리 동적 할당 및 해제  (0) 2020.03.04

    댓글

Designed by Tistory.