작성
·
412
·
수정됨
2
*(parr[j] + i)과 *(*(parr + j) + i))는 어느정도 이해를 했습니다.
예를 들면
*(parr[0] + 1)
parr[0]에 담긴 데이터는 주소이고 그 주소는 arr0이라는 포인터와 비슷한 무언가를 가리킨다.
그리고 arr0이라는 포인터와 비슷한 무언가는 arr0[0]의 주소를 가리킨다.
그리고 arr0[0]은 arr0의 첫 번째 공간을 의미한다.
그러므로 parr[0]은 arr0[0]을 가리키는 것이고 parr[0]에 1을 더하면 arr0[0]의 다음 공간인 arr0[1]을 가리키게 되고
*로 그 공간에 접근하게 된다.
*(*(parr + 1) + 1)
parr은 arr0을 가리킨다. 그리고 arr0은 arr0[0]을 가리킨다.
그러므로 parr에 1을 더하면 arr0[1]을 가리키게 된다.
거기에 *를 붙이면 arr0[1]의 공간에 있는 데이터에 접근을 한다.
거기서 1을 더하면 그 데이터에 1을 더하게 되는 것이다.
이렇게 이해를 했는데 맞는거겠죠?
이거 말고 질문이 있는데
parr[j][i]와 (*(parr + 1))[1]의 맨앞에 *가 없는데도 어떻게 그 공간에 접근해서
printf 함수로 출력을 했을 때 배열의 주소가 아닌 배열의 데이터가 출력 될 수 있는 건지 궁금합니다.
parr[j]는 배열의 주소가 나오는데 parr[j][i]는 왜 배열의 값이 나오는지 이해가 안되요.
감사합니다
답변 3
3
안녕하세요, 답변 도우미 Soobak 입니다.
질문 1)
| (parr[j] + i)과 (*(parr + j) + i))는 어느정도 이해를 했습니다. 예를 들면 (parr[0] + 1) parr[0]에 담긴 데이터는 주소이고 그 주소는 arr0이라는 포인터와 비슷한 무언가를 가리킨다. 그리고 arr0이라는 포인터와 비슷한 무언가는 arr0[0]의 주소를 가리킨다. 그리고 arr0[0]은 arr0의 첫 번째 공간을 의미한다. 그러므로 parr[0]은 arr0[0]을 가리키는 것이고 parr[0]에 1을 더하면 arr0[0]의 다음 공간인 arr0[1]을 가리키게 되고 로 그 공간에 접근하게 된다. ((parr + 1) + 1) parr은 arr0을 가리킨다. 그리고 arr0은 arr0[0]을 가리킨다. 그러므로 parr에 1을 더하면 arr0[1]을 가리키게 된다. 거기에 *를 붙이면 arr0[1]의 공간에 있는 데이터에 접근을 한다. 거기서 1을 더하면 그 데이터에 1을 더하게 되는 것이다.
이렇게 이해를 했는데 맞는거겠죠?
: 네, 거의 올바르게 이해하셨지만, 약간의 혼동이 있으신 것 같아 명확히 해드리도록 하겠습니다.
*(parr[0] + 1)
parr[0]
은 arr0
을 가리키는 포인터입니다.
parr[0] + 1
은 arr0
배열의 두 번째 원소(arr0[1]
)를 가리킵니다.
*(parr[0] + 1)
는 arr0[1]
의 값을 의미합니다.
*(*(parr + 1) + 1)
parr
자체는 포인터의 배열을 가리키는 포인터, 즉, 이중 포인터입니다.
parr + 1
은 두 번째 배열 포인터, 즉, arr1
을 가리킵니다.
*(parr + 1)
은 arr1
배열 자체를 가리킵니다.
*(parr + 1) + 1
은 arr1
배열의 두 번째 원소(arr1[1]
)를 가리킵니다.
*(*(parr + 1) + 1)
는 arr1[1]
의 값을 의미합니다.
즉, parr
은 포인터의 배열을 가리키는 이중 포인터이며, parr + j
는 j
번째 배열을 가리키는 포인터를 의미합니다.
따라서, *(*(parr + j) + i)
는 j
번째 배열의 i
번째 원소의 값을 의미합니다.
질문 2)
| parr[j][i]와 (*(parr + 1))[1]의 맨앞에 *가 없는데도 어떻게 그 공간에 접근해서
printf 함수로 출력을 했을 때 배열의 주소가 아닌 배열의 데이터가 출력 될 수 있는 건지 궁금합니다.
parr[j]는 배열의 주소가 나오는데 parr[j][i]는 왜 배열의 값이 나오는지 이해가 안되요.
: 가장 뒤의 []
인덱스 접근 연산자의 의미에 대해서 생각해보시면 좋을 것 같습니다.
보충 설명을 드리면 다음과 같습니다.
parr[j][i]
의 동작 방식parr
는 이중 포인터이며, 포인터의 배열을 가리킵니다. 여기서, 각 포인터는 다른 배열을 가리킵니다. (arr0
, arr1
등)
이 때, parr[j]
는 j
번째 배열을 가리키는 포인터입니다. 따라서 parr[j]
자체는 주소를 나타냅니다.parr[j][i]
는 j
번째 배열의 i
번째 요소에 접근합니다.parr[j]
가 배열의 주소를 가리키므로, [i]
를 추가하면 그 배열의 i
번째 요소에 접근하는 것이 됩니다.
결과적으로, parr[j][i]
는 주소가 아닌 해당 배열의 i
번째 요소의 값을 나타냅니다.
(*(parr + j))[i]
의 동작 방식
parr + j
는 parr
이 가리키는 배열의 j
번째 포인터를 가리킵니다.
즉, 이는 parr[j]
와 동일합니다.*(parr + j)
는 j
번째 배열 자체를 의미합니다. 여기서, 이 배열은 parr[j]
가 가리키는 배열과 동일합니다.(*(parr + j))[i]
는 *(parr j)
가 가리키는 배열의 i
번째 요소에 접근하는 것입니다.
이는 parr[j][i]
와 동일한 방식으로 동작합니다.
결과적으로, 이 표현은 배열의 i
번째 요소의 값을 나타내게 됩니다.
따라서, parr[j][i]
나 (*(parr + j))[i]
모두 배열의 주소가 아닌, 배열의 특정 요소의 값에 접근합니다.parr[j]
는 이중 포인터이기 때문에 주소를 반환하지만, parr[j][i]
는 그 주소가 가리키는 배열의 i
번째 요소의 값을 반환합니다.
따라서, printf()
와 같은 함수를 사용할 때 배열의 데이터 값을 출력할 수 있는 것입니다.
혹시, 잘 이해가 안되시거나 어려우신 부분 있으시면 편하게 댓글 남겨주세요.
네, 그렇게 이해하시는 것도 정확합니다.
배열의 이름은 그 배열의 첫 번째 원소의 주소를 가리키는 포인터와 호환이 되는 형태라는 점을 생각해보시면 좋을 것 같습니다.int arr0[3] = {1, 2, 3};
, int arr1[3] = {4, 5, 6};
그리고 int* parr[2] = {arr0, arr1}
에서,parr
은 배열의 이름이므로, 배열의 첫 번째 원소 arr0
의 주소를 가리킵니다.
마찬가지로, parr[0]
은 arr0
을 가리키는 포인터입니다.
즉, parr[0]
은 arr0
배열의 첫 번째 원소인 arr[0]
의 주소를 가리키고 있습니다.
좋은 질문해주셔서 저 또한 감사드립니다.
혹시 이해가 안되시거나 어려우신 부분있으시면 편하게 댓글 남겨주세요.
또 질문해서 정말 죄송합니다. 복습 하다 보니 이해가 안 가는 부분이 또 생겨 질문 드립니다.
parr도 arr0을 가리키고 parr[0]도 arr0을 가리키는데
parr에 1을 더하면 arr1을 가리키고 parr[0]에 1을 더하면 arr0[1]을 가리키는 게 혼동이 돼서 이해가 잘 안됩니다.
한번 더 알려주시면 정말 감사하겠습니다.
여러가지 개념이 혼동되어서 너무 어렵네요
배열의 이름은 배열의 첫 번째 공간의 주소라는 걸 기억해내면
parr은 arr0을 가리키는 거고, parr[0]은 arr0[0]을 가리키는 거다.
라고 해석이 가능할 것 같은데 선생님은 parr[0]이 arr0을 가리키는 포인터라고 하셨으니 틀린 해석 인걸까요?
질문해주셔서 감사합니다. 질문은 편하게 해주세요!
학습에 있어서 이해가 어려운 부분을 명확히 하는 것이 중요한 것 같습니다.
parr
과 parr[0]
이 가리키는 대상에 대해서 설명드립니다.
parr
은 int*
타입의 포인터들을 원소로 가지는 배열입니다.
즉, parr
자체는 int*
타입의 포인터를 가리키는 포인터 배열의 시작 주소입니다.
(이 부분이 이중 포인터 개념 때문에 조금 복잡할 수 있으나, 차근 차근 이해해보시면 생각보다 어렵지 않은 내용입니다!)
parr
에 1
을 더했을 때의 동작
: parr
에 1
을 더하면, parr
은 다음 int*
타입의 포인터 원소를 가리키게 됩니다.
이 때, 배열의 포인터 연산은 해당 배열의 원소 타입의 크기에 따라서 주소가 이동한다는 점이 중요합니다.parr
배열의 원소 타입은 int*
이므로, parr + 1
은 arr1
을 가리키는 포인터의 위치로 이동합니다.
반면, parr[0]
은 int*
타입이며, arr0
배열의 첫 번째 원소, 즉, arr0[0]
의 주소를 가리킵니다.
parr[0]
에 1
을 더했을 때의 동작
: parr[0]
에 1
을 더하면, parr[0]
은 arr0
배열의 다음 원소인 arr0[1]
을 가리키게 됩니다.
여기서 중요한 점은, 위에서 강조드렸던 부분, 즉, parr[0]
의 타입이 int*
이기 때문에, 포인터 연산은 int
타입의 크기만큼 주소가 이동한다는 것입니다.
즉, parr[0] + 1
은 arr0[1]
의 주소를 가리키게 됩니다.
"parr 은 arr0 을 가리키는 거고, parr[0] 은 arr0[0] 을 가리키는 거다." 라고 해석하신 부분 역시 옳습니다.
parr
은 int*
타입의 포인터들을 원소로 가지는 배열의 이름입니다.
이 배열에서 parr
자체는 포인터 배열의 첫 번째 원소인 arr0
의 주소를 가리키는 포인터입니다.
즉, parr
은 arr0
을 가리키고 있으며, 이는 arr0
이라는 배열의 시작 주소와 동일합니다.
반면, parr[0]
은 포인터 배열의 첫 번째 원소로, arr0
의 주소를 저장하고 있는 int*
타입의 포인터입니다.parr[0]
이 가리키는 대상은 arr0
배열의 첫 번째 원소, 즉, arr0[0]
입니다.
따라서, parr
은 arr0
배열을 가리키는 포인터입니다.(보다 명확히는, 배열의 이름은 포인터와 호환이 되는 형태라는 표현이 맞지만, 이해의 편의를 위해 여기서는 포인터라고 하겠습니다.)parr[0]
역시 arr0
배열을 가리키며, 동시에 배열의 첫 번째 원소인 arr[0]
의 주소를 가리킵니다.
이렇게, parr
과 parr[0]
은 같은 메모리 주소를 가리키더라도, 타입이 다르기 때문에 포인터 연산의 결과도 달라지게 되는 것입니다.
혼동하기 쉬운 부분이므로, 자신감을 가지시고 충분히 이해하고 넘어가시는 것이 좋습니다.
추가 질문이 있으시면 언제든지 물어보세요.
선생님 parr[0]은 arr0을 가리킨다고 하면 이해가 잘 안되고
parr이 arr0을 가리키고 parr[0]은 arr0이라고 하면 이해가 잘 돼요.
제가 틀린걸까요?
항상 답변 정말정말 감사합니다.