What is a pointer?
A pointer is a variable that stores the memory address of another object. Pointers let you manipulate memory, build dynamic data structures (linked lists, trees), implement polymorphism, and interface with low-level APIs.
Basic syntax & operations
int x = 10;
int *p = &x; // p stores address of x
int val = *p; // dereference: val == 10
*p = 20; // write through pointer; x becomes 20
1 - T* p β pointer to T.
2 - &obj β address-of.
3 - *p β dereference (access the pointee).
Null, uninitialized, and dangling pointers
1 - Null pointer: initialize to nullptr (C++11): int* p = nullptr; β safe to check if (p).
2 - Uninitialized pointer: int* p; β contains garbage; dereferencing is undefined behavior (UB).
3 - Dangling pointer: pointer to an object thatβs been destroyed (e.g., local variable went out of scope or deleted). Accessing it is UB.
Dynamic allocation
int* p = new int(5);
delete p; // free single object
int* arr = new int[3]{1,2,3};
delete[] arr; // must use delete[] for arrays
Common errors: forgetting delete (memory leak), deleting twice (double delete -> UB), mismatch new[]/delete.
Pointer arithmetic & arrays
1 - Pointer arithmetic moves in units of the pointee type: p + 1 points to the next T.
2 - Arrays decay to pointers to first element: int a[3]; int* p = a; then p[1] == *(p + 1).
3 - Valid arithmetic only within the same array (or one past the end).
const correctness
1 - const T* p β pointer to constant T (cannot modify *p).
2 - T* const p β constant pointer (cannot change the address in p).
3 - const T* const p β constant pointer to constant data.
Use const to communicate intent and catch mistakes at compile time.
Common pitfalls
1 - Dereferencing null or uninitialized pointers -> UB.
2 - Use-after-free (dangling pointer).
3 - Double delete.
4 - Buffer overruns via pointer arithmetic.
5 - Mixing new[] with delete (or new with delete[]).
6 - Casting away const and modifying memory that was const -> UB.
7 - Tools to catch these: AddressSanitizer, Valgrind, UBSan.
Quick best-practices
1 - Initialize pointers (nullptr) and prefer RAII.
2 - Prefer references when possible.
3 - Use std::vector/containers instead of raw arrays.
4 - Use unique_ptr for single ownership, shared_ptr only when shared ownership is needed.
5 - Use const to express immutability.
6 - Test with sanitizers and run-time tools.
More...
A pointer is a variable that stores the memory address of another object. Pointers let you manipulate memory, build dynamic data structures (linked lists, trees), implement polymorphism, and interface with low-level APIs.
Basic syntax & operations
int x = 10;
int *p = &x; // p stores address of x
int val = *p; // dereference: val == 10
*p = 20; // write through pointer; x becomes 20
1 - T* p β pointer to T.
2 - &obj β address-of.
3 - *p β dereference (access the pointee).
Null, uninitialized, and dangling pointers
1 - Null pointer: initialize to nullptr (C++11): int* p = nullptr; β safe to check if (p).
2 - Uninitialized pointer: int* p; β contains garbage; dereferencing is undefined behavior (UB).
3 - Dangling pointer: pointer to an object thatβs been destroyed (e.g., local variable went out of scope or deleted). Accessing it is UB.
Dynamic allocation
int* p = new int(5);
delete p; // free single object
int* arr = new int[3]{1,2,3};
delete[] arr; // must use delete[] for arrays
Common errors: forgetting delete (memory leak), deleting twice (double delete -> UB), mismatch new[]/delete.
Pointer arithmetic & arrays
1 - Pointer arithmetic moves in units of the pointee type: p + 1 points to the next T.
2 - Arrays decay to pointers to first element: int a[3]; int* p = a; then p[1] == *(p + 1).
3 - Valid arithmetic only within the same array (or one past the end).
const correctness
1 - const T* p β pointer to constant T (cannot modify *p).
2 - T* const p β constant pointer (cannot change the address in p).
3 - const T* const p β constant pointer to constant data.
Use const to communicate intent and catch mistakes at compile time.
Common pitfalls
1 - Dereferencing null or uninitialized pointers -> UB.
2 - Use-after-free (dangling pointer).
3 - Double delete.
4 - Buffer overruns via pointer arithmetic.
5 - Mixing new[] with delete (or new with delete[]).
6 - Casting away const and modifying memory that was const -> UB.
7 - Tools to catch these: AddressSanitizer, Valgrind, UBSan.
Quick best-practices
1 - Initialize pointers (nullptr) and prefer RAII.
2 - Prefer references when possible.
3 - Use std::vector/containers instead of raw arrays.
4 - Use unique_ptr for single ownership, shared_ptr only when shared ownership is needed.
5 - Use const to express immutability.
6 - Test with sanitizers and run-time tools.
More...