C
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions
-
Section 4: Arrays and Strings
-
Section 5: Pointers
-
Section 6: Memory Management
-
Section 7: Structures and Unions
-
Section 8: The Preprocessor and Build Process
-
Section 9: Standard Library: stdio.h
-
Section 10: Standard Library: stdlib.h
-
Section 11: Standard Library: string.h
-
Section 12: Standard Library: ctype.h and wctype.h
-
Section 13: Standard Library: math.h, complex.h, fenv.h, tgmath.h
-
Section 14: Standard Library: Type and Limit Headers
-
Section 15: Standard Library: Error Handling and Debugging
-
Section 16: Standard Library: Localization and Encoding
-
Section 17: Standard Library: time.h
-
Section 18: Standard Library: Concurrency (C11)
-
Section 19: POSIX and System Programming (unistd.h)
-
Section 20: More Data Structures
-
Section 21: Algorithms in C
-
Section 22: Bitwise Operations
-
Section 23: Command-Line Programs
-
Section 24: Debugging and Best Practices
-
Section 25: Compiler and Language Internals
-
Section 26: Embedded and Cross-Platform Considerations
-
Section 27: Networking Basics
-
Section 28: Practical Projects
-
Section 29: Interview Practice
-
Section 30: C23 Modern Features
-
Section 31: More Practice and Review
242: The nullptr Constant
Imagine you're managing a restaurant. You have a dozen tables, and each table is meant to hold a party of guests. Now, if a table is currently empty, you don't just leave it blank—because a blank table looks like it's ready for anyone to sit down. Instead, you place a "Reserved" sign on it. That sign isn't a guest, and it's not a piece of food; it's a specific marker that tells your staff, "There is intentionally nobody here right now."
In C, nullptr is that "Reserved" sign. For a long time, we used NULL or just the number 0 to indicate that a pointer wasn't pointing to anything useful. But the problem with 0 is that it's an integer. If you have a function that can take either an integer or a pointer, the compiler might get confused about whether you're passing the number zero or a null pointer. nullptr solves this by being a distinct type that says, "I am definitely a pointer, and I am definitely pointing to nothing."
Why we stopped just using zero
If you've looked at older C code, you'll see NULL everywhere. In most implementations, NULL is just a macro for ((void*)0). While that worked for decades, it's a bit clunky. By introducing nullptr (starting in C23), the language finally gives us a first-class keyword that the compiler understands natively.
I've spent way too many hours debugging "ambiguous overload" style issues where the compiler thought I was passing an int when I actually meant "no object." Using nullptr removes that ambiguity. It's type-safe. When you see nullptr, you know exactly what's happening: the pointer is intentionally empty.
Putting it into practice
Let's look at a scenario where this is actually useful. Suppose you're writing a function to find a specific user in a list. If the user doesn't exist, you can't return a valid user pointer, so you return nullptr.
struct User {
int id;
char name[50];
};
struct User* find_user_by_id(struct User* list, int size, int target_id) {
for (int i = 0; i < size; i++) {
if (list[i].id == target_id) {
return &list[i]; // Found them!
}
}
// We searched the whole list and found nothing.
// Return nullptr to explicitly say "Not Found".
return nullptr;
}
int main() {
struct User users[] = {{1, "Alice"}, {2, "Bob"}};
struct User* result = find_user_by_id(users, 2, 99);
if (result == nullptr) {
// This is the "Reserved" sign. We know there's no user here.
printf("User not found.\n");
} else {
printf("Found: %s\n", result->name);
}
return 0;
}
The logic of the null check
You'll notice the if (result == nullptr) check. This is the most critical part of working with pointers. If you tried to access result->name without checking if result was nullptr first, the program would attempt to read memory at address zero, and the OS would immediately kill your process with a Segmentation Fault. I've crashed more programs in my early career by forgetting this check than I care to admit. Always check for nullptr before dereferencing.
📋 Practical Task
The Missing Employee Lookup
You are building a small HR system. You have a function called get_employee_by_role that should search an array of employees and return a pointer to the one matching a specific role (e.g., "Manager"). If no one has that role, the function must return nullptr.
Your Task: Complete the code below. Implement the get_employee_by_role function to iterate through the array and return the correct pointer or nullptr. In main, ensure you handle the nullptr case so the program doesn't crash when a role is not found.
#include <stdio.h>
#include <string.h>
struct Employee {
int id;
char role[20];
};
struct Employee* get_employee_by_role(struct Employee* staff, int count, const char* target_role) {
// TODO: Implement search logic
// Return the pointer to the employee if found, otherwise return nullptr
}
int main() {
struct Employee staff[] = {
{101, "Developer"},
{102, "Designer"},
{103, "Developer"}
};
const char* search_role = "CEO"; // This role doesn't exist in our list
struct Employee* emp = get_employee_by_role(staff, 3, search_role);
// TODO: Check if emp is nullptr before printing
// If it is nullptr, print "No employee found with that role."
// Otherwise, print the employee's ID.
return 0;
}
There are no comments for now.