Short answer: it depends on a lot of factors, including the compiler, processor architecture, specific processor model, and the OS, among others.

Long answer (x86 and x86-64): Let's go down to the lowest level: the CPU. On x86 and x86-64, that code will typically compile into an instruction or instruction sequence like this:

movl $10, 0x00000000

Which says to "store the constant integer 10 at virtual memory address 0". The Intel® 64 and IA-32 Architectures Software Developer Manuals describe in detail what happens when this instruction gets executed, so I'm going to summarize it for you.

The CPU can operate in several different modes, several of which are for backwards compatibility with much older CPUs. Modern operating systems run user-level code in a mode called protected mode, which uses paging to convert virtual addresses into physical addresses.

For each process, the OS keeps a page table which dictates how the addresses are mapped. The page table is stored in memory in a specific format (and protected so that they can not be modified by the user code) that the CPU understands. For every memory access that happens, the CPU translates it according to the page table. If the translation succeeds, it performs the corresponding read/write to the physical memory location.

The interesting things happen when the address translation fails. Not all addresses are valid, and if any memory access generates an invalid address, the processor raises a page fault exception. This triggers a transition from user mode (aka current privilege level (CPL) 3 on x86/x86-64) into kernel mode (aka CPL 0) to a specific location in the kernel's code, as defined by the interrupt descriptor table (IDT).

The kernel regains control and, based on the information from the exception and the process's page table, figures out what happened. In this case, it realizes that the user-level process accessed an invalid memory location, and then it reacts accordingly. On Windows, it will invoke structured exception handling to allow the user code to handle the exception. On POSIX systems, the OS will deliver a SIGSEGV signal to the process.

In other cases, the OS will handle the page fault internally and restart the process from its current location as if nothing happened. For example, guard pages are placed at the bottom of the stack to allow the stack to grow on demand up to a limit, instead of preallocating a large amount of memory for the stack. Similar mechanisms are used for achieving copy-on-write memory.

In modern OSes, the page tables are usually set up to make the address 0 an invalid virtual address. But sometimes it's possible to change that, e.g. on Linux by writing 0 to the pseudofile /proc/sys/vm/mmap_min_addr, after which it's possible to use mmap(2) to map the virtual address 0. In that case, dereferencing a null pointer would not cause a page fault.

The above discussion is all about what happens when the original code is running in user space. But this could also happen inside the kernel. The kernel can (and is certainly much more likely than user code to) map the virtual address 0, so such a memory access would be normal. But if it's not mapped, then what happens then is largely similar: the CPU raises a page fault error which traps into a predefined point at the kernel, the kernel examines what happened, and reacts accordingly. If the kernel can't recover from the exception, it will typically panic in some fashion (kernel panic, kernel oops, or a BSOD on Windows, e.g.) by printing out some debug information to the console or serial port and then halting.

See also Much ado about NULL: Exploiting a kernel NULL dereference for an example of how an attacker could exploit a null pointer dereference bug from inside the kernel in order to gain root privileges on a Linux machine.

Answer from Adam Rosenfield on Stack Overflow
Top answer
1 of 5
76

Short answer: it depends on a lot of factors, including the compiler, processor architecture, specific processor model, and the OS, among others.

Long answer (x86 and x86-64): Let's go down to the lowest level: the CPU. On x86 and x86-64, that code will typically compile into an instruction or instruction sequence like this:

movl $10, 0x00000000

Which says to "store the constant integer 10 at virtual memory address 0". The Intel® 64 and IA-32 Architectures Software Developer Manuals describe in detail what happens when this instruction gets executed, so I'm going to summarize it for you.

The CPU can operate in several different modes, several of which are for backwards compatibility with much older CPUs. Modern operating systems run user-level code in a mode called protected mode, which uses paging to convert virtual addresses into physical addresses.

For each process, the OS keeps a page table which dictates how the addresses are mapped. The page table is stored in memory in a specific format (and protected so that they can not be modified by the user code) that the CPU understands. For every memory access that happens, the CPU translates it according to the page table. If the translation succeeds, it performs the corresponding read/write to the physical memory location.

