Pointer Arithmetic & Arrays
p+1 scales by sizeof(*p), and arr[i] is just *(arr+i)
Quick check before you start: Can you declare a pointer, assign it with
&, and dereference it with*? If not, review Pointer Basics first.Practice this topic: Pointer Arithmetic skill drill
After this lesson, you will be able to:
- Calculate the result of adding an integer to a pointer, accounting for type-size scaling
- Explain the equivalence between
arr[i]and*(arr + i) - Traverse an array using pointer increment instead of index-based access
- Explain why an array parameter decays to a pointer inside a function
- Distinguish between
sizeofon an array vs.sizeofon a pointer
How Pointer Math Works
When you add 1 to a pointer, it does not move by 1 byte – it moves by sizeof the pointed-to type:
int arr[] = {10, 20, 30, 40, 50};
int *p = arr; /* Points to arr[0] */
printf("%d\n", *p); /* 10 (arr[0]) */
printf("%d\n", *(p + 1)); /* 20 (arr[1]) */
printf("%d\n", *(p + 2)); /* 30 (arr[2]) */
Since int is 4 bytes, p + 1 moves 4 bytes forward – exactly to the next int:
Memory: [10] [20] [30] [40] [50]
Address: 1000 1004 1008 1012 1016
^ ^ ^
p p+1 p+2
Key Insight:
p + nmovesn * sizeof(*p)bytes forward, notnbytes. Forint *p,p + 1advances 4 bytes. Fordouble *q,q + 1advances 8 bytes. C scales automatically so you never have to think about byte sizes when walking through arrays.
The Array-Pointer Equivalence
These are interchangeable:
| Array notation | Pointer notation | Meaning |
|---|---|---|
arr[0] |
*arr |
First element |
arr[i] |
*(arr + i) |
Element at index i |
&arr[i] |
arr + i |
Address of element i |
The name of an array, when used in an expression, decays to a pointer to its first element:
int arr[] = {10, 20, 30};
int *p = arr; /* No & needed -- arr decays to pointer */
Walking an Array with Pointers
Instead of indexing, you can increment a pointer:
int arr[] = {10, 20, 30, 40, 50};
int size = 5;
/* Index-based (familiar): */
for (int i = 0; i < size; i++)
{
printf("%d ", arr[i]);
}
/* Pointer-based (equivalent): */
int *p = arr;
for (int i = 0; i < size; i++)
{
printf("%d ", *p);
p++; /* Move to next element */
}
Both print: 10 20 30 40 50
Pointer Subtraction
Subtracting two pointers gives the number of elements between them (not bytes):
int arr[] = {10, 20, 30, 40, 50};
int *start = &arr[0];
int *end = &arr[4];
printf("Elements between: %ld\n", end - start); /* 4 */
Key Insight: Pointer subtraction is the inverse of pointer addition – both scale by
sizeofthe type. Ifpandqare bothint *pointers 16 bytes apart,q - preturns 4 (elements), not 16 (bytes). This only works when both pointers point into the same array.
sizeof Array vs. sizeof Pointer
This is why functions cannot use sizeof on array parameters:
void print_size(int arr[])
{
/* sizeof(arr) is the size of a POINTER (8 bytes), not the array! */
printf("Inside function: %zu\n", sizeof(arr)); /* 8 */
}
int main(void)
{
int nums[100];
printf("In main: %zu\n", sizeof(nums)); /* 400 (100 * 4) */
print_size(nums);
return 0;
}
Key Insight: When you pass an array to a function, it decays to a pointer. The function receives
int *arr, not the full array. That is why you must always pass the size as a separate parameter – the function has no way to determine it from the pointer alone.
From Java: In Java, arrays are objects with a
.lengthfield that travels with the array. In C, the array name decays to a raw pointer when passed to a function – all size information is lost. This is the root of why C requires you to pass size everywhere.
int *p points to address 0x1000, what address does p + 3 point to? (Assume sizeof(int) is 4.)sizeof(int) = 4 bytes. So p + 3 advances 3 * 4 = 12 bytes. 0x1000 + 12 = 0x1000 + 0xC = 0x100C. Option A ignores type scaling. Option C only advances by one element. Option D misreads the hex math.
What Comes Next
Array notation (arr[i]) and pointer notation (*(arr + i)) are the same thing. Understanding this connection means you will never be confused by C code that mixes them.
Next: double pointers. What happens when a function needs to modify a pointer itself, not just the value it points to? You need a pointer to a pointer – int **pp.