강의보고 공부한 것을 정리하는 목적으로 작성된 글이므로 틀린점이 있을 수 있음에 양해부탁드립니다.
(피드백 환영입니다)
이때까지 우리는 함수로 지역변수의 원본에 접근하여 값을 바꿔 줄 수 있는 방법이 없었다.
왜냐하면 값이 복사되어서 들어가는 방식이였기 때문이다.
이럴때 그 값의 원본에 접근하여 줄 수 있는 것이 포인터(pointer)이다.
[타임]* [이름];
int* ptr;
포인터는 이러한 형태로 선언이 된다.
*(애스터리스크)가 들어가면 포인터로 생각을 하면된다.
포인터는 간단하게 주소값을 담는 바구니라고 생각을 하면된다.
그리고 포인터 변수의 크기는 얼마일까? 라는 생각을 해보면
포인터는 주소를 담고 있는 변수이기 때문에 주소의 크기가 얼마인가?에 대해 생각을 해야하는데
이 주소의 크기는 프로그램이 실행되는 환경에 따라 다르다.
요즘에는 거의 대부분 64비트 환경에서 동작이 될 것인데 이러한 경우에는 8바이트이다.(32비트 환경이라면 4바이트)
즉 64비트 환경에서 포인터변수의 크기는 8바이트 인것이다.(앞에 타입은 중요하지 않다)
int hp = 100;
int* ptr = &hp;
이런식으로 &(엔드)를 사용하게되면 변수의 주소값을 알려달라는 것과 같기에 저런식으로 포인터에 주소값을 넣어주면 된다.
그럼 여기서 의문이 들 수 있는데 포인터의 크기는 자기 컴퓨터의 비트 환경에 따라 달라지는데 왜 타입을 선언하지? 라는 생각을 할 수 있다.
포인터에서 타입은 주소값을 타고 가면 -> 무엇이 있는가? (어떤 데이터가 저장 되어 있는가?)를 타입으로 나타내어 주는 것이라고 볼 수 있다.
int hp = 100;
int* ptr = &hp;
여기서는 포인터가 "hp로 넘어가면 int타입의 데이터가 있을꺼야!"라는 주장을 해주는 것이라고 볼 수 있다.
그럼 어떻게 접근하는냐?
포인터를 선언할 때 처럼 *를 사용하여 접근할 수 있다.
접근 후 일반 변수처럼 사용해주면 된다.
int hp = 100;
int* ptr = &hp;
*ptr = 120;
cout << *ptr << endl;
이것을 역참조라고 부른다.
만약 우리가 가르키는 주소에는 int타입이 있는데 포인터를 float로 선언하고 float로 캐싱을 하여 실행시켜본다면 이상한 값이 뜰 것이다.
왜냐하면 컴파일러는 분명 주소에 접근하면 float가 있을 것이라고 생각하고 값을 float의 방식으로 컴파일했는데 막상 int타입이 있으니 이상한 값이 나올 수 밖에 없을 것이다.
하지만 int와 float는 그나마 값의 크기가 다르지 않아서 다행이지만 만약에 나중에
struct타입을 만들었는데 막 몇백 바이트를 차이가 나버려서 초과해 훼손시켜버린다면 난리가 나버릴 것이다.
그래서 타입을 지정할 때는 조심해줘야 한다.