The interesting things happen when the address translation fails. Not all addresses are valid, and if any memory access generates an invalid address, the processor raises a page fault exception. This triggers a transition from user mode (aka current privilege level (CPL) 3 on x86/x86-64) into kernel mode (aka CPL 0) to a specific location in the kernel's code, as defined by the interrupt descriptor table (IDT).

The kernel regains control and, based on the information from the exception and the process's page table, figures out what happened. In this case, it realizes that the user-level process accessed an invalid memory location, and then it reacts accordingly. On Windows, it will invoke structured exception handling to allow the user code to handle the exception. On POSIX systems, the OS will deliver a SIGSEGV signal to the process.

In other cases, the OS will handle the page fault internally and restart the process from its current location as if nothing happened. For example, guard pages are placed at the bottom of the stack to allow the stack to grow on demand up to a limit, instead of preallocating a large amount of memory for the stack. Similar mechanisms are used for achieving copy-on-write memory.

In modern OSes, the page tables are usually set up to make the address 0 an invalid virtual address. But sometimes it's possible to change that, e.g. on Linux by writing 0 to the pseudofile /proc/sys/vm/mmap_min_addr, after which it's possible to use mmap(2) to map the virtual address 0. In that case, dereferencing a null pointer would not cause a page fault.

The above discussion is all about what happens when the original code is running in user space. But this could also happen inside the kernel. The kernel can (and is certainly much more likely than user code to) map the virtual address 0, so such a memory access would be normal. But if it's not mapped, then what happens then is largely similar: the CPU raises a page fault error which traps into a predefined point at the kernel, the kernel examines what happened, and reacts accordingly. If the kernel can't recover from the exception, it will typically panic in some fashion (kernel panic, kernel oops, or a BSOD on Windows, e.g.) by printing out some debug information to the console or serial port and then halting.

See also Much ado about NULL: Exploiting a kernel NULL dereference for an example of how an attacker could exploit a null pointer dereference bug from inside the kernel in order to gain root privileges on a Linux machine.

2 of 5
6

As a side note, just to compel the differences in architectures, a certain OS developed and maintained by a company known for their three-letter acronym name and often referred to as a large primary color has a most-fasicnating NULL determination.

They utilize a 128-bit linear address space for ALL data (memory AND disk) in one giant "thing". In accordance with their OS, a "valid" pointer must be placed on a 128-bit boundary within that address space. This, btw, causes fascinating side effects for structs, packed or not, that house pointers. Anyway, tucked away in a per-process dedicated page is a bitmap that assigns one bit for every valid location in a process address space where a valid pointer can lay. ALL opcodes on their hardware and OS that can generate and return a valid memory address and assign it to a pointer will set the bit that represents the memory address where that pointer (the target pointer) is located.

So why should anyone care? For this simple reason:

int a = 0;
int *p = &a;
int *q = p-1;

if (p)
{
// p is valid, p's bit is lit, this code will run.
}

if (q)
{
   // the address stored in q is not valid. q's bit is not lit. this will NOT run.
}

What is truly interesting is this.

if (p == NULL)
{
   // p is valid. this will NOT run.
}

if (q == NULL)
{
   // q is not valid, and therefore treated as NULL, this WILL run.
}

if (!p)
{
   // same as before. p is valid, therefore this won't run
}

if (!q)
{
   // same as before, q is NOT valid, therefore this WILL run.
}

Its something you have to see to believe. I can't even imagine the housekeeping done to maintain that bit map, especially when copying pointer values or freeing dynamic memory.

Top answer
1 of 8
118

A NULL pointer points to memory that doesn't exist. This may be address 0x00000000 or any other implementation-defined value (as long as it can never be a real address). Dereferencing it means trying to access whatever is pointed to by the pointer. The * operator is the dereferencing operator:

int a, b, c; // some integers
int *pi;     // a pointer to an integer

a = 5;
pi = &a; // pi points to a
b = *pi; // b is now 5
pi = NULL;
c = *pi; // this is a NULL pointer dereference

