C

([C언어] 17강) 포인터의 포인터와, 포인터의 메모리크기

잭클 2019. 6. 28. 14:49

이번 시간에는 포인터의 포인터를 배워보겠습니다

 

자 우선 생각해보죠, 우리는 배열은 포인터다 라는 개념을 배웠었습니다

 

그럼 배열의 요소로 배열을 가지고있는 배열 즉, 2차원배열은 어떻게 이뤄져있는걸까요?

 

포인터들을 가지고있는 포인터라..

 

네 바로 포인터의 포인터입니다ㅋㅋ

 

포인터가 어떤 요소의 주소였다면

 

포인터의 포인터는 그 주소값이 저장된곳의 주소입니다ㅋㅋㅋ

 

마치 마트료시카 인형같죠ㅋㅋ

포인터의 포인터형은 다음과 같이 표시합니다

 

자료형 ** 변수이름;

자 우리는 지난 시간에 콜 바이 벨류와 콜 바이 레퍼런스에 대해 배웠습니다.

 

그런데 만약에 우리가 배열을 함수의 매개변수로 보내고 싶다면 어떻게 해야할까요?

 

#include <stdio.h>

int test(int arr[])
{
    printf("%d", arr[3]);
}
int main()
{
    int a[5] = { 0,1,2,3,4 };
    test(a);
}

물론, 이렇게 해도 상관은 없습니다!

 

그러나 우리는 나름대로의 규칙을 정하도록 하겠습니다.

 

우리는 이제 배열은 포인터다 라는 개념을 배웠으니 어떻게 해야할까요?

#include <stdio.h>

int test(int * arr)
{
    printf("%d", arr[3]);
}
int main()
{
    int a[5] = { 0,1,2,3,4 };
    test(a);
}

이런식으로 할 수 있겠네요!

 

하지만 여기에서 꼭 참고해야할 점이 있습니다.

 

위의 코드에서 test함수 내에서 a배열의 길이를 구하고 싶다고 칩시다.

 

자 그럼 printf("%d",sizeof(arr) / sizeof(int)); 로 바꿔서

 

#include <stdio.h>

int test(int* arr)
{
    printf("%d", sizeof(arr) / sizeof(int));
}
int main()
{
    int a[5] = { 0,1,2,3,4 };
    test(a);
}

 

이렇게 해주면 되겠죠? 한번 해볼까요?

엥??? 분명 우리 배열 크기는 5갠데 왜 1이라고 나오죠..?

 

정확히는 배열은 포인터지만 포인터는 배열이 아닙니다.

 

배열은 무조건 요소의 포인터이다는 참이지만

 

포인터는 무조건 배열이다는 거짓입니다.

 

배열이 포인터로 바뀌는 순간 자신은 일개의 포인터로 생각할 뿐

 

자신이 배열이였다는것을 잃어버립니다

 

그리고 요소의 포인터는 항상 4바이트입니다.

 

배열이었을 때에는 배열이 sizeof함수를 통해서

 

"아, 나는 int형이니까 4바이트고 요소가 5개니까 20바이트야!"

 

이렇게 알려줬었다면

 

포인터로 바뀌고나서는

 

"나는 포인터니까 4바이트야, 내 요소? 난 주소일뿐이라 그런거 모르는데?"

 

이렇게 되는겁니다.

 

그래서 항상 배열을 매개변수로 함수를 호출할때에는 아래코드처럼 배열의 길이도

 

매개변수로 보내도록 프로그래밍해주세요!

 

#include <stdio.h>

int test(int* arr,int length)
{
    printf("%d", length);
}
int main()
{
    int a[5] = { 0,1,2,3,4 };
    test(a, sizeof(a)/sizeof(int));
}

이렇게 하면 test함수도 배열의 길이를 알 수 있겠죠??

 

그럼 이번엔 포인터의 포인터의 메모리 사이즈를 볼까요?

 

#include <stdio.h>

int main()
{
    int arr[3][3];
    int** ptr = arr;
    printf("%d", sizeof(ptr));
}

이렇게 해서 실행하면!?

왜 3 x 3 = 9고 int가 4바이트니까.. 9x4=36이어야하는데 대체 왜 4일까요??

 

아까 말했다싶이 배열을 포인터로 바꾼 순간에 더이상 배열이 아니라 포인터인겁니다

 

포인터든 포인터의 포인터든 어쨋든 단순히 주소일뿐이기때문에 항상 4바이트입니다.

 

마지막으로 배열과 2차원배열이 메모리에 쓰이는 방법을 그림으로 나타내자면

 

arr[8] 배열은 메모리에

이런식으로 저장되지만

 

arr[4][2] 배열은 메모리에

이렇게 저장된다는 점 꼭 기억해주세요

 

예를들어

 

1 2 3 4 5 6

7 8 9 10 11

12 13 14 15 16

 

이렇게 들어있는 2차원배열은 메모리에

 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

 

이런순서로 들어있게 됩니다.

 

포인터는 배열이 아닌 포인터일 뿐인데

 

어떻게 ptr[3] 이런식으로 대괄호로 접근이 가능하죠?

하고 물어보실수 있을것 같은데요

 

강제로 접근하는겁니다. ptr[3]이라고하면

ptr의 주소갚부터 세칸 뒤에있는 주소에 저장된 값을 가져와라 라는뜻이 됩니다.

 

ptr[3]이라고 한것과 *(ptr + 3) 은 같은 의미가 됩니다!

 

이렇게 ptr[3] 이런식으로 대괄호 []로 접근하는 방식을 "랜덤접근"이라고 합니다.

 

아참! 배열은 포인터이지만 포인터는 배열이 아니다 라는 말은 무슨말인지 이해하기 힘들수도 있어서

 

더 쉽게 풀어말하자면

 

연필은 필기도구이지만

 

필기도구는 연필이 아니다.

 

라고 보시면 될것같네요!

 

오늘강좌는 여기서 마치도록 하겠습니다! 수고하셨습니다!