Pointer & Array Arithmetic in C

After a decade of working with TypeScript, my pointer arithmetic skills had become rusty. While I had spent the last few months working with C and C++, my experience is that organizing lessons learned—and relearned—helps fill gaps, and writing an article is a great way to reinforce that. This isn’t a deep dive into pointers; plenty of great in-depth articles already exist. Instead, it’s my reflection on the topic—perhaps someone else will find it useful too.

This article takes the following small piece of C code as a starting point:

int arr[3] = {10, 20, 30};
int *p = arr;

Defined array with three elements, and created a pointer storing the address of the array.

An array decays into a pointer in most expressions...

printf("%d\n", *(p + 1));  // prints 20
printf("%d\n", arr[1]); // prints 20

p+1 moves the address p by 4 bytes because p is an int*. Array indexing is simply syntactic sugar for pointer arithmetic and dereferencing.

💡
An int is not necessarily 4 bytes, but it is on most systems. For simplicity, assuming that from now on.

...but an array is not a pointer

The size of an array gives the size of the array, not the size of the address, as a pointer would.

printf("%lu\n", sizeof(arr));   // Prints 12 (if int is 4 bytes)
printf("%lu\n", sizeof(p));     // Prints 8 (pointer size on 64-bit)
💡
sizeof(p) isn’t necessarily 8 on all systems—it depends on whether the system is 32-bit or 64-bit. A pointer is typically 8 bytes on a 64-bit system or 4 bytes on a 32-bit system. For simplicity, this demonstration assumes a 64-bit system.

The reference operator gives a different type

printf("%p\n", p);      // Address of arr[0]
printf("%p\n", &arr);   // Address of the whole array

While both prints the same address, incrementing them leads to different results:

printf("%p\n", p+1);    // Address of arr[1]
printf("%p\n", &arr+1); // The first address after array

The first expression shifts by sizeof(int) which is 4. In the second expression, since &arr is of type int(*)[3] increments the address by sizeof(arr), the size of the array which is in this case is 12.

Arrays cannot be reassigned

p = &arr[2];      // allowed
arr = p;          // ERROR
arr = {40,50,60}; // ERROR

An array cannot be reassigned to a pointer, further proving that an array is not a pointer.

arr is not a pointer; it’s an array name, which most of the time acts as a constant pointer to the first element. The example attempts to modify an immutable address.

Summary

Pointers and arrays in C are closely linked but not interchangeable. While arrays decay into pointers, they retain some properties.