Please include an example with the explanation.
What does 'dereferencing' a pointer mean in C/C++?
806.6k views Asked by asir AtThere are 6 answers
A pointer is a "reference" to a value.. much like a library call number is a reference to a book. "Dereferencing" the call number is physically going through and retrieving that book.
int a=4 ;
int *pA = &a ;
printf( "The REFERENCE/call number for the variable `a` is %p\n", pA ) ;
// The * causes pA to DEREFERENCE... `a` via "callnumber" `pA`.
printf( "%d\n", *pA ) ; // prints 4..
If the book isn't there, the librarian starts shouting, shuts the library down, and a couple of people are set to investigate the cause of a person going to find a book that isn't there.
Code and explanation from Pointer Basics:
The dereference operation starts at the pointer and follows its arrow over to access its pointee. The goal may be to look at the pointee state or to change the pointee state. The dereference operation on a pointer only works if the pointer has a pointee -- the pointee must be allocated and the pointer must be set to point to it. The most common error in pointer code is forgetting to set up the pointee. The most common runtime crash because of that error in the code is a failed dereference operation. In Java the incorrect dereference will be flagged politely by the runtime system. In compiled languages such as C, C++, and Pascal, the incorrect dereference will sometimes crash, and other times corrupt memory in some subtle, random way. Pointer bugs in compiled languages can be difficult to track down for this reason.
void main() {
int* x; // Allocate the pointer x
x = malloc(sizeof(int)); // Allocate an int pointee,
// and set x to point to it
*x = 42; // Dereference x to store 42 in its pointee
}
Dereferencing a pointer means getting the value that is stored in the memory location pointed by the pointer. The operator * is used to do this, and is called the dereferencing operator.
int a = 10;
int* ptr = &a;
printf("%d", *ptr); // With *ptr I'm dereferencing the pointer.
// Which means, I am asking the value pointed at by the pointer.
// ptr is pointing to the location in memory of the variable a.
// In a's location, we have 10. So, dereferencing gives this value.
// Since we have indirect control over a's location, we can modify its content using the pointer. This is an indirect way to access a.
*ptr = 20; // Now a's content is no longer 10, and has been modified to 20.
I think all the previous answers are wrong, as they state that dereferencing means accessing the actual value. Wikipedia gives the correct definition instead: https://en.wikipedia.org/wiki/Dereference_operator
It operates on a pointer variable, and returns an l-value equivalent to the value at the pointer address. This is called "dereferencing" the pointer.
That said, we can dereference the pointer without ever accessing the value it points to. For example:
char *p = NULL;
*p;
We dereferenced the NULL pointer without accessing its value. Or we could do:
p1 = &(*p);
sz = sizeof(*p);
Again, dereferencing, but never accessing the value. Such code will NOT crash: The crash happens when you actually access the data by an invalid pointer. However, unfortunately, according the the standard, dereferencing an invalid pointer is an undefined behaviour (with a few exceptions), even if you don't try to touch the actual data.
So in short: dereferencing the pointer means applying the dereference operator to it. That operator just returns an l-value for your future use.
Reviewing the basic terminology
It's usually good enough - unless you're programming assembly - to envisage a pointer containing a numeric memory address, with 1 referring to the second byte in the process's memory, 2 the third, 3 the fourth and so on....
When you want to access the data/value in the memory that the pointer points to - the contents of the address with that numerical index - then you dereference the pointer.
Different computer languages have different notations to tell the compiler or interpreter that you're now interested in the pointed-to object's (current) value - I focus below on C and C++.
A pointer scenario
Consider in C, given a pointer such as
p
below......four bytes with the numerical values used to encode the letters 'a', 'b', 'c', and a 0 byte to denote the end of the textual data, are stored somewhere in memory and the numerical address of that data is stored in
p
. This way C encodes text in memory is known as ASCIIZ.For example, if the string literal happened to be at address 0x1000 and
p
a 32-bit pointer at 0x2000, the memory content would be:Note that there is no variable name/identifier for address 0x1000, but we can indirectly refer to the string literal using a pointer storing its address:
p
.Dereferencing the pointer
To refer to the characters
p
points to, we dereferencep
using one of these notations (again, for C):You can also move pointers through the pointed-to data, dereferencing them as you go:
If you have some data that can be written to, then you can do things like this:
Above, you must have known at compile time that you would need a variable called
x
, and the code asks the compiler to arrange where it should be stored, ensuring the address will be available via&x
.Dereferencing and accessing a structure data member
In C, if you have a variable that is a pointer to a structure with data members, you can access those members using the
->
dereferencing operator:Multi-byte data types
To use a pointer, a computer program also needs some insight into the type of data that is being pointed at - if that data type needs more than one byte to represent, then the pointer normally points to the lowest-numbered byte in the data.
So, looking at a slightly more complex example:
Pointers to dynamically allocated memory
Sometimes you don't know how much memory you'll need until your program is running and sees what data is thrown at it... then you can dynamically allocate memory using
malloc
. It is common practice to store the address in a pointer...In C++, memory allocation is normally done with the
new
operator, and deallocation withdelete
:See also C++ smart pointers below.
Losing and leaking addresses
Often a pointer may be the only indication of where some data or buffer exists in memory. If ongoing use of that data/buffer is needed, or the ability to call
free()
ordelete
to avoid leaking the memory, then the programmer must operate on a copy of the pointer......or carefully orchestrate reversal of any changes...
C++ smart pointers
In C++, it's best practice to use smart pointer objects to store and manage the pointers, automatically deallocating them when the smart pointers' destructors run. Since C++11 the Standard Library provides two,
unique_ptr
for when there's a single owner for an allocated object......and
shared_ptr
for share ownership (using reference counting)...Null pointers
In C,
NULL
and0
- and additionally in C++nullptr
- can be used to indicate that a pointer doesn't currently hold the memory address of a variable, and shouldn't be dereferenced or used in pointer arithmetic. For example:In C and C++, just as inbuilt numeric types don't necessarily default to
0
, norbools
tofalse
, pointers are not always set toNULL
. All these are set to 0/false/NULL when they'restatic
variables or (C++ only) direct or indirect member variables of static objects or their bases, or undergo zero initialisation (e.g.new T();
andnew T(x, y, z);
perform zero-initialisation on T's members including pointers, whereasnew T;
does not).Further, when you assign
0
,NULL
andnullptr
to a pointer the bits in the pointer are not necessarily all reset: the pointer may not contain "0" at the hardware level, or refer to address 0 in your virtual address space. The compiler is allowed to store something else there if it has reason to, but whatever it does - if you come along and compare the pointer to0
,NULL
,nullptr
or another pointer that was assigned any of those, the comparison must work as expected. So, below the source code at the compiler level, "NULL" is potentially a bit "magical" in the C and C++ languages...More about memory addresses, and why you probably don't need to know
More strictly, initialised pointers store a bit-pattern identifying either
NULL
or a (often virtual) memory address.The simple case is where this is a numeric offset into the process's entire virtual address space; in more complex cases the pointer may be relative to some specific memory area, which the CPU may select based on CPU "segment" registers or some manner of segment id encoded in the bit-pattern, and/or looking in different places depending on the machine code instructions using the address.
For example, an
int*
properly initialised to point to anint
variable might - after casting to afloat*
- access memory in "GPU" memory quite distinct from the memory where theint
variable is, then once cast to and used as a function pointer it might point into further distinct memory holding machine opcodes for the program (with the numeric value of theint*
effectively a random, invalid pointer within these other memory regions).3GL programming languages like C and C++ tend to hide this complexity, such that:
If the compiler gives you a pointer to a variable or function, you can dereference it freely (as long as the variable's not destructed/deallocated meanwhile) and it's the compiler's problem whether e.g. a particular CPU segment register needs to be restored beforehand, or a distinct machine code instruction used
If you get a pointer to an element in an array, you can use pointer arithmetic to move anywhere else in the array, or even to form an address one-past-the-end of the array that's legal to compare with other pointers to elements in the array (or that have similarly been moved by pointer arithmetic to the same one-past-the-end value); again in C and C++, it's up to the compiler to ensure this "just works"
Specific OS functions, e.g. shared memory mapping, may give you pointers, and they'll "just work" within the range of addresses that makes sense for them
Attempts to move legal pointers beyond these boundaries, or to cast arbitrary numbers to pointers, or use pointers cast to unrelated types, typically have undefined behaviour, so should be avoided in higher level libraries and applications, but code for OSes, device drivers, etc. may need to rely on behaviour left undefined by the C or C++ Standard, that is nevertheless well defined by their specific implementation or hardware.