작성
·
290
·
수정됨
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 입니다.
*(parr + 1)
을 "4
의 주소로 접근하여 *
에 의해 4
라는 값을 역참조해오게 됩니다." 라는 부분이 잘못되었습니다.
*(parr + 1)
은 parr[1]
을 역참조하는 것으로, parr[1]
또한 arr[1]
배열의 첫 번째 원소를 가리키는 포인터입니다.
parr
은 이중포인터라는 것을 이해하시면 도움이 되실 것 같습니다.
안녕하세요, 답변 도우미 Soobak 입니다.
제가 이전 답변에서 말씀을 조금 혼동을 드리게 드렸네요.
다시 명확하게 설명드리면 다음과 같습니다.
parr + 1
은 parr
배열의 두 번째 원소, 즉, parr[1]
을 가리키는 포인터의 주소입니다.
여기서, parr[1]
은 arr[1]
배열, 즉, {4, 5, 6}
배열의 첫 번째 원소인 4
의 주소를 가리키고 있습니다.
따라서, *(parr + 1)
은 parr[1]
과 같고, 4
의 주소를 가리키는 포인터입니다.
그렇기에, *(*(parr + 1) + 2)
와 같은 포인터 연산이 가능한 것입니다.
마지막에 말씀하신 parr[1]
자체의 주소와 관련된 말씀은 맞습니다.
답변 감사합니다.
중간에 말씀하신 parr[1]
이 포인터 변수명 인가요? 일단 변수명이라 생각하고 제 설명 드려보겠습니다.
parr + 1
은parr
배열의 두 번째 원소, 즉,parr[1]
을 가리키는 포인터의 주소입니다.
말씀하신 위의 부분을 아래의 그림으로 표현해봤습니다.
(주소값은 예시)
또한 parr[1]
은 arr[1]
배열 즉슨, 4
의 주소를 가리키므로
이렇게 될 것 같습니다.
하지만 *
는 간접 참조 연산자로서 주소로 접근하여 그 주소의 데이터(내용물)를 읽어온다는 걸로 알고있는데 그렇다면
*(parr + 1)
은 parr + 1
이라는 주소로 접근하여 그 옆에 있는 저장된 주소값인 104
를 가져오는데, 이는 어떤 포인터이거나 말씀하신 포인터변수parr[1]
가 되는 것 같아 보이지는 않습니다.
제가 *
의 역할에 대해 오해하고 있는 게 있을까요?
어디서부터 잘못 되었는지 정말 모르겠습니다...
안녕하세요, 답변 도우미 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 + 1
은 parr[1]
의 주소를 가리키는 포인터라는 것을 이해하시는 데에 도움이 되셨으면 좋겠습니다.
정리하자면,
parr
은 포인터의 배열이며, int*
자료형의 포인터들을 저장합니다.
parr + 1
은 parr
배열의 두 번째 원소(parr[1]
)의 주소를 가리킵니다. 즉, parr + 1
은 parr[1]
의 주소를 가리키는 포인터입니다.
*(parr + 1)
은 parr + 1
이 가리키는 주소에 있는 값, 즉, parr[1]
을 가져옵니다.
parr[1]
은 arr[1]
배열의 첫 번째 원소의 주소를 가리키는 포인터입니다.
따라서, *(parr + 1)
과 parr[1]
은 동일한 값을 나타내며, 이는 arr[1]
배열의 시작 주소입니다.
-추가 보충 설명-
오해하고 계신 부분을 점검하는 데에 도움을 드리기 위해, 각 변수들과 관계를 최대한 정리하여 설명드립니다.
arr
배열
arr
은 2차원 정수
배열 입니다.
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 + 1
은 parr
배열의 두 번째 원소인 parr[1]
의 주소를 나타내고, *(parr + 1)
은 parr[1]
의 값을 가져옵니다. 즉, *(parr +1)
은 parr[1]
이며, arr[1]
배열의 첫 번째 원소의 주소입니다.
요약
arr
은 2차원 배열
입니다.
parr
은 포인터의 배열
로, 각 포인터는 arr
의 각 행을 가리키는 포인터입니다.
혹시 이해가 안되시는 부분이 있으시면 편하게 댓글 남겨주세요.
정말 정말 정성스러운 답변 다시 한 번 감사합니다.
요약하자면,
parr
포인터 자체가 원래 parr[0]
의 주소를 담고있었는데
포인터 산술연산 +1
을 통해 주소를 int 자료형 크기만큼 건너뛰어가서
포인터 parr + 1
에 parr[1]
의 주소가 저장되도록 즉,
포인터 parr + 1
이 parr[1]
의 주소를 가리키게 했고
*
를 parr + 1
에 붙여서 ,*(parr + 1)
가 "arr[1](4의 주소)
라는 주소가 포인터에 저장된 즉, 이 주소를 가리키는 포인터변수 parr[1]
" 가 되도록 했다.
따라서 남아있는 것은 *(parr[1] + 2)
이 됐고
+2
라는 포인터 산술연산을 통해
포인터변수 parr[1]
안에 저장된 주소를 조정하여 목적지인
4
의 주소로 도달했고 *
를 통해 4를 읽어냈다.
라고하면 정확한 이해일까요?
안녕하세요, 답변 도우미 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 + 1
은 parr
배열의 두 번째 원소, 즉, parr[1]
의 주소를 가리킵니다.
그리고 *(parr + 1)
은 이 주소에 저장된 값을 역참조하여 가져옵니다. 이 값은 parr[1]
과 동일하며, arr[1]
배열의 시작 주소를 가리키고 있으므로, parr[1] + 2
는 arr[1]
배열의 세 번째 원소의 주소를 가리킵니다. 이 주소는 {4, 5, 6}
배열에서 6
의 위치입니다.
따라서, *(parr[1] + 2)
는 6
을 역참조하여 가져옵니다.
전에는 바로위의 수박님께서 말씀해주신 내용을 따라가다보면 자꾸 갓길로 빠져서 계속 도돌이표를 돌았는데 지금 보니 내용 그대로 납득이 잘 되는 것 같네요. 감사합니다 (_ _)
감사합니다
그렇다면 말씀하신 부분인
에서
(아래의 사진을 참고해주시면 감사하겠습니다.)
*(parr + 1)
가parr[1]
를 역참조하기 위해서는 주소인parr + 1
가parr[1]
의 주소여야 하는데지적해주신 것 처럼
4
의 주소이지는 않으니parr + 1
의 주소, 즉parr[1]
이 있는 곳의 주소는 12가 아닌 어디 다른 별도의 주소이다 라는 말씀인가요?