$ overview
overview/0x0A·Pointers & Memory

Pointers & Arrays

Why arr[i] and *(arr + i) are the same thing, and what decays.

Arrays and pointers are different types, but they're linked so closely in C that understanding one clarifies the other. This chapter connects the array indexing from 0x07 with the pointer mechanics from 0x09.

An array's name is (almost) a pointer

In most expressions, an array's name automatically "decays" into a pointer to its first element:

decay.c
1int nums[] = {10, 20, 30};
2int *p = nums; // same as int *p = &nums[0];
3 
4printf("%d\n", *p); // 10
5printf("%d\n", nums[0]); // 10 — same value, two ways to write it

Indexing is pointer arithmetic

nums[i] and *(nums + i) compile to the identical instructions. Adding i to a pointer doesn't move it by i bytes — it moves it by i elements, using sizeof of the pointer's type to work out the actual byte offset:

pointer-arithmetic.c
1int nums[] = {10, 20, 30};
2int *p = nums;
3 
4*(p + 1); // 20
5p[1]; // 20 — pointers can even use bracket syntax
6*(p + 2); // 30
note: This is why array types matter for arithmetic
p + 1 on an int * moves forward 4 bytes (on most systems); the same expression on a double * moves forward 8. The compiler uses the pointed-to type to compute the correct step.

Where the analogy breaks down

Despite behaving alike in expressions, arrays and pointers are not the same thing:

difference.c
1int nums[5] = {1, 2, 3, 4, 5};
2int *p = nums;
3 
4sizeof(nums); // 20 — 5 ints, the array's true size
5sizeof(p); // 8 — the size of a pointer itself, on most 64-bit systems
6 
7nums = p; // compile error — an array name isn't reassignable
8p = nums; // fine — p is an ordinary variable

This is exactly why the sizeof(arr) / sizeof(arr[0]) trick from 0x07 only works on the original array — once it's been passed to a function and decayed into a pointer parameter, sizeof can no longer see the original length.

Passing arrays to functions, correctly

pass-array.c
1int sum(int *arr, int length) {
2 int total = 0;
3 for (int i = 0; i < length; i++) {
4 total += arr[i];
5 }
6 return total;
7}
8 
9int main(void) {
10 int nums[] = {4, 8, 15, 16, 23, 42};
11 int total = sum(nums, 6);
12 printf("%d\n", total);
13 return 0;
14}

Writing the parameter as int arr[] instead of int *arr is allowed and means exactly the same thing — both are pointer parameters. Either way, the length has to be passed explicitly.