배열 vs 포인터
배열 이름은 자신의 시작 주소를 의미하고 포인터와 동일한 문법을 사용할 수 있지만, 배열은 포인터처럼 어떠한 주소를 저장하는 용도로는 사용하지 못한다.
2차원 배열 vs 다중 포인터
int arr2[2][2] = { {1, 2}, {3, 4} };
int** pp = arr2; // 컴파일 에러
int** pp = (int**)arr2;
cout << (**pp) << endl; // 런타임 에러
// pp에는 arr2의 시작 주소가 들어있고, arr2의 시작 주소로 가서 int*을 기대했는데, 1이 들어있었고, 이를 int*로 해석하여 주소 1에 접근하다가 크래시가 남.
int* p = arr2; // 컴파일 에러
int(*p2)[2] = arr2; // 이전 차원에 대한 크기를 요구하는 이유는 추측컨대, 어셈블리 코드에서 초기 주소를 계산할 때 필요하기 때문인 듯하다.
cout << (*p2)[0] << endl;
cout << (*p2)[1] << endl;
cout << (*(p2 + 1))[0] << endl;
cout << (*(p2 + 1))[1] << endl;
cout << p2[0][0] << endl;
cout << p2[0][1] << endl;
cout << p2[1][0] << endl;
cout << p2[1][1] << endl;
int* TestPointer()
{
int a = 1;
return &a;
}
void TestWrong(int* ptr)
{
int a[100] = {};
a[99] = 0xAAAAAAAA;
*ptr = 0x12341234;
}
int main()
{
int* pointer = TestPointer();
TestWrong(pointer);
}
디버그 모드에서 스택을 cc로 초기화하는 것은 스택 프레임을 정리하는 과정에서 엉뚱한 메모리를 덮어쓴 것에 대해 크래시를 내주기 위해 컴파일러가 추가해주는 꼼수이다. (Stack around the variable 'a' was corrupted.)
릴리즈 모드에서는 엉뚱한 스택 메모리를 덮어쓴다고해서 일부러 크래시를 내주지 않는다.