Despite the identical syntax in this example, the underlying operations are different. The language is trying to simplify your life.
0x1000 int myArray [10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
...
...
...
0x2000 int *pArray = myArray
Contents at memory address 0x1000: 0
Contents at memory address 0x1014 (presuming 4-byte int): 5
Contents at memory address 0x2000: 0x1000
0x10000 int i = myArray [5];
Action: get address of myArray (0x1000)
add 5 * sizeof int (0x1014, presuming 4-byte int)
get value from 0x1014
put value in 0x10000
Contents at memory address 0x10000: 5
...
0x20000 int j = pArray [5];
Action: get address of pArray (0x2000)
get value from pArray (0x1000) -- extra step, dereferencing
add 5 * sizeof int (0x1014, presuming 4-byte int)
get value from 0x1014
put value in 0x20000
Contents at memory address 0x20000: 5