오븐 노트

[C++] 포인터 마무리 본문

Develop/C++

[C++] 포인터 마무리

오 븐 2022. 7. 15. 23:24

포인터나 참조처럼 주소를 다룰때는 그 주소가 정말 끝까지 유효한지 항상 습관처럼 생각하고 있어야하며

어지간해서는 스택에서 스택과 관련된 데이터의 주소를 바깥으로 넘겨주려는 행동은 조심해야함

스택에서만 존재하는 값의 주소를 외부로 가져간다는것 자체가 말이 안되고 절대 하면 안되는 행위

항상 함수와 주소의 생명 주기를 생각하고 있어야함

#include <iostream>
using namespace std;

// 포인터나 참조처럼 주소를 다룰때는 그 주소가 정말 끝까지 유효한지 항상 습관처럼 생각하고 있어야하며
// 어지간해서는 스택에서 스택과 관련된 데이터의 주소를 바깥으로 넘겨주려는 행동은 조심해야함
// 스택에서만 존재하는 값의 주소를 외부로 가져간다는것 자체가 말이 안되고 절대 하면 안되는 행위
// 항상 함수와 주소의 생명 주기를 생각하고 있어야함

int& TestRef()
{
	int a = 1; // 사실상 스택에서 값이 날아감
	return a; // 사실상 스택에서 값이 날아감
}

int* TestPointer()
{
	int a = 1; // 사실상 스택에서 값이 날아감
	return &a; // 사실상 스택에서 값이 날아감
}

void TestWrong(int* ptr)
{
	int a[100] = {}; // crash test를 위해 임의로 만든 영역
	a[99] = 0xAAAAAAAA;
	*ptr = 0x12341234; // 현재 함수와는 아무런 관계가 없는 외부에서 가져온 메모리를 수정하려하지만 사실 자기 자신의 스택 프레임
						// 때문에 현재 스택 프레임에 있는 a[100]이라는 배열의 메모리를 건들게됨
						// debug 모드에서는 crash가 잡혔지만 relese 모드에서는 넘어가버림
}

int main()
{
	// 주소를 담는 바구니 실데이터는 X
	// p는 단지 그 주소로 이동하기 위한 이동 수단
	int* p;

	// 실 데이터가 존재
	// 데이터의 묶음 (포인터에 비해 거대함)
	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8 };

	// 많은 사람들이 배열 == 포인터라 착각하는 경향을 가지는 이유
	// - [배열의 이름]은 배열의 시작 주소값을 가리키는 TYPE* 포인터로 변환이 가능
	p = arr;

	// - [TYPE형 1차원 배열]과 [TYPE*형 포인터]는 완전히 호환이 된다
	cout << p[0] << endl;
	cout << arr[0] << endl;
	cout << p[5] << endl;
	cout << arr[5] << endl;
	cout << *p << endl; // p[0]
	cout << *arr << endl; // arr[0]
	cout << *(p + 3) << endl;
	cout << *(arr + 3) << endl;

	// 2차원 배열 vs 다중 포인터

	// [1][2][3][4]
	int arr2[2][2] = { {1, 2}, {3, 4} };

	// 다중 포인터
	// pp[ 주소1 ]
	// 주소1[ 주소2 ]
	// 주소2[] << 4바이트 (32bit 운영체제 기준)
	int** pp = (int**)arr2;
	// 위와 같은 경우
	// pp[ 주소1 ]
	// 주소1[ 00000001(배열 첫 값) ]
	// 주소2[] << 4바이트 (32bit 운영체제 기준)
	cout << (**pp) << endl;
	// 포인터는 한번 더 이동을 해야하지만 저장된 값이 주소값이 아닌 배열에 저장한 1 이라는 값이므로 크래시 발생

	// 배열 == TYPE name[개수]
	// [ 주소 ]
	// [1][2] [3][4]
	// 결국 [1]의 주소값, [3]의 주소값 순서로 저장되어있음
	// 사실상 거의 쓰이지 않는 문법이긴함
	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;

	// crash test
	int* pointer = TestPointer();
	*pointer = 123; // 엉뚱한 메모리 값을 건드리고 있음에도 불구하고 함수 내부 스택에서 설정해준 값이 스택에서 날아갔기 때문에 문제가 없이 넘어가버림
	TestWrong(pointer);

	return 0;
}

[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part1: C++ 프로그래밍 입문 - 인프런 | 강의
 
C++ 카테고리의 글은 인프런 Rookiss님의 강의를 공부하며 정리하는 내용입니다.
이미 알고 있는 내용도 다시 정리 되어있을 수 있습니다.

 

모든 글은 제가 공부하기 위해 작성합니다.

'Develop > C++' 카테고리의 다른 글

[C++] 연습 문제 (문자열) #1 ~ 2  (0) 2022.08.16
[C++] TextRPG #3  (0) 2022.08.13
[C++] 다차원 배열  (0) 2022.07.15
[C++] 다중 포인터  (0) 2022.07.14
[C++] 로또 번호 생성기  (0) 2022.07.13