• 카테고리

    질문 & 답변
  • 세부 분야

    프로그래밍 언어

  • 해결 여부

    미해결

배열의 이중포인터

23.12.14 09:23 작성 23.12.14 10:46 수정 조회수 241

2

안녕하세요

학습중 개념에 혼동이 생겨 질문글을 남깁니다.

강의는 10.13, 4분 18초 쯤입니다.

 

예컨대*(*(parr + 1) + 2)가 있다 하면 이것이 어떤 값을 나타내는지 그 과정 중에서 혼란스러운 부분이 몇 개 있습니다. 질문과 더불어 제가 잘못 설명하는 부분이 있으면 지적해주시면 감사하겠습니다.

 

parr + 1는 포인터parr 배열의 2번 째 원소(arr[1])의 첫 주소, 즉 4의 주소를 가리키는 포인터입니다.

 

한편, *라는 기호는 포인터변수에 저장된 주소에 접근하여 그쪽에 저장된 데이터를 들고오는 역참조의 기능을 수행케 합니다.

 

그렇다면 *이 붙은 *(parr + 1)에서는 4의 주소로 접근하여 *에 의해 4라는 값을 역참조해오게 됩니다.

 

하지만 그러면 *(4 + 2)가 되는데 이는 전혀 말이 안 되고 본래의 +2는 포인터의 산술연산을 위한 것이기에 *(parr + 1)는 모종의 포인터가 돼야 하고 강의 중에서도 교수님이 그렇게 말씀하셨습니다.

(제가 오해하고 있는 부분과 달리 가장 밖에 있는 *는 실제로 역참조의 기능을 가지는 것이 자명한데도요...)

 

그래서 정리하자면 *(parr + 1)는 어떤 주소를 나타내것인지 아니면 모종의 포인터를 의미하는 건지 궁금하며

 

그리고*(*(parr + 1) + 2)의 전체적인 플로우를 정확하게 이해하고 싶습니다.

 

감사합니다.

 

답변 1

답변을 작성해보세요.

3

Soobak님의 프로필

Soobak

2023.12.15

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

 

*(parr + 1) 을 "4 의 주소로 접근하여 * 에 의해 4 라는 값을 역참조해오게 됩니다." 라는 부분이 잘못되었습니다.

*(parr + 1)parr[1] 을 역참조하는 것으로, parr[1] 또한 arr[1] 배열의 첫 번째 원소를 가리키는 포인터입니다.

parr이중포인터라는 것을 이해하시면 도움이 되실 것 같습니다.

 

Echapper4님의 프로필

Echapper4

질문자

2023.12.15

감사합니다

 

그렇다면 말씀하신 부분인

*(parr + 1)parr[1] 을 역참조하는 것으로, ...

에서

(아래의 사진을 참고해주시면 감사하겠습니다.)

*(parr + 1)parr[1]를 역참조하기 위해서는 주소인parr + 1parr[1]의 주소여야 하는데

 

지적해주신 것 처럼 4의 주소이지는 않으니 parr + 1의 주소, 즉 parr[1]이 있는 곳의 주소는 12가 아닌 어디 다른 별도의 주소이다 라는 말씀인가요?

Soobak님의 프로필

Soobak

2023.12.16

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

 

제가 이전 답변에서 말씀을 조금 혼동을 드리게 드렸네요.

다시 명확하게 설명드리면 다음과 같습니다.

parr + 1parr 배열의 두 번째 원소, 즉, parr[1] 을 가리키는 포인터의 주소입니다.

여기서, parr[1]arr[1] 배열, 즉, {4, 5, 6} 배열의 첫 번째 원소인 4 의 주소를 가리키고 있습니다.

따라서, *(parr + 1)parr[1] 과 같고, 4의 주소를 가리키는 포인터입니다.

그렇기에, *(*(parr + 1) + 2) 와 같은 포인터 연산이 가능한 것입니다.

마지막에 말씀하신 parr[1] 자체의 주소와 관련된 말씀은 맞습니다.

Echapper4님의 프로필

Echapper4

질문자

2023.12.16

답변 감사합니다.

중간에 말씀하신 parr[1]이 포인터 변수명 인가요? 일단 변수명이라 생각하고 제 설명 드려보겠습니다.

 