This is exactly the same thing as a NullReferenceException in C#, except that pointers in C can point to any data object, even elements inside an array.

2 of 8
56

Dereferencing just means accessing the memory value at a given address. So when you have a pointer to something, to dereference the pointer means to read or write the data that the pointer points to.

In C, the unary * operator is the dereferencing operator. If x is a pointer, then *x is what x points to. The unary & operator is the address-of operator. If x is anything, then &x is the address at which x is stored in memory. The * and & operators are inverses of each other: if x is any data, and y is any pointer, then these equations are always true:

*(&x) == x
&(*y) == y

A null pointer is a pointer that does not point to any valid data (but it is not the only such pointer). The C standard says that it is undefined behavior to dereference a null pointer. This means that absolutely anything could happen: the program could crash, it could continue working silently, or it could erase your hard drive (although that's rather unlikely).

In most implementations, you will get a "segmentation fault" or "access violation" if you try to do so, which will almost always result in your program being terminated by the operating system. Here's one way a null pointer could be dereferenced:

int *x = NULL;  // x is a null pointer
int y = *x;     // CRASH: dereference x, trying to read it
*x = 0;         // CRASH: dereference x, trying to write it

And yes, dereferencing a null pointer is pretty much exactly like a NullReferenceException in C# (or a NullPointerException in Java), except that the langauge standard is a little more helpful here. In C#, dereferencing a null reference has well-defined behavior: it always throws a NullReferenceException. There's no way that your program could continue working silently or erase your hard drive like in C (unless there's a bug in the language runtime, but again that's incredibly unlikely as well).

Discussions

What happens when dereferencing a nullptr?
Dereferencing a null pointer is undefined behavior. In practice, trying to dereference null usually results in a seg-fault, but sometimes the compiler can optimize out the operation entirely. In your example, *p == true; doesn't actually change any of the program state, so the compiler is being smart and removing the extra computation. In the cout line, your program is actually using the result of the computation so it can't be removed. Note: In some cases an aggressive optimizer may recognize that dereferencing a null pointer would be undefined behavior and assume that the pointer therefore cannot be null. This can lead to some unintuitive and hard to find bugs. More on reddit.com
🌐 r/cpp_questions
20
14
August 18, 2022
Dereferencing a pointer to save it's value before setting the pointer to NULL
C is not devious the way you think that it is. Instead, C is vicious and uncaring in ways that you have not yet imagined. There is no risk to copying an invalid address, or even a valid address. The copies don't change, nor do they deteriorate. This is why "NULL pointers" are a thing. The null address is invalid, and if you try to access it your program will immediately crash. But as long as all you do is copy it without trying to access it, nothing bad happens! In your case, you have POSITION *tmp = curr->next; curr->next = NULL; return tmp; This is perfectly valid code, and works in exactly the way you intend it to work. If curr->next contains NULL, this code will work. If it contains an invalid address, this code will work. If it contains exactly the right answer, this code will work. Because you are not "dereferencing" the pointer (address). All you are doing is copying it from one place to another. I'm not sure what language you are coming from. But in C, assignment and initialization are the same - you are copying bits into a named space. It is definitely not the case that initializing a variable to another variable makes them synonyms, or pointers to the same "bucket", or anything like that. Variables are fully distinct in C, and when you use an initializer or a "bare" assignment(*) you are overwriting whatever previous value might have existed. The only way to get the hinky "action at a distance" effect you are afraid of is to use pointers. But it's only the pointed-to thing that can be changed. So: curr->next = &(POSITION){.x=12}; // This is valid C11 code. It creates a "temporary" object with element "x" assigned 12, everything else 0 POSITION *tmp = curr->next; print(tmp->x); // 12 print(curr->next->x); // 12 curr->next->x += 3; // Because of pointers, this is a "shared" change print(tmp->x); // 15 curr->next = NULL; print(tmp->x); // 15 print(curr->next); // NULL POSITION * tmp2 = curr->next; // You can initialize using a NULL value POSITION * tmp3 = tmp; // You can initialize using a non-NULL value tmp3 = tmp2; // You can assign using a NULL value print(tmp); // 0xDEADBEEF (some random address in memory) print(tmp2); // NULL (still no problem "passing" (copying) a null value) print(tmp3); // NULL (still good) print(curr->next->x); // Segmention fault. Core dumped. (Game over: You cannot "dereference" (access) through a NULL value.) We pretend there is a function called "print" that amazingly does what you expect it to. Ignore that part. You can see in the "upper" parts of the example that (1) tmp is initialized to the same pointer that curr->next has. Thus, while the two variable tmp and curr->next are separate memory locations, they both refer to the same location because they are pointers that have the same value. I then modify the ->x value, which modification will be visible through both variables because the variables are pointers referring to the same target object. Then I set one of the variables to NULL. That breaks the symmetry, since now one variable refers to the position object, but the other does not. But it's still okay to hold a NULL value, and it's okay to initialize with a NULL values, and it's okay to copy a NULL value from one variable to another. But it's not okay to "dereference" a NULL value.(**) That is, you may not try to fetch the memory at location 0, nor at any location close to 0(***). When you do, that's the end. ====== (*) "bare" assignment is just a simple "=" sign. Not "+=" or "/=" or "->=" (which doesn't exist but should!) or any of the other "compound assignment" operators. (**) This is not really true. On embedded systems it is frequently necessary to operate on memory at or near location 0. But you have to know what you're doing, and if you don't you can really screw things up. On desktop and server systems, it is possible to operate on memory at or near location 0. But we have adopted this convention "as a society" that zero means "probably an error," and the developers and vendors of operating systems, compilers, development tools, etc., have agreed to support that beneficial convention, to the extent that they now enforce the rule because it probably indicates a programming error. (***) A "struct" in C is a collection of logically related data that may be of the same or different types. It is implemented as named elements that are located in close proximity to each other in memory. The struct has a base address and internally is accessed using offsets relative to the base address. Thus, on a 32-bit system, a simple POSITION linked list might have elements next, x, y with offsets of 0, 4, and 8 bytes (since pointers and ints are 32-bits) respectively. You know that accessing memory address 0 is forbidden. But because someone might try to do POSITION *tmp = NULL; print(tmp->y) in their code, and generate an access to memory at location 0 + 8, modern system forbid access to memory anyplace near location 0. Usually that means a "page" at location 0 and maybe one page at the "top" of memory, where location -1 would be. More on reddit.com
🌐 r/cprogramming
5
2
May 24, 2021
Dereferencing null pointers - what does the standard say?
https://eel.is/c++draft/class.mfct.non-static If a non-static member function of a class X is called for an object that is not of type X, or of a type derived from X, the behavior is undefined. More on reddit.com
🌐 r/cpp_questions
40
14
April 20, 2021
what happened when dereference a null pointer
First, let's clear the easy: and whats the actual memory layout of a null pointer? The memory layout of a pointer, like for any value, depends only on its type, and does not depend on the current value stored inside it. That is, on a 64-bits machine, *mut T is 8 bytes (64 bits), regardless of whether it is null or not. i wonder what happened when i try to deref a null pointer at virtual memory address 0x0, at the low level? It depends upon the platform (combination of hardware, OS and run-time) that you are using. On a typical x64 computer, running Unix or Windows, the OS apportions virtual memory in pages of various sizes. On modern Linux, the typical sizes are 4 KB (normal), 2 MB (large), and 1 GB (huge). Since null-pointer dereferences are such a common issue, a common mitigation is to leave the first (few) pages of virtual memory unmapped. That is, the virtual memory page at address 0x0 is not mapped to a range of RAM. This uses the fact that when looking up memory, the CPU will need to map the virtual memory address to a real address in RAM to fetch the actual content. If no mapping exists, the CPU will raise a specific signal (Segmentation Fault) which will interrupt the program and, typically, will be handled by the OS. Here be dragons I did mention mitigation above. If, for example, you create a large slice with a null pointer and a large size, then the address 0x0 is not accessed itself, instead, when accessing slice[8192], the address 0x0 + 8192 is accessed. It may jump "past" the mitigation area, and not be detected. Also, the rules of the language mention that 0x0 is NOT a valid pointer to dereference, allowing the optimizer to assume it will never happen... which speeds up programs, at the cost of potentially unexpected behavior. I'll let Chris Lattner, from LLVM fame, explain the latter in detail: What every C programmer should know about Undefined Behavior 1/3 What every C programmer should know about Undefined Behavior 2/3 What every C programmer should know about Undefined Behavior 3/3 More on reddit.com
🌐 r/rust
11
3
May 18, 2020

Short answer: it depends on a lot of factors, including the compiler, processor architecture, specific processor model, and the OS, among others.

Long answer (x86 and x86-64): Let's go down to the lowest level: the CPU. On x86 and x86-64, that code will typically compile into an instruction or instruction sequence like this:

movl $10, 0x00000000

Which says to "store the constant integer 10 at virtual memory address 0". The Intel® 64 and IA-32 Architectures Software Developer Manuals describe in detail what happens when this instruction gets executed, so I'm going to summarize it for you.

The CPU can operate in several different modes, several of which are for backwards compatibility with much older CPUs. Modern operating systems run user-level code in a mode called protected mode, which uses paging to convert virtual addresses into physical addresses.

For each process, the OS keeps a page table which dictates how the addresses are mapped. The page table is stored in memory in a specific format (and protected so that they can not be modified by the user code) that the CPU understands. For every memory access that happens, the CPU translates it according to the page table. If the translation succeeds, it performs the corresponding read/write to the physical memory location.

The interesting things happen when the address translation fails. Not all addresses are valid, and if any memory access generates an invalid address, the processor raises a page fault exception. This triggers a transition from user mode (aka current privilege level (CPL) 3 on x86/x86-64) into kernel mode (aka CPL 0) to a specific location in the kernel's code, as defined by the interrupt descriptor table (IDT).

The kernel regains control and, based on the information from the exception and the process's page table, figures out what happened. In this case, it realizes that the user-level process accessed an invalid memory location, and then it reacts accordingly. On Windows, it will invoke structured exception handling to allow the user code to handle the exception. On POSIX systems, the OS will deliver a SIGSEGV signal to the process.

In other cases, the OS will handle the page fault internally and restart the process from its current location as if nothing happened. For example, guard pages are placed at the bottom of the stack to allow the stack to grow on demand up to a limit, instead of preallocating a large amount of memory for the stack. Similar mechanisms are used for achieving copy-on-write memory.

In modern OSes, the page tables are usually set up to make the address 0 an invalid virtual address. But sometimes it's possible to change that, e.g. on Linux by writing 0 to the pseudofile /proc/sys/vm/mmap_min_addr, after which it's possible to use mmap(2) to map the virtual address 0. In that case, dereferencing a null pointer would not cause a page fault.

The above discussion is all about what happens when the original code is running in user space. But this could also happen inside the kernel. The kernel can (and is certainly much more likely than user code to) map the virtual address 0, so such a memory access would be normal. But if it's not mapped, then what happens then is largely similar: the CPU raises a page fault error which traps into a predefined point at the kernel, the kernel examines what happened, and reacts accordingly. If the kernel can't recover from the exception, it will typically panic in some fashion (kernel panic, kernel oops, or a BSOD on Windows, e.g.) by printing out some debug information to the console or serial port and then halting.

See also Much ado about NULL: Exploiting a kernel NULL dereference for an example of how an attacker could exploit a null pointer dereference bug from inside the kernel in order to gain root privileges on a Linux machine.

Answer from Adam Rosenfield on Stack Overflow
🌐
SEI CERT
wiki.sei.cmu.edu › confluence › display › c › EXP34-C.+Do+not+dereference+null+pointers
EXP34-C. Do not dereference null pointers | CERT Secure Coding
No dereferencing actually occurs ... not violate this rule, evaluates to ((*int) NULL) + 5. Dereferencing a null pointer is undefined behavior , typically abnormal program termination ....
🌐
Wikipedia
en.wikipedia.org › wiki › Null_pointer
Null pointer - Wikipedia
June 13, 2026 - Dereferencing a null pointer is undefined behavior in C, and a conforming implementation is allowed to assume that any pointer that is dereferenced is not null. In practice, dereferencing a null pointer may result in an attempted read or write from memory that is not mapped, triggering a ...
🌐
Sivanesh Waran
sivaneshwaran.com › home › klocwork › null pointer dereference in c
Null Pointer Dereference in C Null Pointer Dereference in C
May 5, 2023 - Dereferencing a null pointer can cause a segmentation fault, which is a type of error that occurs when a program tries to access a memory location that it is not allowed to access.
🌐
Quora
quora.com › What-actually-happens-when-dereferencing-a-NULL-pointer-Usually-the-process-terminates-Does-the-reaction-depend-on-the-operating-system-or-is-it-controlled-by-the-compiler-Is-it-mandatory-that-NULL-always-be-defined-as-“0”-with-proper-casting
What actually happens when dereferencing a NULL pointer? Usually, the process terminates. Does the reaction depend on the operating syste...
Answer (1 of 10): C/C++ are different from most of the popular languages: there is no runtime environment, there are no runtime checks, the actual machine language instructions will be generated and executed performing the read/write access at address zero. The behavior is entirely HW dependent. ...
🌐
Rip Tutorial
riptutorial.com › dereferencing a null pointer
C Language Tutorial => Dereferencing a null pointer
This is an example of dereferencing a NULL pointer, causing undefined behavior.
Find elsewhere
🌐
Quora
quora.com › What-will-happen-at-low-level-when-we-dereference-a-null-pointer-in-C-or-C
What will happen at low level when we dereference a null pointer in C or C++? - Quora
In most such situations, you were ... point of triple faulting and the processor resetting itself. ... Register your business with a credible street address. Launch or run your business from anywhere with a virtual mailbox and a real street address. ... Dereferencing a null pointer in C or C++ ...
🌐
Mayhem Security
mayhem.security › blog › what-is-null-pointer-dereference
What Is Null Pointer Dereference? | Mayhem
June 1, 2022 - CWE-476 Null Pointer Dereference is a programming error that can occur when a program attempts to deference a null pointer. This can happen when the programmer mistakenly assumes that a pointer pointing to NULL is actually pointing to a valid object.
🌐
123Microcontroller
123microcontroller.com › en › cpp-null-pointer-dereferencing
Decoding Null-Pointer Dereferencing: When a Program’s End is the Beginning of Undefined Behavior Disaster | 123Microcontroller
February 5, 2026 - Theoretically, this translates to “a Pointer that does not point to any valid object or location in memory.” The C Standard explicitly dictates that attempting to Dereference a Null Pointer results in an absolute Undefined Behavior (UB).
🌐
MITRE
cwe.mitre.org › data › definitions › 476.html
CWE - CWE-476: NULL Pointer Dereference (4.20)
A community-developed list of SW & HW weaknesses that can become vulnerabilities
🌐
Housing Innovations
dev.housing.arizona.edu › home › log › the fatal mistake: what happens when you dereference a null pointer
The Fatal Mistake: What Happens When You Dereference a Null Pointer - Housing Innovations
May 21, 2025 - Dereferencing a null pointer occurs when a program attempts to access memory through a pointer that has not been initialized or has been set to null, leading to crashes and errors; understanding null pointer exceptions, pointer arithmetic, and ...
🌐
Quora
quora.com › What-happens-if-you-dereference-a-null-pointer
What happens if you dereference a null pointer? - Quora
Answer (1 of 8): The outcome is exactly the same as with any other pointer. If the address represents a valid mapping for which the attempted action is permitted (typically read, write or execute, as determined by the instruction that attempts the access and/or its context), the address is resol...
🌐
Snyk Learn
learn.snyk.io › home › security education › what is a null dereference? | tutorial & examples
What is a null dereference? | Tutorial & examples | Snyk Learn
August 15, 2024 - This can occur in various programming languages and it can cause the program to crash or behave unexpectedly, potentially leading to security issues. A null pointer dereference, on the other hand, is a specific type of null dereference that ...
🌐
Security Boulevard
securityboulevard.com › home › security bloggers network › what is a null pointer dereference error?
What Is A Null Pointer Dereference Error? - Security Boulevard
July 1, 2022 - CWE-476 Null pointer dereference ... a null pointer. This can happen when the programmer mistakenly assumes that a pointer pointing to NULL is actually pointing to a valid object....
🌐
Quora
quora.com › What-does-it-mean-when-you-dereference-a-pointer-and-its-null
What does it mean when you dereference a pointer and it's null? - Quora
Answer (1 of 3): It means that in C the program will crash with a segmentation fault; it is not allowed to access address [code ]0x0000000000[/code] in memory for user programs. In a language that uses pointers but have exception mechanisms such as C++, objective C, C#, D, Fortan, Rust, Go, Ada,...
🌐
8th Light
8thlight.com › home › insights › dereferencing null pointer, without a seg fault
8th Light | Dereferencing NULL Pointer, without a Seg Fault
March 5, 2024 - On line 1, we create one cow and tie the leash cowPointer to that cow. On line 2, we create another cow, untie the leash from the first cow, and tie that same leash to the new cow. At this point if we follow the leash: ... The technical term for "following a leash" is dereferencing a pointer. Now remember, the pointer (cowPointer) is just a variable that stores an address. It stores the memory address of a Cow object. If the Cow object happens to be stored in memory at address 0x887788, then the "value" of cowPointer will be 0x887788.
🌐
Reddit
reddit.com › r/cpp_questions › what happens when dereferencing a nullptr?
r/cpp_questions on Reddit: What happens when dereferencing a nullptr?
August 18, 2022 -

I saw this code in A Tour of C++, but with a bit modify for illustration:

#include <iostream>

int main() {
  char s = 'a';
  char *p = &s;
  while (*p) {
    std::cout << *p;
    p++;
  }
  p = nullptr;
  //std::cout << (*p == true);
  *p == true;
}

I do not know how does while (*p) { end while I do not know what happens when p is nullptr. And std::cout << (*p == true) will induce segment fault but *p == true does not.

🌐
AWS
docs.aws.amazon.com › codeguru › detector-library › c › null-pointer-dereference
Null pointer dereference | Amazon Q, Detector Library
We observed that a NULL pointer dereference occurs when a program attempts to access the value referenced by a pointer that is currently set to NULL.
🌐
Reddit
reddit.com › r/cprogramming › dereferencing a pointer to save it's value before setting the pointer to null
r/cprogramming on Reddit: Dereferencing a pointer to save it's value before setting the pointer to NULL
May 24, 2021 -

I'm implementing a linked list for external chaining of a hashmap implementation. The code I'm asking about deletes the last node of a linked list and returns it. Originally, I was thinking of writing the following code to do that:

(POSITION is a struct defined by me, where next is a pointer to another POSITION)

POSITION *tmp = curr->next;
curr->next = NULL;
return tmp;

But I think this would return NULL (I may be mistaken though I'm only a beginner at C). So instead I wrote the following code, which dereferences the pointer into tmp, which is now a variable, to save it's value before setting the next pointer to NULL, then returning a pointer to the tmp variable.

POSITIION tmp = *(curr->next);
curr->next = NULL;
return &tmp;

I think this will give me back a pointer to my data, but I'm not sure and my implementation is nowhere near complete enough to be able to test it.

Edit: It seems like my code generates a warning, and that is that I am returning the address of a local variable. This means that the return value will be useless. Do I have to use malloc and rely on the user to free?

Top answer
1 of 5
4
C is not devious the way you think that it is. Instead, C is vicious and uncaring in ways that you have not yet imagined. There is no risk to copying an invalid address, or even a valid address. The copies don't change, nor do they deteriorate. This is why "NULL pointers" are a thing. The null address is invalid, and if you try to access it your program will immediately crash. But as long as all you do is copy it without trying to access it, nothing bad happens! In your case, you have POSITION *tmp = curr->next; curr->next = NULL; return tmp; This is perfectly valid code, and works in exactly the way you intend it to work. If curr->next contains NULL, this code will work. If it contains an invalid address, this code will work. If it contains exactly the right answer, this code will work. Because you are not "dereferencing" the pointer (address). All you are doing is copying it from one place to another. I'm not sure what language you are coming from. But in C, assignment and initialization are the same - you are copying bits into a named space. It is definitely not the case that initializing a variable to another variable makes them synonyms, or pointers to the same "bucket", or anything like that. Variables are fully distinct in C, and when you use an initializer or a "bare" assignment(*) you are overwriting whatever previous value might have existed. The only way to get the hinky "action at a distance" effect you are afraid of is to use pointers. But it's only the pointed-to thing that can be changed. So: curr->next = &(POSITION){.x=12}; // This is valid C11 code. It creates a "temporary" object with element "x" assigned 12, everything else 0 POSITION *tmp = curr->next; print(tmp->x); // 12 print(curr->next->x); // 12 curr->next->x += 3; // Because of pointers, this is a "shared" change print(tmp->x); // 15 curr->next = NULL; print(tmp->x); // 15 print(curr->next); // NULL POSITION * tmp2 = curr->next; // You can initialize using a NULL value POSITION * tmp3 = tmp; // You can initialize using a non-NULL value tmp3 = tmp2; // You can assign using a NULL value print(tmp); // 0xDEADBEEF (some random address in memory) print(tmp2); // NULL (still no problem "passing" (copying) a null value) print(tmp3); // NULL (still good) print(curr->next->x); // Segmention fault. Core dumped. (Game over: You cannot "dereference" (access) through a NULL value.) We pretend there is a function called "print" that amazingly does what you expect it to. Ignore that part. You can see in the "upper" parts of the example that (1) tmp is initialized to the same pointer that curr->next has. Thus, while the two variable tmp and curr->next are separate memory locations, they both refer to the same location because they are pointers that have the same value. I then modify the ->x value, which modification will be visible through both variables because the variables are pointers referring to the same target object. Then I set one of the variables to NULL. That breaks the symmetry, since now one variable refers to the position object, but the other does not. But it's still okay to hold a NULL value, and it's okay to initialize with a NULL values, and it's okay to copy a NULL value from one variable to another. But it's not okay to "dereference" a NULL value.(**) That is, you may not try to fetch the memory at location 0, nor at any location close to 0(***). When you do, that's the end. ====== (*) "bare" assignment is just a simple "=" sign. Not "+=" or "/=" or "->=" (which doesn't exist but should!) or any of the other "compound assignment" operators. (**) This is not really true. On embedded systems it is frequently necessary to operate on memory at or near location 0. But you have to know what you're doing, and if you don't you can really screw things up. On desktop and server systems, it is possible to operate on memory at or near location 0. But we have adopted this convention "as a society" that zero means "probably an error," and the developers and vendors of operating systems, compilers, development tools, etc., have agreed to support that beneficial convention, to the extent that they now enforce the rule because it probably indicates a programming error. (***) A "struct" in C is a collection of logically related data that may be of the same or different types. It is implemented as named elements that are located in close proximity to each other in memory. The struct has a base address and internally is accessed using offsets relative to the base address. Thus, on a 32-bit system, a simple POSITION linked list might have elements next, x, y with offsets of 0, 4, and 8 bytes (since pointers and ints are 32-bits) respectively. You know that accessing memory address 0 is forbidden. But because someone might try to do POSITION *tmp = NULL; print(tmp->y) in their code, and generate an access to memory at location 0 + 8, modern system forbid access to memory anyplace near location 0. Usually that means a "page" at location 0 and maybe one page at the "top" of memory, where location -1 would be.
2 of 5
2
Your last code snippet returns a pointer to a memory location on the stack. This will most likely be invalid as soon as you call another function. That is probably why you’re getting a warning.