포인터란
메모리 주소를 저장하는 변수이다.
일단 포인터는 변수이다. 그냥 단순하게 주소를 저장하는 변수이다.
포인터는 프로그래밍에서 참조라는 뜻을가진다. 변수에 직접적으로 접근하지 않고, 주소를 통해 접근 한다.
포인터선언
자료형* 변수명;
간단하게 자료형 뒤에 *만 붙여주면된다
*은 에스크리터 라고 읽는다.
포인터를 선언하면 포인터에 주소를 넘겨줘야하는데 이때는 &변수명을 붙여주면된다.
&은 어드레스 연산자라고 읽는다.
void main()
{
int a = 10;
int* ptr = &a;
cout << *ptr << endl;
}
이런 식으로 선언하고 주소를 담는다.
cout << *ptr << endl;
*ptr은 역참조 연산자이다 해당 포인터가 가리키는 주소의 값을 반환한다. ptr은 a의 주소를 가리키고있고
a의 주소는 10이다. *ptr은 a의 10을 반환하게된다.
포인터 선언 주의사항
int* ptr;
이런식으로 선언을 하게되면 문제가 생기는데 바로 쓰레기 값이 들어가기 때문이다.그냥 일반적인 변수에는 그냥 쓰레기 값이 들어갈 뿐이지만 이게 포인터라면 문제가 생길 수 있다.
이유는 포인터는 쓰레기 값이 주소이기 때문이데 포인터가 우리가 지정하지 않은 이상한 곳을 지정하고 있기 때문인데
포인터가 우연히 운영체제의 중요한 위치를 쓰레기 값으로 받아버리게 되면 우리는 윈도 운영체제의 값을 변경하게 되고 상당히 큰 문제가 발생할 수 있다.
다만 요즘 운영체제는 할당받지 않은 메모리가 접근 시도할 경우 해당 프로그램을 강제로 종료시키기 때문에
이런 문제는 생기지 않지만 그래도 항상 조심해야 된다.
그래서 만약 포인터에 아무런값을 넣고싶지 않을경우에는
int* ptr1 = 0;
int* ptr2 = nullptr;
이런 식으로 해주면 되지만 그냥 일반적으로 0을 하면 이게 나중에 포인터인지 아닌지 확인이 어려울 수 있으니
nullptr로 해주는게 좋다.
포인터의 크기
포인터의 크기는 어떠한 자료형이든 4bytes의 크기를 가진다.
이유는 개발 환경인 32bits 개발환경 때문인데
32bits 운영체제에서 가용할 수 있는 메모리의 크기는 4기가 이다.
포인터는 1byte당 하나의 주소가 할당되니 4기가를 byte단위로 변환하면 약 42억9천만개의 주소가 나온다.
각 주소를 저장하기 위해서 필요한 크기는 최대 4bytes의 공간만 있으면 저장이 가능하다. 만약 2bytes라면
해당 메모리르 전부 가용할수 없을것이다. 왜냐하면 포인터의 담을 수 있는 크기가 2기가 밖에 안되기 때문이다.
만약 64bits운영체제 라면 포인터의 크기는 8bytes가 된다.
포인터의 데이터값 알아보기
만약 int*가 float의 주소를 가리키면 어떻게 될까?
float의 주소와 int의 주소는 같은 크기를 가지고 똑같은 16진수 표기법이다.
하지만 int*에 &float를 할당할려고 하면 에러가 발생한다.
이유는 무엇일까? 바로 포인터는 주소뿐만 아니라 주소가 가리키고있는 해당 값또한 보기 때문이다.
int와 float는 같은 형식의 주소방식이지만 데이터값을 실수와 정수로 완전 다르다. 포인터는 대입을 할때
이런 부분도 확인하기 때문에 되지 않는다.
포인터의 형변환
위에서 포인터는 대입할때 해당 데이터값도 본다고 하였다. 그러면 만약 실수형 변수를 정수형 포인터에 대입할때
형변환을 하여 대입하면 어떻게 될지 알아보자
void main()
{
double value = 5;
int* ptr;
ptr = (int*)&value;
cout << *ptr << endl;
}
ptr에 value를 넣고 빌드하면 아무런 애러가 발생하지 않는다. 하지만 결과를 출력하면 0이 나올것이다.
이상하다 분명 포인터는 가리키는 주소의 데이터값을 가져온다고 하였는데
일단 여기서 잘못된게 하나있는데 포인터는 가리키는 주소의 데이터값을 가져오는게 아니다.
포인터는 자료형에 따라서 해당되는 메모리의 값이 출력되는 것이다.
int 포인터면 첫 4byte의 값
char 포인터면 첫 1byte의 값
long long 포인터면 첫 8byte의 값이 표현되는것이다.
그래도 이상하다 아무리 그래도 0이 출력되는건 이상하다.
이유는 다음과 같다.
위에서 말한것처럼 포인터는 자료형에 따라서 해당 메모리의 값을 출력한다.
즉 5가 아닌 자료형을 기준 4byte를 출력하게되는데
double형인 value의 5를 비트로 표현 하면
5는 101(2진수)
1.01x2(2) 2의 2승
double형 가수부는 52bit로 소수점앞의 1은 버리고 01에 나머지 0을 50개로 채우게 됩니다.
지수부는 11bit로 1023 bias에 2승니니까 2를 더하면 1025가 되는데
이를 2진수소 표기하면 100 0000 0001이 됩니다.
부호는 1bit로 0이 되지요
즉 value는
부호 1bit(0)
지수부 11bit(100 0000 0001)
가수부 52bit(01 0...0) 01 다음 0 연속 50개
합쳐셔 표기하면 0100 0000 0001 010...001 이렇게 표기된다.
메모리는 이를 거꾸로 표현하게 되는데 이를 거꾸로 표기하면
00000000
00000000
00000000
00000000
00000000
00000000
00101000
00000010
int*는 처음의 4byte인 0으로 표현된 32bit의 값을 가르키고 있어 해당 값은 0이 출력되는것이다.
'C++' 카테고리의 다른 글
C++ 문자열 함수 (0) | 2020.08.31 |
---|---|
C++ char*와char[] (0) | 2020.08.28 |
C++ Reference (0) | 2020.08.24 |
C++ 연산자 (0) | 2020.08.14 |
C++ 진수 (0) | 2020.08.14 |