A reader of my blog sent me a question the other day asking to explain a piece of code with pointers. I found it to be a very interesting puzzle, not just because I had to drop into an object dump with a friend to work through it. The error is consistent, even across platforms. Here is a slightly modified version of the original code. We will call this file bad.c. See if you can notice the error.

If you compile that, gcc bad.c you will get a bunch of warnings. Affirming that it is not good to ignore warnings, upon running it you should see output like this.

arr0=0
arr1=4
arr2=8
arr3=12
arr4=16

We ran this on both x64 mac and linux. Same result. What the expected output is is something like this.

arr0=0
arr1=1
arr2=2
arr3=3
arr4=4

Try to figure out the error before going further.

The Error

The error is actually easy to overlook. The int *a[] means an array of int pointers. What was probably intended was an array of ints.

Change that and compile it and done. We get the output. The *a+n expression dereferences the value at the start of the a array, in this case 0, and adds n to it. The *a+0 was probably intended to be *(a + 0) as well, leading to the same output but for a different reason. Mildly interesting.

Ignoring the array of int pointers instead of ints and the dereferencing logic errors, what is interesting is that the error is consistent, even across platforms. Do you know why?

The Puzzle

Confused. Run the error version multiple times you will get the same output. Usually with pointer errors you get changing memory locations and values. But the error output was consistent. I had to work through it in an object dump with my friend Seth Hartbecke to figure out what was going on.

Let’s drop into assembly output.

This is interesting. It takes the first value of the array, 0, and adds 4, 8, 12, and 16 to it in sequence to give us our output. Where did those values come from? Have you solved it?

A Bad Case of Pointer Math

This is a bad case of pointer math.

The first piece of the puzzle is that int *a[] is an array of pointers. The initialization {0,0,0,0,0} or {0,1,2,3,4} are, rightly so according to the compiler, seen as pointers holding addresses. There are instances where absolute addresses are used, though it is more common in embedded programming.

The second piece to the puzzle is the 0, 4, 8, 12, 16 in the assembly. These are equivalent to 0 * 4, 1 * 4, 2 * 4, 3 * 4, and 4 * 4 respectively.

The int *a[] being an array of pointers, the compiler is doing pointer math. The *a + 1 value is being evaluated as an int pointer + n. In this case ints are 4 bytes and according to pointer math, a + n items get translated to 4 bytes * n items.

In the end a consistent, and somewhat interesting, case of bad pointer math. All from one little character.