NULL

공부용·2025년 4월 3일

Null 사랑해~ Don't cry 김경현님

null이란 무엇인가?

화면상에 표시되지 않고 바이트 상으로 존재하는 제어 문자(control character)이다.

이러한 제어 문자는 컴퓨팅 및 전자통신 환경에서 사용되는 특별한 문자인데
출력 가능한 문자가 아닌, 컴퓨터나 장치에서 특수한 동작을 지시하는 문자를 말한다.

제어문자의미ASCII 코드 (10진수)
\n줄 바꿈 (new line)10
\t탭 (tab)9
\r캐리지 리턴 (carriage return)13
\b백스페이스8
\0널 문자 (null character)0

제어 문자 예시


메모리 관점에서 의미

#include <iostream>
using namespace std;

int main() {
    int* ptr = nullptr;
    cout << ptr << endl;
    return 0;
}

nullptr 출력

  • nullptr이 가리키는 주소는 0번 (0x0)을 나타낸다.
  • 보통 운영체제가 이 0번지 주소를 보호하여, 사용자가 접근하지 못하도록 한다.

null이 필요한 이유

명시적으로 해당 변수에 참조 없음을 표현하기 위함이다.

User user = null; // 아직 아무 사용자도 할당되지 않음

이처럼 null을 사용하면 코드 작성자의 의도를 명확히 표현할 수 있다.

예시 1: 조건 분기

if (cache == null) {
    cache = new Cache();  // 처음 접근할 때만 초기화
}

예시 2: 오류 탐지 및 예외 처리

String s = null;
s.length(); // NullPointerException 발생

예시 3: 기본값이나 종료 조건

Node current = head;
while (current != null) {
    current = current.next;
    // 연결 리스트나 트리 같은 자료구조에서 null은 끝을 나타낸다.
}
  • 의미 없는 값을 넣는 대신 null을 쓰면 메모리 절약에도 도움된다.

C에서의 null

null의 정의

#define NULL ((void *)0)
  • NULL은 C에서 널 포인터 상수를 의미한다.
  • stdio.h 헤더에 정의되어 있음.

포인터 초기화

int *ptr = NULL;

if (ptr == NULL) {
    printf("예외 처리\n");
}
  • 포인터를 NULL로 초기화하면 유효한 주소인지 쉽게 체크 가능.
  • 쓰레기 값을 가진 포인터를 사용하는 실수를 방지함.

NULL 포인터 역참조 시 오류

int *ptr = NULL;
printf("%d\n", *ptr);  // NULL 포인터 역참조 → Segmentation Fault 발생
  • 운영체제가 막아둔 0번 주소를 참조하려 해 오류 발생

NULL 체크 패턴

if (ptr != NULL) {
    printf("%d\n", *ptr);
} else {
    printf("포인터가 NULL입니다.\n");
}
  • 특히 malloc, calloc 사용 시 NULL 체크 필수
int *arr = malloc(sizeof(int) * 10);
if (arr == NULL) {
    // 메모리 할당 실패 처리
}

C++에서의 null

C++98: NULL 사용

#define NULL 0
  • NULL이 0으로 정의되어 오버로딩/템플릿에서 혼란 유발 가능

C++11 이후: nullptr 도입

NULL == 0 때문에 정수와 포인터 사이의 경계를 구분하기 어렵고, 오버로딩에서 문제가 발생하였다.
그래서 nullptr이라는 명확한 포인터 타입 리터럴이 도입되었다.

#include <iostream>
#include <cstddef>  // for std::nullptr_t

void func(int) {
    std::cout << "정수(int) 버전 호출됨\n";
}

void func(char*) {
    std::cout << "char* 포인터 버전 호출됨\n";
}

int main() {
    func(0);           // 출력: 정수(int) 버전 호출됨
    func(NULL);        // 출력: 정수(int) 버전 호출됨
    func(nullptr);     // 출력: char* 포인터 버전 호출됨
    return 0;
}

모호성 에러

  • C++에서 NULL은 컴파일러에 따라 ((void*)0) 또는 0으로 정의될 수 있어,
    func(NULL) 호출 시 어떤 함수를 선택해야 할지 모호해진다.
  • nullptr를 사용하면 이러한 모호성(ambiguity)을 피할 수 있다.

결론

포인터 초기화

int* ptr = nullptr;  // C++11 이후 권장
  • 포인터를 선언했으면 무조건 nullptr로 초기화하자.

null 체크는 반드시 하자

if (ptr != nullptr) {
    doSomething(ptr);
}
  • 포인터를 사용할 땐 항상 null인지 확인하자.

함수 인자로 포인터가 오면 null 가능성을 고려하자

void log(User* user) {
    if (user == nullptr) {
        std::cerr << "user is null!" << std::endl;
        return;
    }
    std::cout << user->name << std::endl;
}
  • 함수 안에서 nullptr 체크는 예외 안전성을 높여준다.

해제 후 null로 초기화

delete ptr;
ptr = nullptr;  // dangling pointer 방지
  • delete 후 포인터를 그대로 두면 사용자가 실수로 다시 접근할 가능성이 있다.
  • nullptr로 초기화해서 다시 접근 시 오류가 바로 나게 하자.

null? 더 이상 두렵지 않다.

profile
공부 내용을 가볍게 적어놓는 블로그.

4개의 댓글

comment-user-thumbnail
2025년 4월 3일

null 사랑해는 뭔가요🤷🏻‍♀️

1개의 답글
comment-user-thumbnail
2025년 4월 3일

따봉드립니다

1개의 답글