Skip to content

Pointers and References in C++

Both references and pointers are related terms. Pointers and references are connected to a variable, but in different ways. The difference is that a pointer stores the address of the variable, while a reference acts as an alias for the variable, directly referring to its value.

  • A pointer is a variable that stores the address of another variable.
  • It allows indirect access to the value stored in that variable.
  • Useful for dynamic memory allocation, arrays, and data structures like linked lists.
int* p = &x; // p points to x

or

int *p;
p = &x

int *p = x ❌ because x is an int but p expects an int*. So pointer → type mismatch → compile-time error

int *p; *p = x ; ❌ because p is uninitialized and *p dereferences a garbage address so Writing to it → undefined behavior

p -> address
*p -> value at address p
  • p: is a pointer, and it stores the address of x.
  • *p: can be used to access or modify the value stored at the address p is pointing to (i.e., the value of x).
  • Note: *p = x; will change the value of p to x.
  • A reference is an alias for another variable.
  • It must be initialized when declared and cannot refer to a different variable later.
  • Simplifies function argument passing and avoids copying.
int& r = x; // r is another name for x

or

int &r;
r = x;
r -> value of x
&r -> address of x
  • a: is a reference, and it directly refers to the variable b. It behaves as an alias to b.
  • &a: gives the address of b (because a is just another name for b).
  • Note: a = c; will change the value of b to c.

Null Reference (Not Allowed ❌) ⭐

int *ptr = nullptr;
int &ref = *ptr; // Error: dereferencing a null pointer
### Variable
int a = 5; // 'a' is an integer variable initialized to 5.
a; // Value of 'a' is 5.
&a; // Address of 'a' in memory.
*a; // **error**. 'a' is not a pointer, so dereferencing it with '*' is invalid.

Pointer:

### Pointer
int b2 = 10; // Assuming you meant to have 'b2' as an integer variable.
int *b = &b2; // 'b' is a pointer to an integer, initialized to the address of 'b2'.
b; // Value of 'b' is the address of 'b2'.
*b; // Dereferencing 'b', gives the value stored in 'b2', which is 10.
&b; // Address of the pointer 'b' itself in memory.

Reference :

### Reference
int c2 = 15; // Assuming you meant to have 'c2' as an integer variable.
int &c = c2; // 'c' is a reference to 'c2'.
c; // Value of 'c' is the same as the value of 'c2', which is 15.
&c; // Address of 'c' is the same as the address of 'c2'.
*c; // *error** 'c' is not a pointer, so dereferencing it with '*' is invalid.
  • Operator * is used for both
  1. declaring pointers - When you see * before a variable in a declaration, it means the variable is a pointer.
  2. dereferencing them - When you see * before a pointer variable (not in a declaration), it means dereferencing that pointer to get the value it points to.
  • Operator & is used for both
  1. obtaining the address of a variable - When you see & before a variable, it typically means you’re getting its address.
  2. declaring references - When you see & in a declaration, it means you’re creating a reference.

  • A pointer to array stores the address of the entire array, not just the first element.
  • Type matters: pointer knows array size.
int arr[5] = {1,2,3,4,5};
int (*p)[5] = &arr;
p -> address of whole array arr
*p -> the array itself
(*p)[i] -> arr[i]
  • p+1 moves by 5 integers (size of array)
  • Different from int *p = arr; (that points to first element only)

Pointer to Element vs Pointer to Array

  • Comparison
int *p1 = arr; // pointer to element
int (*p2)[5] = &arr; // pointer to whole array
  • Access ⭐⭐⭐
arr // address of first element (decays to int*)
*arr // arr[0]
arr[0] // arr[0]
arr[3] // arr[3]
// p1 form pointer to element ⭐
p1 // address of arr[0]
*p1 // arr[0]
p1[0] // arr[0]
p1[3] // arr[3]
// p2 form (pointer to array)
p2 // address of whole array
*p2 // the array arr
(*p2)[0] // arr[0]
(*p2)[3] // arr[3]
  • Best use: passing arrays with fixed size to functions
  • A reference to array is an alias for the entire array.
  • Must be initialized at declaration.
  • Cannot be reseated.
int arr[5] = {1,2,3,4,5};
int (&r)[5] = arr;
r -> the array arr
r[i] -> arr[i]
&r -> address of array arr
  • No pointer arithmetic on r
  • Safer than pointer to array
  • Preserves array size information

Function example

void func(int (&r)[5]) {
r[0] = 10;
}

Key Difference

Pointer to Array -> stores address, can be reassigned
Reference to Array -> alias, cannot change binding

Best opinion:
Use reference to array when size is fixed and safety matters
Use pointer to array when low-level control is required


Passing Pointer/Reference as Function Parameter

Section titled “Passing Pointer/Reference as Function Parameter”
  • Passes the address of a variable
  • Allows modification of the original variable
  • Needs * to access or modify the value
void func(int* a){
cout << a << endl; // prints address of b
cout << *a << endl; // prints value of b
}
int b = 10;
func(&b); // pass address directly
// OR
int* a = &b;
func(a); // pass pointer
  • Passes a reference (alias) to the original variable
  • Allows direct access/modification without dereferencing
  • Simpler and safer than pointers
void func(int& a){
cout << a << endl; // prints value of b
cout << &a << endl; // prints address of b
}
int b = 10;
func(b); // pass by reference

  • A function pointer stores the address of a function.
  • Can be reassigned to point to different functions.
  • Useful for callbacks and dynamic function calls.
int add(int x, int y) {
return x + y;
}
int main() {
int (*funcPtr)(int, int) = &add; // Declare and assign
int result = funcPtr(5, 3); // Call via pointer
cout << "Result: " << result << endl; // Outputs 8
}
  • A function reference is an alias for a function.
  • Must be initialized during declaration and cannot be changed later.
  • Safer and simpler, but less flexible than pointers.
int add(int x, int y) {
return x + y;
}
int main() {
int (&funcRef)(int, int) = add; // Reference to function
int result = funcRef(5, 3); // Call via reference
cout << "Result: " << result; // Outputs 8
}