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:
1int nums[] = {10, 20, 30};2int *p = nums; // same as int *p = &nums[0];34printf("%d\n", *p); // 105printf("%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:
1int nums[] = {10, 20, 30};2int *p = nums;34*(p + 1); // 205p[1]; // 20 — pointers can even use bracket syntax6*(p + 2); // 30
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:
1int nums[5] = {1, 2, 3, 4, 5};2int *p = nums;34sizeof(nums); // 20 — 5 ints, the array's true size5sizeof(p); // 8 — the size of a pointer itself, on most 64-bit systems67nums = p; // compile error — an array name isn't reassignable8p = 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
1int sum(int *arr, int length) {2int total = 0;3for (int i = 0; i < length; i++) {4total += arr[i];5}6return total;7}89int main(void) {10int nums[] = {4, 8, 15, 16, 23, 42};11int total = sum(nums, 6);12printf("%d\n", total);13return 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.