C nullptr (C23)
Type-safe null pointer constant in modern C
🎯 What is nullptr?
The nullptr keyword in C23 provides a type-safe null pointer constant. Unlike NULL, nullptr has a distinct type and cannot be accidentally converted to integers.
#include <stdio.h>
int main() {
int* ptr = nullptr; // Type-safe null pointer
if (ptr == nullptr) {
printf("Pointer is null\n");
}
return 0;
}
nullptr Features
Type Safety
Cannot convert to integers
int x = nullptr; // Error!
Distinct Type
Has its own type: nullptr_t
nullptr_t null_val = nullptr;
Convertible
Converts to any pointer type
int* p = nullptr;
char* q = nullptr;
Comparable
Can compare with pointers
if (ptr == nullptr) { }
🔹 nullptr vs NULL
nullptr is a type-safe null pointer constant, while NULL is a traditional macro often defined as 0. nullptr prevents subtle type confusion bugs where NULL matches integer overloads unintentionally. Modern C standards prefer nullptr for type safety and clarity. NULL remains widely used for compatibility with existing code. Understanding differences helps write safer code and appreciate language evolution toward stronger type safety in null pointer handling.
#include <stdio.h>
#include <stddef.h>
void func_int(int x) {
printf("Called with int: %d\n", x);
}
void func_ptr(int* ptr) {
printf("Called with pointer: %p\n", (void*)ptr);
}
int main() {
// NULL can be ambiguous
// func_int(NULL); // This might work (NULL is often 0)
// func_int(nullptr); // Error: cannot convert nullptr to int
// Both work for pointers
int* p1 = NULL;
int* p2 = nullptr;
printf("NULL pointer: %p\n", (void*)p1);
printf("nullptr: %p\n", (void*)p2);
// Type safety demonstration
printf("sizeof(NULL): %zu\n", sizeof(NULL));
printf("sizeof(nullptr): %zu\n", sizeof(nullptr));
return 0;
}
Output:
NULL pointer: (nil) nullptr: (nil) sizeof(NULL): 8 sizeof(nullptr): 8
🔹 Using nullptr_t Type
The nullptr_t type represents the type of null pointer constants, enabling overload resolution. Functions can specifically accept nullptr_t parameters for null pointer-only overloads distinct from integers. This type enables powerful type-safe APIs preventing common null pointer handling mistakes. Understanding nullptr_t demonstrates advanced C features supporting modern programming patterns. Using these features creates robust code with compile-time safety guarantees.
#include <stdio.h>
#include <stddef.h>
// Function that accepts nullptr_t
void handle_null(nullptr_t null_val) {
printf("Received nullptr_t value\n");
// null_val is always nullptr
}
// Function overloading simulation with _Generic
#define process(x) _Generic((x), \
nullptr_t: handle_null, \
int*: handle_int_ptr, \
char*: handle_char_ptr \
)(x)
void handle_int_ptr(int* ptr) {
printf("Handling int pointer: %p\n", (void*)ptr);
}
void handle_char_ptr(char* ptr) {
printf("Handling char pointer: %p\n", (void*)ptr);
}
int main() {
nullptr_t my_null = nullptr;
int* int_ptr = nullptr;
char* char_ptr = nullptr;
// Using the generic macro
process(my_null); // Calls handle_null
process(int_ptr); // Calls handle_int_ptr
process(char_ptr); // Calls handle_char_ptr
return 0;
}
Output:
Received nullptr_t value Handling int pointer: (nil) Handling char pointer: (nil)
🔹 Practical Examples
The nullptr keyword in C is used to represent a null pointer value, providing a safer and more explicit way to initialize and check pointers. Unlike traditional NULL macro definitions, nullptr offers type safety and helps prevent common pointer-related bugs in modern C programming. For example, int *ptr = nullptr; clearly indicates that the pointer doesn't point to any valid memory location yet. This makes code more readable and helps developers quickly identify uninitialized pointers during debugging and code review processes.
#include <stdio.h>
#include <stdlib.h>
// Safe pointer checking function
bool is_valid_ptr(void* ptr) {
return ptr != nullptr;
}
// Dynamic memory allocation with nullptr checking
int* create_array(size_t size) {
if (size == 0) {
return nullptr; // Return nullptr for invalid size
}
int* arr = malloc(size * sizeof(int));
if (arr == nullptr) {
printf("Memory allocation failed\n");
return nullptr;
}
// Initialize array
for (size_t i = 0; i < size; i++) {
arr[i] = (int)i;
}
return arr;
}
int main() {
// Test with valid size
int* array1 = create_array(5);
if (array1 != nullptr) {
printf("Array created successfully\n");
for (int i = 0; i < 5; i++) {
printf("array1[%d] = %d\n", i, array1[i]);
}
free(array1);
array1 = nullptr; // Set to nullptr after freeing
}
// Test with invalid size
int* array2 = create_array(0);
if (array2 == nullptr) {
printf("Array creation failed as expected\n");
}
return 0;
}
Output:
Array created successfully array1[0] = 0 array1[1] = 1 array1[2] = 2 array1[3] = 3 array1[4] = 4 Array creation failed as expected
🔹 Best Practices
Following best practices when using nullptr ensures robust and maintainable C code that minimizes pointer-related errors. Always initialize pointers to nullptr when declaring them if they won't immediately point to valid memory. Before dereferencing any pointer, check if it's nullptr to avoid segmentation faults and undefined behavior. Use nullptr instead of NULL or 0 for better code clarity and type safety. Additionally, set pointers to nullptr after freeing dynamically allocated memory to prevent dangling pointer issues that could lead to security vulnerabilities or program crashes.
nullptr Best Practices:
- Use nullptr instead of NULL: For better type safety
- Initialize pointers: Always initialize pointers to nullptr
- Check before use: Always check if pointer != nullptr
- Set after free: Set pointers to nullptr after freeing memory
- Function parameters: Use nullptr_t for functions that only accept null
// Good practices with nullptr
#include <stdio.h>
#include <stdlib.h>
int main() {
// Initialize to nullptr
int* ptr = nullptr;
// Allocate memory
ptr = malloc(sizeof(int));
if (ptr != nullptr) {
*ptr = 42;
printf("Value: %d\n", *ptr);
// Free and nullify
free(ptr);
ptr = nullptr; // Prevent dangling pointer
}
// Safe to check again
if (ptr == nullptr) {
printf("Pointer is safely null\n");
}
return 0;
}