본문 바로가기

널 포인터 (Null pointer) 본문

💘 C++/행렬, 문자열, 포인터, 참조

널 포인터 (Null pointer)

Hyonii 2022. 7. 8. 13:30

Null values and Null pointers

일반 변수와 마찬가지로 포인터는 인스턴스화 될 때 초기화되지 않는다.

값이 할당되지 않으면 포인터는 기본적으로 어떤 쓰레기 주소를 가리킨다.

 

포인터의 위험성 중 쓰레기 주소 값이 들어간 경우, de-referencing을 시도하게 되면 

실제 메모리에 데이터가 잘 담겨있는 것이 아니라서, 엉뚱한 곳에 가서 데이터를 찾기 때문에

OS가 문제가 있다고 경고한다고 앞 포스팅에서 말씀드렸다.

이런 문제를 방지하기 위해서 null pointer라는 것을 사용한다. 

 

메모리 주소 외에도 포인터가 저장할 수 있는 값이 하나 있다. 바로 null 값이다.

null 값은 포인터가 아무것도 가리키지 않는다는 것을 의미하는 특수 값이다.

null값을 가진 포인터를 null pointer라고 한다.


null pointer 사용법

 

C-style에서는 포인터로 null 값을 지정하려면 선언할 때 0을 넣어준다.

 

이렇게 NULL을 넣어주기도 한다.

그리고 최근에 Modern C++ Style로는 nullptr 이라는 것이 있다.

 

이걸 많이 사용한다.

어떻게 작동하냐면

 

이런식으로 쓰인다.

nullptr이 아닐 경우에만 ptr이 의미가 있기 때문에 쓸모있는 작업을 하라고 하는 거고

nullptr이 들어왔으면 이 포인터 값이 제대로 들어온 주소가 아니니까 아무것도 하지 말아라 하는 용도로 쓰인다.

 

초기화하는 방법은 다른 변수와 같다.

 

uniform initialization도 가능하다

또는

 

이렇게 0을 넣기도 한다.

0도 많이 쓰였지만 앞으로는 nullptr 쓰는 게 좋을 것 같다.

 

값 0은 포인터 유형이 아니므로 포인터가 null 포인터임을 나타내기 위해서 포인터에 0을 할당하는 것은 일관성이 없다.

드문 경우이지만, 리터럴 0을 사용할 경우 컴파일러에서 null 포인터를 의미하는지 정수 0을 의미하는지 확인할 수 없으므로 문제가 발생할 수 있다.

doSomething(0);

이러한 문제를 해결하기 위해 C++11 에서는 nullptr이라는 새로운 키워드를 도입했다.

nullptr은 true, false와 같은 불린 키워드와 마찬가지로 키워드 및 r-value 상수이다.

int *ptr{ nullptr }; //ptr is still an integer pointer, just set to a null value

C++은 암시적으로 nullptr을 포인터 모든 유형으로 변환한다.

따라서 위의 예제에서 nullptr은 암시적으로 정수 포인터로 변환된 다음, nullptr 값이 ptr에 할당된다.

이것은 정수 포인터 ptr을 널 포인터로 만드는 효과가 있다.


nullptr 리터럴로 함수를 호출하는 데에도 사용할 수 있다.

함수 파라미터로 넘어갈 때 유용하다.

 

얘가 제대로 된 값을 받았는지 안받았는지 이런식으로 확인해 볼 수 있다.

함수를 만들고

 

이 코드를 실행시켜 보면

변수에 주소를 직접 넣어도 잘 작동하고, 

포인터 변수에다가 d의 주소를 넣고 그 ptr을 넣어줘도 잘 작동하는 것을 볼 수 있다.

 

C++11 에서는 nullptr을 사용해서 포인터를 null 값으로 초기화하자.

 


std::nullptr_t in C++ 11

C++은 <cstddef> 헤더에 있는 std::nullptr_t라는 새로운 유형을 도입했다.

 

nullptr_t에 뒤에 붙은 _t는 type이라는 의미다.

std::nullptr_t는 nullptr 하나의 값만 가질 수 있다.

 

이것은 nullptr 인자를 받아들이는 함수를 작성할 때 

std::nullptr_t 타입의 매개 변수를 만들어서 쓸 수 있다.

 


포인터 변수의 주소를 찍어보면 어떻게 나올까?

 

함수에 double의 포인터가 들어오고 있다.

그럼 이 포인터 변수의 주소를 찍어보자

 

main()에 한번 찍어보고
함수에서도 찍어보자
주소가 다르게 나오는 것을 볼 수 있다.

지난 포스팅에서

이 파라미터로 넘어오는 변수는 다시 선언이 되고,

거기에 argument로 들어온 변수에 들어있는 값이 복사가 되는 것이라고 말씀드렸다.

그래서 함수에 있는 double *ptr은

 

main에 있는 ptr과는 다른 메모리를 쓰는 것이다.

포인터도 결국 변수이고, 함수로 넘어오면서 메모리값이 다시 복사가 되는 것이다.

nullptr 값이 다시 복사가 되고,

double d가 정의가 되어있는 메모리의 주소 값이 값 자체가 다시 복사가 된다는 또 다른 증거다.

알아두면 도움되니까 잘 알아두자.

Comments