int main()
{
int numArr[5] = {11, 22, 33, 44, 55}
void *ptr = *numArr[2];
printf("%d\n", *(int *)ptr); // 33
printf("%d\n", *((int *)ptr + 1)); // 44
printf("%d\n", *((int *)ptr - 1)); // 22
여기까지는 알겠고
printf("%d\n", *(++(int *)ptr)); // 44 여기도 알겠는데
printf("%d\n", *(--(int *)ptr)); 이거는 // 33이 아니라 22가 되야하지 않나요??
그리고
printf("&d\n", *(((int *)ptr)++)); // 이거는 후위연산자라 33인 거 같은데
그렇다면
printf("%d\n", *(((int *)ptr)--)); //이것도 33이 되야하는 거 같은데 왜 44로 늘어나는지 모르겠어요.
printf("%d\n", *((int*)ptr + 1)); // 44
printf("%d\n", *((int*)ptr - 1)); // 22
printf("%d\n", *(++(int*)ptr)); // 44
printf("-------%d\n", *(int*)ptr);
printf("%d\n", *(--(int*)ptr)); // 33
printf("-------%d\n", *(int*)ptr);
printf("%d\n", *(((int*)ptr)++)); // 33
printf("-------%d\n", *(int*)ptr);
printf("%d\n", *(((int*)ptr)--)); // 44
printf("-------%d\n", *(int*)ptr);
-------44
33
-------33
33
-------44
44
-------33
-------44
33
-------33
33
-------44
44
-------33
"++ptr이나 ptr++은 ptr의 값 자체를 바꿉니다."
이 말을 이해하고 나서
printf("%d\n", *(++(int*)ptr)); // 44
printf("-------%d\n", *(int*)ptr);
printf("%d\n", *(--(int*)ptr)); // 33
printf("-------%d\n", *(int*)ptr);
이것은 이해가 되었습니다.
하지만
printf("%d\n", *(((int*)ptr)++)); // 33
printf("-------%d\n", *(int*)ptr);
printf("%d\n", *(((int*)ptr)--)); // 44
printf("-------%d\n", *(int*)ptr);
이것은 아직 이해가 되지 않습니다..
정답은 33 44인데
#include <stdio.h>
int main()
{
int numArr[5] = { 11, 22, 33, 44, 55 };
void *ptr = &numArr[2]; // 두 번째 요소의 메모리 주소
printf("%d\n", *(int *)ptr); // 33: 포인터 연산을 하지 않은 상태에서 역참조
// void 포인터를 다른 포인터로 변환하여 포인터 연산을 한 뒤 역참조
printf("%d\n", *((int *)ptr + 1)); // 44
printf("%d\n", *((int *)ptr - 1)); // 22
printf("%d\n", *(++(int *)ptr)); // 44
printf("%d\n", *(--(int *)ptr)); // 33
printf("%d\n", *(((int *)ptr)++)); // 33
printf("%d\n", *(((int *)ptr)--)); // 44
return 0;
}
그림으로 그려서 이해하세요.
예제 자체가 하나씩 하는 게 아니라 계속 ptr에 연산한 결과가 누적되어서 헷갈리는 것 같습니다.
int numArr[5] = { 11, 22, 33, 44, 55 };
void *ptr = &numArr[2]; // 두 번째 요소의 메모리 주소
printf("%d\n", *(int *)ptr); // 33: 포인터 연산을 하지 않은 상태에서 역참조
여기까지의 상태는
그림으로 그리세요.
가로로 그려도 되지만, 이해하기 쉽게 세로로 그렸습니다.
가로나 세로나 상관없습니다.
// void 포인터를 다른 포인터로 변환하여 포인터 연산을 한 뒤 역참조
printf("%d\n", *((int *)ptr + 1)); // 44
ptr+1이 먼저 계산되고 역참조를 하니까 44입니다.
근데 여기서 중요한 것은 ptr은 값이 안 바뀌었습니다.
printf("%d\n", *(int *)ptr);
이거 다시 출력하면 33 나옵니다.
printf("%d\n", *((int *)ptr + 2)); // 55
당연하지만 ptr+2 역참조하면 55 나옵니다.
ptr 값은 안 바꿨어요.
printf("%d\n", *((int *)ptr - 1)); // 22
ptr -1을 역참조하니까 당연히 22입니다.
ptr 값이 안 바뀌었어요.
printf("%d\n", *((int *)ptr - 2)); // 11
ptr-2 역참조해서 찍어봐요. 11 나오지. ptr은 여전히 33을 가리킵니다.
printf("%d\n", *(++(int *)ptr)); // 44
전위 연산자는 값을 바꾸죠? 포인터 연산에서는? 한 칸 이동하는 겁니다.
++ 전위 연산자썼으니까 뒤로 한 칸 이동합니다.
이제 ptr은 44를 가리킵니다. 아까처럼 이 상태에서 ptr+1 역참조하면 55 나오고, ptr -1 역참조하면 33 나옵니다. ptr + 2 역참조하면 참조할 게 없으니까 에러나거나 쓰레기값이 나오거나 하겠지요. 하면 안 되는 코드. 범위를 벗어난 접근이죠.
printf("%d\n", *(--(int *)ptr)); // 33
ptr이 지금 44를 가리키는 상태에서 -- 전위 연산자이니까 한 칸 앞으로 이동한 결과를 ptr에 저장됩니다. 그러니까 이제 ptr은 33을 가리킵니다.
다시 예제 처음처럼 ptr은 33을 가리키는 상태.
printf("%d\n", *(((int *)ptr)++)); // 33
이건 후위 연산자입니다. 후위 연산자는 '계산을 나중에 한다'는 뜻입니다.
따라서 ptr을 역참조하면 현재 위치이니까 33이 나옵니다.
printf 다음에 ptr은 한 칸 뒤로 이동합니다.
printf 출력하고 나중에 ptr++ 처리했으니까 내부에서는 이제 44를 가리킵니다.
이제 ptr은 44를 가리키는 상태인데 또 ptr--로 후위 연산자입니다. 즉, 참조는 먼저하고 계산은 나중에 한다는 뜻이죠.
printf("%d\n", *(((int *)ptr)--)); // 44
ptr 참조해서 44는 출력했고, 이제 -- 연산을 하니까 내부에서는 ptr이 33을 가리키는 상태가 됩니다.
예제 코드 마지막에
printf("%d\n", *(int *)ptr);
이게 출력해서 다시 찍어보면 33입니다.
각 단계별로 그림으로 그려보세요. 그림으로 그릴 수 없으면 이해 못한 겁니다.
머릿속으로 이해? 그건 천재나 가능한 겁니다. 천재 아니면 범재면 그림으로 그리세요. 전 그림으로 그려서 이해하고, 그림으로 그려서 설명합니다.
천재들끼리만 '말로 설명하고 머릿속으로 이해'할 수 있는 겁니다.
그림으로 그리세요.
예제가 6개 출력문을 다 짬뽕해서 그런 건데, 모르겠으면 2개씩 다 나눠서 따로따로 예제 실습하고, 그림으로 그려서 이해하세요.
+1 하지 말고 +2도 해서 살펴보고, 에러로 일부러 만들어보고, 경고문 뜨나, 쓰레기 값이 나오나보세요. 근데 이건 컴파일러 구현체에 따라 다른 거라서 믿으면 안 됩니다. 정의되지 않은 동작(undefined behavior)입니다. 컴파일러마다 동작이 다르다는 뜻이죠.