parr + 1parr 배열의 두 번째 원소, 즉, parr[1] 을 가리키는 포인터의 주소입니다.

말씀하신 위의 부분을 아래의 그림으로 표현해봤습니다.

(주소값은 예시)

Gâteau De Nous (1).jpeg.png

또한 parr[1]arr[1]배열 즉슨, 4의 주소를 가리키므로

Gâteau De Nous (2).jpeg.png

이렇게 될 것 같습니다.

 

하지만 *는 간접 참조 연산자로서 주소로 접근하여 그 주소의 데이터(내용물)를 읽어온다는 걸로 알고있는데 그렇다면

*(parr + 1)parr + 1이라는 주소로 접근하여 그 옆에 있는 저장된 주소값인 104를 가져오는데, 이는 어떤 포인터이거나 말씀하신 포인터변수parr[1]가 되는 것 같아 보이지는 않습니다.

제가 *의 역할에 대해 오해하고 있는 게 있을까요?

어디서부터 잘못 되었는지 정말 모르겠습니다...

Soobak님의 프로필

Soobak

2023.12.17

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

 

parr[1]int* parr[2] = {arr[0], arr[1]}; 으로 선언된 배열의 두 번째 원소를 나타냅니다.

 

그려주신 그림과 말씀해주신 설명 모두 정확하게 잘 이해하고 계신 것 같습니다.

"하지만 *는 간접 참조 연산자로서 주소로 접근하여 그 주소의 데이터(내용물)를 읽어온다는 걸로 알고있는데 그렇다면

*(parr + 1)parr + 1이라는 주소로 접근하여 그 옆에 있는 저장된 주소값인 104를 가져오는데, 이는 어떤 포인터이거나 말씀하신 포인터변수parr[1]가 되는 것 같아 보이지는 않습니다."

이 부분에 대해서는, *(parr + 1) 은 'parr + 1 이라는 주소로 접근하여, 저장된 주소값(이 또한 데이터입니다.) 104 를 역참조하는 것'으로 parr[1] 과 같은 동작을 수행합니다.

배열의 인덱싱 접근 [] 은, 일반적으로 포인터 연산으로 구현됩니다.
즉, parr[1] 로 배열의 원소에 접근하는 것은 *(parr + 1) 과 같은 방식으로 동작합니다.
'배열의 시작주소(배열의 이름)' 와 '포인터 연산을 통한 역참조', '주소와 데이터' 를 생각해보시면 이해가 수월하실 것 같습니다.

위 내용이 parr + 1parr[1] 의 주소를 가리키는 포인터라는 것을 이해하시는 데에 도움이 되셨으면 좋겠습니다.

정리하자면,

  • parr 은 포인터의 배열이며, int* 자료형의 포인터들을 저장합니다.

  • parr + 1parr 배열의 두 번째 원소(parr[1])의 주소를 가리킵니다. 즉, parr + 1parr[1] 의 주소를 가리키는 포인터입니다.

  • *(parr + 1)parr + 1 이 가리키는 주소에 있는 값, 즉, parr[1] 을 가져옵니다.

  • parr[1]arr[1] 배열의 첫 번째 원소의 주소를 가리키는 포인터입니다.

따라서, *(parr + 1)parr[1] 은 동일한 값을 나타내며, 이는 arr[1] 배열의 시작 주소입니다.

Soobak님의 프로필

Soobak

2023.12.17

-추가 보충 설명-

