Are pointers and arrays equivalent in C?
Written by Eli Bendersky   
Wednesday, 04 May 2011
Article Index
Are pointers and arrays equivalent in C?
An important difference

Short answer: no

Longer answer: it depends on what you mean by "equivalent". Pointer arithmetic and array indexing are equivalent. In other aspects, pointers and arrays are different.

Here’s an example displaying the equivalence:

#include <stdio.h>

int main()
{
    char arr[] = "don't panic\n";
    char* ptr = arr;

    printf("%c %c\n", arr[4], ptr[4]);
    printf("%c %c\n", *(arr+2), *(ptr+2));

    return 0;
}

The output is, of course:

t t
n n

Note that indexing works on both arrays and pointers. Similarly, pointer arithmetic works on both arrays and pointers.

So how are they different?

In a very important and fundamental way. Consider this code snippet:

char array_place[100] = "don't panic";
char* ptr_place = "don't panic";

int main()
{
char a = array_place[7];
char b = ptr_place[7];

return 0;
}

What exactly happens in the assignment to a, and how is it different from the assignment to b? It's informative to take a look at the disassembly (taken from Visual C++ 2005 on an x86 machine running Windows XP):

  char a = array_place[7];

0041137E mov al,byte ptr
[_array_place+7 (417007h)]
00411383 mov byte ptr [a],al

  char b = ptr_place[7];

00411386 mov eax,dword ptr
[_ptr_place (417064h)]
0041138B mov cl,byte ptr [eax+7]
0041138E mov byte ptr [b],cl

The semantics of arrays in C dictate that the array name is the address of the first element of the array. Hence in the assignment to a, the 8th character of the array is taken by offsetting the value of array_place by 7, and moving the contents pointed to by the resulting address into the al register, and later into a.

On the other hand, the semantics of pointers are quite different. A pointer is just a regular variable that happens to hold the address of another variable inside. Therefore, to actually compute the offset of the 8th character of the string, the CPU will first copy the value of the pointer into a register and only then increment it. Because we are using an x86 this takes another instruction - on a CPU with a richer set of addressing modes (like a PDP-11), it could have been done in a single instruction.

This is a graphical explanation:

 

 

The rightmost column is the memory addresses, and the boxes are the contents of memory cells. The first few letters of the string in array_place are displayed.

Note that array_place is simply a label (or an alias) to the memory address 0×417000. Therefore accessing array_place[7] is simply accessing memory address 0×417007. Therefore, as we can see in the disassembly, the compiler just replaces array_place[7] by 0×417007 – no address computation has to be done by the assembly it generates.

With a pointer, this works differently:

 

ptr_place

 

ptr_place is just a variable that contains an address inside. (Notice that I drew a multi-byte memory cell for ptr_place. On my x86 32-bit machine, it actually takes 4 bytes with the least significant byte of the value in the lower address). This is the address to the first byte of the string that sits in another memory location. Compare this to the disassembly listing of the access to pointer_place[7] – it becomes clear why the compiler generates that code.



Last Updated ( Wednesday, 04 May 2011 )