• 카테고리

    질문 & 답변
  • 세부 분야

    프로그래밍 언어

  • 해결 여부

    해결됨

배열과 포인터와 포인터 산술 연산의 이해

23.09.03 01:19 작성 조회수 245

5

안녕하세요, 집에서 해당 강의로 입문한 독학러 입니다.
제가 배열과 메모리, 포인터와 산술 연산을 제 기준으로 쉽게 풀어서 이해를 하였는데 이해한게 맞는건지 확인을 부탁드리고자 글을 작성하게 되었습니다.

  1. 포인터변수의 크기

    포인터변수의 크기는 자료형이 무엇이든 x86(32비트)에선 4바이트, x64(64비트)에선 8바이트가 나왔습니다.
    이러한 이유가 메모리주소에서 확인할 수가 있었는데 일단 x86(32비트)에선 왜 4바이트가 나오냐에 대한 생각인데 메모리 주소를 포인터 변수에 저장한다고 가정했을 때 메모리 주소도 값이잖아요?

    해당 값을 일단 출력해보면 아래와 같이 나옵니다.

    1.png2.png

    이 사진으로 생각할 수 있는건 16진수의 8자리 그리고 4바이트. 즉 4바이트가 표현할 수 있는 가짓수는 2^32 = 4,294,967,296
    0 ~ 4,294,967,295까지 여기서 4,294,967,295는 16진수로 FFFFFFFF. 위 사진의 자릿수와 같은 8자리다.
    즉 메모리 주소의 가짓수는 unsigned int과 마찬가지로 4,294,967,296만큼 가질 수 있으며 00000000 ~ FFFFFFFF 이기 때문에 x86(32비트)에선 포인터 변수는 해당 16진수의 값을 저장해야 하니 4바이트인 것이다. x64(64비트)에서도 위와 동일한 이유로 8바이트가 되는 것이다, 라고 이해했습니다. 맞게 이해했을까요??

  2. 배열과 포인터의 산술연산

    배열과 포인터의 산술연산을 보고 제일 먼저 떠오른게 "주사위 게임"이였습니다.

    일단 배열을 선언하면 1차든 2차배열이든 몇겹이든 메모리 공간에 1차원적으로 차례대로 나열되어 메모리 공간이 확보되는걸 선생님 강의를 통해 이해했는데요. 이 메모리를 주사위 게임의 게임판 처럼 변형하여 생각을 해본다면 아래와 같이 될 것 같습니다.

    3.jpg<- 배열의 메모리공간 가정

    주사위 놀이판을 편집을 해왔습니다.

    여기서 위 그림대로 배열을 선언한다 가정했을 때 arr[3][5]가 될 것 입니다.

    1~5까진 arr[0][0] ~ arr[0][4]
    6~10까진 arr[1][0] ~ arr[1][4]
    11~15까진 arr[2][0] ~ arr[2][4]

    자료형을 적지않은 이유는 1바이트 자료형이든 4바이트 자료형이든 저 위 그림 한칸 한칸을 하나의 인덱스라고 생각해주시면 될 것 같습니다.

    만약 int 4바이트라고 가정한다면 위 그림 1번칸엔 메모리 주소 0~3까지 있을 것이고 2번칸엔 4~7까지 있다고 생각할 수 있습니다.

    그러면 이제 저 주사위놀이판 위에 이제 말을 배치해야 인덱스칸에 접근할 수 있다고 생각해봅시다.

    그럼 그 말은 포인터변수가 될 것입니다.

    *ptr = arr; 여기서 arr은 &arr[0][0] 즉 메모리의 첫주소 값을 가지고 있기 때문에 이게 몇차원 배열이든 배열변수의 이름만 적어서 포인터변수에 첫 주소를 저장합니다.

    그러면 이제 1번칸에 말이 접속하여 인덱스에 포인터변수로 접근할 수 있게 된다고 생각했습니다.

    1번칸은 [0][0] 여기서 5번칸 [0][4]으로 이동한다고 가정 한다면 4칸을 이동해야 합니다.
    그러면 여기서 말에다가 4칸을 더하면 ptr += 4;을 하면 포인터변수의 주소는 [0][4]을 가리키고 있을 것 입니다. 여기서 바꿔 생각한다면[0][4]가 아니라 [0][i] 라고 했을 때 ptr += i; 을 더하면 [0][0] ~ [0][i] 까지 이동할 수 있을 것 입니다.

    위 방법대로 한다면 1차원이든 2차원이든 3차원이든 배열 맨 끝 [인덱스]에 포인터 변수로 접근할 수 있다고 생각합니다.
    그러면 이제 1번칸 [0][0]에서 6번칸 [1][0]에 가고 싶다고 가정을 한다면 총 5칸을 가야 도달할 수 있습니다.
    왜냐하면 arr[3][5]으로 선언했기 때문에 뒤에 [5]인덱스가 0~4까지 총 5가짓수이기 때문입니다.

    그러면 포인터변수(말)에게 ptr+=1*5을 하면 6번칸 [1][0]에 도달할 수 있습니다.

    1번칸 [0][0]에서 11번칸 [2][0]에 갈려면 ptr += 2*5을 하면 됩니다. 즉 이걸 바꿔서 생각해본다면[0][0]에서 [j][0]로 가기 위해서는 ptr += j * 5(인덱스 총 갯수)을 이용하면 옮겨갈 수 있습니다.
    여기서 빼기도할 수 있는데
    현재 ptr이 [0][0]에 있다고 가정하고 ptr += 2 * 5를 하면 [2][0]으로 가게 되는데 여기서 [1][0]으로 간다고 가정하면 ptr += -1 * 5를 하면 [1][0]으로 가게 된다. 위와 같은 방식으로 배열에 포인터변수로 접근하여 사용하니까 아주 쉽게 사용이 되더라구요, 반복문에서는 따로 위 그림처럼 포인터변수 = 말, 배열 = 주사위게임판 이라 생각하고 머릿속에 그리면서 하니까 원하는 값을 얻을 수 있고 이러한 방식이 괜찮은 방법 중 하나일까요? 아니면 잘못 이해하고 있는걸까요? 문장 정리능력이 없다보니 이렇게 긴 글을 적어놨는데 읽어주시면 감사하겠습니다.

답변 1

답변을 작성해보세요.

2

Soobak님의 프로필

Soobak

2023.09.03

안녕하세요, 답변 도우미 Soobak 입니다.

  • 포인터 변수의 크기에 대해서
    : 잘 이해하고 계신 것 같습니다. 포인터 변수는 메모리 주소를 저장하기 때문에, 주소를 나타내는 데에 필요한 바이트 크기가 그대로 포인터 변수의 크기가 됩니다. x86 아키텍쳐에서는 32 비트, 즉 4 바이트로 주소를 표현하고, x64 아키텍쳐에서는 64 비트, 즉 8 바이트로 주소를 표현합니다.

  • 배열과 포인터의 산술연산
    : '주사위 게임' 이라는 비유를 통해 쉽게 이해가 되신다면 유용한 비유인 것 같습니다. 포인터 산술을 통해 계산하시는 방법도 잘 이해하고 계신 것 같습니다.

    *ptr = arr; 에 대해서 이해하신 부분, ptr += 4;ptr[0][4] 에 대해 이해하신 부분, 그리고 [0][0] 인덱스에서 [j][0] 인덱스로 이동하는 방법에 대한 부분 등 모두 잘 이해하고 계십니다.

 

대체적으로 올바르게 잘 이해하고 계신 것 같습니다. 설명을 통해 얼마나 열심히 공부하고 계신지 잘 느껴지네요.