오해하고 계신 부분을 점검하는 데에 도움을 드리기 위해, 각 변수들과 관계를 최대한 정리하여 설명드립니다.

 

  • arr 배열

    • arr2차원 정수 배열 입니다.

    • int arr[2][3] = { {1,2,3}, {4,5,6} }; 과 같이 선언되었으며, 두 개의 행과 각 행에 세 개의 열(원소)을 가진 배열입니다.

    • arr[0]{1, 2, 3} 배열을 가리킴과 동시에 해당 배열의 시작 주소를 가리키는 포인터와 호환이 되는 형태입니다. arr[1] 또한 {4, 5, 6} 배열을 가리킴과 동시에 해당 배열의 시작 주소를 가리키는 포인터와 호환이 되는 형태입니다.

    • 따라서 arr[0]int* 자료형의 포인터로 사용할 수 있습니다.
      예) int* ptr = arr[0]; 과 같이 선언하면, ptr{1, 2, 3} 배열의 첫 번째 원소인 1 의 주소를 가리키게 됩니다.

 

  • parr 배열

    • parr 은 포인터의 배열입니다.

    • int* parr[2] = { arr[0], arr[1] }; 과 같이 선언되었으며, parr 배열의 각 원소는 정수를 가리키는 포인터 (int* 자료형) 입니다.

    • parr[0]arr[0] 이라는 주소를 가리키며, arr[0]{1, 2, 3} 배열의 첫 번째 원소의 주소입니다.

    • parr[1]arr[1] 이라는 주소를 가리키며, arr[1]{4, 5, 6} 배열의 첫 번째 원소의 주소입니다.

    • parr + 1parr 배열의 두 번째 원소인 parr[1] 의 주소를 나타내고, *(parr + 1)parr[1] 의 값을 가져옵니다. 즉, *(parr +1)parr[1] 이며, arr[1] 배열의 첫 번째 원소의 주소입니다.

 

  • 요약

    • arr2차원 배열 입니다.

    • parr포인터의 배열 로, 각 포인터는 arr 의 각 행을 가리키는 포인터입니다.

       

혹시 이해가 안되시는 부분이 있으시면 편하게 댓글 남겨주세요.

Echapper4님의 프로필

Echapper4

질문자

2023.12.18

정말 정말 정성스러운 답변 다시 한 번 감사합니다.

 

요약하자면,

parr포인터 자체가 원래 parr[0]의 주소를 담고있었는데

포인터 산술연산 +1 을 통해 주소를 int 자료형 크기만큼 건너뛰어가서

포인터 parr + 1parr[1]의 주소가 저장되도록 즉,

포인터 parr + 1parr[1]의 주소를 가리키게 했고

*parr + 1에 붙여서 ,*(parr + 1)가 "arr[1](4의 주소)라는 주소가 포인터에 저장된 즉, 이 주소를 가리키는 포인터변수 parr[1]" 가 되도록 했다.

 

따라서 남아있는 것은 *(parr[1] + 2)이 됐고

+2라는 포인터 산술연산을 통해

포인터변수 parr[1]안에 저장된 주소를 조정하여 목적지인

4의 주소로 도달했고 *를 통해 4를 읽어냈다.

라고하면 정확한 이해일까요?

Soobak님의 프로필

Soobak

2023.12.18

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

 

거의 맞지만, 몇 가지 중요한 부분에서 혼동이 있으신 것 같습니다.

 

보다 자세하게 요약해보면 다음과 같습니다.

  • parr 배열과 포인터 연산


    : parr 은 포인터의 배열입니다. 이 배열에는 arr[0]arr[1] 이라는 두 개의 주소가 저장되어 있습니다. 여기서 parr[0]arr[0] 을, parr[1]arr[1] 을 가리킵니다.
    arr[0]arr[1] 은 각각 {1, 2, 3}{4, 5, 6} 배열의 시작 주소입니다.

  • 포인터 산술 연산과 *(parr + 1)
    : parr + 1parr 배열의 두 번째 원소, 즉, parr[1] 의 주소를 가리킵니다.
    그리고 *(parr + 1) 은 이 주소에 저장된 값을 역참조하여 가져옵니다. 이 값은 parr[1] 과 동일하며, arr[1] 배열의 시작 주소를 가리키고 있으므로, parr[1] + 2arr[1] 배열의 세 번째 원소의 주소를 가리킵니다. 이 주소는 {4, 5, 6} 배열에서 6 의 위치입니다.
    따라서, *(parr[1] + 2)6 을 역참조하여 가져옵니다.

Echapper4님의 프로필

Echapper4

질문자

2023.12.18

전에는 바로위의 수박님께서 말씀해주신 내용을 따라가다보면 자꾸 갓길로 빠져서 계속 도돌이표를 돌았는데 지금 보니 내용 그대로 납득이 잘 되는 것 같네요. 감사합니다 (_ _)