주소를 저장하는 변수
char* pChar = nullptr;
short* pShort = nullptr;
int* pInt = nullptr; // = 0
nullptr은 아무것도 안들어감 = 0
int형 포인터 변수이다.
int i = 100;
int* pInt = &i; // &는 주소값 표현
(*pInt) = 200; // 변수앞에 * 가지고있는 주소값을 찾아감
주소의 단위는 byte 단위로 이동
주소를 표현하는 방식은 정수 로 표현
따라서 비트 단위로 표현 불가능
주소값 이후에 어느정도가 변수의 바이트 인지 모르기때문에 지정해서 가지고있음
그래서 포인터 변수를 사용할때 그뒤에 얼마만큼 읽을지 설정하기 위해서 변수형으로 선언
int i = sizeof(int*);
// i == 8
만약 32비트 기반 이라면 4이다.
int i = 0;
int* pInt = &i;
pInt += 1;
만약에 주소 값이 100인 i가있고 주소 값을 += 해주면 101 이 아니고 다음 주소값 104이다.
int형이 4byte이고 주소 표현 방식만 정수표현만 따르고
계산은 다르다. 즉 +=는 값을 1 증가 하는게 아니다고 다음 번지수로 가는것이다.
만약 char* 일경우 1주소값이 증가하는것 처럼 자료형 사이즈 크기로 증가한다
pInt 는 int* 변수 이기 때문에, 가르키는 곳을 int로 해석한다.
주소값을 1증가는 다음 int로 접근을 위해 사이즈 크기 단위로 증가하게 된다.
배열의 특징은 메모리가 연속적인 구조이다.
배열의 이름은 배열의 시작 주소 값이다 메모리가 연속 적이기 때문이다.
int iArr[10] = {};
*(iArr + 0) = 1;
*(iArr + 1) = 10; // iArr[1] = 10; 이랑 같은 말이다. 편의성을 위에 주석으로 된걸 많이 쓴다.
// iArr + 1 할경우에는 결국 위에 처럼 사이즈 크기 4증가 이다.
*(iArr + 1) = 10; 인경우 주소값 찾기로 인해서 2번째 칸에 10이 들어간다.
const는 constant의 약자로 명사형 사전적 의미로 "상수"를 뜻합니다.
C++에서 const는 그 대상을 변경하지 않는 "상수"를 의미한다.
포인터 변수와 const가 만나면 상황이 생기는데
본인이 const 포인터 변수가 된다면 가르키는 대상을 변경할수가없다
int a = 0;
const int* pConstInt = &a;
int const* p = &a; // 의미는 위랑 같다. 원본을 바꿀수가 없는것이다.
*pConstInt = 100; // 여기서 에러 난다.
int b = 0;
pConstInt = &b;
const int* pConstInt = 인 경우에는 값이 변경 할수가없고 지칭하는 대상을 바꾸는건 가능하다.
바라보는 변수 원본이 상수화 된다.
int a = 0;
int* const pConstInt = &a;
*pConstInt = 100;
int b = 0;
pConstInt = &b; // 여기서 에러난다.
값의 원본은 수정 가능 하고 하지만 바라 보는 대상에 주소 값을 변경할수가없다.
포인터 변수 자체가 상수화 되는거랑 바라보는 변수를 상수화 시킬수 있다.
const int* const pConstIntConst = nullptr;
이런 경우에는 값을 바꿀수도 없고 바라보는 주소 값을 변경 할수도없다.
int a = 0;
const int* pConstInt = &a;
a = 100; // 포인터 변수가 제한을 두더라도 그건 포인터가 자신이 사용하는 곳에 제약을 위해 둔거
원본 인 int a 변수는 그대로 일반 변수 처럼 사용 가능하고
pConstInt는 사용하는곳에서 제한을 두기 위해서 사용하는것이다.
만약 함수나 이런것에서 데이터 을 받아올때
전달할때 데이터 복사가 일어난다.
그러고 함수 처리후 복사된 데이터는 삭제 된다.
그러면 데이터크기가 엄청 클경우 렉이 걸릴수도있고 문제가 발생하거나
메모리 포퍼먼스가 엄청 떨어진다.
이럴때 포인터로 전달해야하는 값의 주소 값만 매겨 변수로 받아오면 직접 가서 데이터 변경 처리 할수도있다.
이렇게 쉽다면 다행이지만 이경우 생각해봐야한다.
만약 전달 하는 데이터 주소 값을 주는경우 함수 안에서 또 예상하지 못한 데이터 처리 라든지 등등 발생할수있다.
그래서 만약 읽기만 하거나 그렇게 사용하려면 이런씩으로 해야한다.
void Output(const int* pI) { // 상수화 시켜서 받았앗다.
int i = *pI; //값은 읽을수있지만
*pI = 100; // 변경은 할수 없다 여기서 에러가 일어난다.
}
}
int main() {
int a = 0;
Output(&a);
return 0;
}
함수로 포인터 을 가지고 가고싶고 그값을 읽기용으로만 사용할때 const int* 등등 으로 선언해주면 보는사람이나 다른사람도 이해가 쉽다.
보통 함수를 만들면 void 함수명() {} 으로 많이들 사용하는걸 봤을껀데
void* pVoid = nullptr;
int a = 0;
float f = 0.0f;
double d = 0.4f;
long long ll = 0;
pVoid = &a;
pVoid = &f;
pVoid = &d;
pVoid = ≪
이라고 선언을 할수도있다.
보통 자료형의 원본을 변수형에 지정을 해주는데 int나 float 등등
void 는 존재 하지 않는건데 그걸 포인터로 활용은
주소를 저장하는 변수는 맞지만 원본으로 접근할때 int인지 short인지 정하지않은 포인터 변수이다.
그래서 모든 변수들의 주소 값을 받을수있지만
역 참조를 할수가 없다. 왜냐면 무슨 타입인지 자료형을 정해지지 않아서 주소값 뒤에 얼마의 길이를 가지고 볼수 있는지 모른다.
역시 주소 연산도 할수가 없다.