› Module 7: Pointers › 7.1 Pointer Fundamentals
M O D U L E

Module 7: Pointers

Variables that store memory addresses — C's most powerful and distinctive feature.

7.1 Pointer Fundamentals

A pointer is a variable that stores the memory address of another variable rather than a direct value. It is declared with * (int *p;) and given a target's address using the & (address-of) operator: p = &x;. Once p holds &x, the dereference operator *p accesses/modifies the value stored at that address, effectively giving pointer-based access to x.

int x = 10; int *p = &x;
Variable x value = 10 address = 0x1000 p stores address of x Pointer p value = 0x1000 address = 0x2000

*p dereferences p and gives 10 (the value stored at 0x1000).
&x gives the address of x (0x1000), used to initialize p.

A pointer variable holding the address of another variable.

7.2 Pointer Arithmetic

Pointers support limited arithmetic that is scaled by the size of the type they point to. p + 1 does NOT add 1 byte to the address — it advances by sizeof(type) bytes, landing exactly on the next element. This scaling is what makes pointer arithmetic and array indexing behave identically for contiguous data.

int a[4] = {5, 10, 15, 20}; int *p = a; // (p points to a[0])
5 a[0] 1000 10 a[1] 1004 15 a[2] 1008 20 a[3] 1012
p -> 1000 (a[0])
p + 1 -> 1004 (a[1]) [ moves by sizeof(int)=4 bytes, NOT by 1 byte ]
*(p + 2) -> 15 (value at a[2])
p+1 jumps by sizeof(int), not by one raw byte.

7.3 Pointers and Arrays

An array's name, when used in an expression, decays into a pointer to its first element. Consequently arr[i] and *(arr + i) are exactly equivalent and compile to the same machine instructions — indexing is really pointer arithmetic wearing a friendlier syntax.

arr[i] ≡ *(arr + i)

The array name "arr" itself decays to a pointer to its first element,
so array indexing and pointer arithmetic are interchangeable in C.

Array indexing is pointer arithmetic in disguise.

7.4 Pointers and Functions

Passing a pointer to a function lets the function read and modify the caller's original data (true 'pass by reference' behaviour). Functions can also RETURN pointers, but must never return the address of a local variable — that memory is destroyed when the function returns, leaving a dangling pointer.

The Dangling Pointer Bug:

int* badFunction() {
  int local = 42;
  return &local; // BUG: local is deallocated on return!
}

When badFunction() returns, its stack frame is popped. The memory address returned now points to garbage or will be overwritten by the next function call. To return pointers safely, allocate memory dynamically on the heap with malloc() or return pointers to static variables.

7.5 Pointer to Pointer, void*, and NULL

A pointer to a pointer (int **pp) stores the address of another pointer — used for things like dynamically resizable 2D arrays or modifying a pointer inside a function. void* is a generic pointer that can point to any data type but must be cast before dereferencing. NULL is a special pointer value meaning 'points to nothing' — always check a pointer against NULL before dereferencing it to avoid crashes.

  • Double Pointer (int **pp): A pointer holding the address of a pointer variable. Frequently used when a helper function needs to modify where a pointer points (e.g., allocating memory for a caller's pointer), or for dynamically allocated arrays of strings (char **argv).
  • Generic Pointer (void*): A type-agnostic pointer that can hold any data address without a compiler error. malloc() returns a void*. It cannot be directly dereferenced or incremented without explicit typecasting.
  • The NULL Pointer: Macro defined in <stddef.h> (often ((void*)0)). Indicates that a pointer does not point to valid memory. Dereferencing NULL causes an immediate OS segmentation fault.
MODULE COMPREHENSIVE QUIZ

Module 7 Final Quiz

Test your understanding across all 5 topics of this module with interview-grade questions, tricky edge cases, and code output predictions.

Take Module 7 Final Quiz →
Yukti Mascot