' 메모리의 실제 주소값 '
= 포인터 변수 = 주소값을 저장하는 변수 = '가리키는' 개념
실제로 프로그램이 변수에 있는 값을 가져올 때 값을 가져오는게 아니고 '공간'을 가져온다.
값을 가져온다 = 공간을 불러온다
int a= 5;
int *p = &a;
이런식으로 선언하면 a라는 변수가 메모리 상에 자리잡으면서 주소를 갖는다.
그리고 포인터는 이 주소값을 저장한다. (포인터 변수에는 참조연산자 *를 붙여 포인트 변수임을 선언하고 주소값을 저장할 때에는 변수 앞에 주소 연산자 &를 붙여준다)
a라는 변수의 주소값은 가진 포인터 p는 '5'를 가리킨다.
간접 참조(dereferencing, indirection) 연산자* = 역참조
또한, 포인터 변수의 주소를 담는 곳은 따로 저장 되며 (운영체제가 같으면) 그 크기는 모두 동일하다.
64비트에선 8바이트, 32비트에선 4바이트이다.
Q. 자료형에 따라 선언하는 자료형이 달라지는 이유?
A. 가리킬 주소가 어떤 자료형을 갖는지 알려주기 위해 -> int면 4바이트만큼, double이면 8바이트만큼
포인터는 주소값을 담는 변수이기 때문에 어떤 특정한 숫자로 초기화 할 수 없다.
숫자가 아닌 NULL(0)으로만 가능하다. (C++에선 nullptr)
Q. NULL과 nullptr의 차이는?
A. nullptr은 null pointer를 의미. C++에서 함수 오버로딩(함수 이름이 같으나 인자 갯수나 타입에 따라 특징이 다른 여러 함수들을 만드는 것)이라는 기능이 존재하는데 NULL은 0으로 정의되어 있어 int 타입으로 불러와짐 > 컴파일러에서 null포인터인지 정수 0인지 구분이 안되어 문제가 발생할 수 있다. nullptr은 포인터 모든 유형(int, double 등등)으로 변환하고 다른 기능을 차단한다고 함. 그래서 쓸 수 있다면 nullptr을 쓰는게 좋다.
연산자에는 우선순위가 있어서 증감연산자보다 참조 연산자의 우선순위가 높다
-->> 따라서 (p)++ 와 p++은 다른 결과값을 낸다
p++는 주소 값을 증가시킨거고 ( = 다음 주소값을 가져옴)
(p)++는 주소가 가리키는 값을 증가 시킨 것.
Q. 왜 굳이 포인터에 주소를 넣어서 사용하나?
A. 함수 때문. 함수에서는 인자를 전달할 때 복사해서 사용함 (call by value). 즉 전달하는 원래의 변수 값은 함수에서 수정할 수 없다. 그러나 포인터는 메모리의 주소로 넘기기 때문에 함수에서도 메모리에 직접적으로 참조할 수 있어서 변수의 값을 바로 수정해버린다 (call by reference).
C언어에서는 주소값 자체를 복사해서 넘겨주는 것이어서 call by address 방식이라고 한다. 근데 call by reference처럼 사용할 수 있다고 함. 일반적으로 C언어에서 함수 전달 방식은 call by value.
: 포인터가 가리키고 있던 메모리를 해제(delete) 후 다시 사용하는 것. 포인터는 메모리에서 할당되었던 영역을 가리키고 있을 것이다. 하지만 컴파일러는 그 주소에 다른 데이터를 놓을 수 있다. 따라서 포인터를 사용하게 되면 프로그램이 종료될 것이다.
const int *p1; // 1
int * const p2; // 2
const int * const p3; // 3
*p1 = 5; // 같은 문장은 불가능
p2 = &a // 같은 문장은 불가능.
( * )기호를 중심으로 const가 왼쪽에 있으면 객체가 변경되지 않는다는 의미. 오른쪽에 있으면 포인터 자체가 변경되지 않는다는 의미
const int *p1; // 가리키는 정수가 상수
int * const p2; // p2가 상수가 된다. 따라서 다른 것을 가리킬 수 없음
멤버 함수를 const로 정의하면 함수 안에서 멤버 변수 변경이 금지됨. const 객체를 가리키는 포인터를 정의하면 이 포인터로 호출할 수 있는 함수는 const 함수 뿐이다.
= 상수 객체에 대한 포인터를 선언하는 것은 이 포인터를 통해 상수 함수만 호출할 수 있다는 의미