Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different ways to access array's element

As well as I know, there are two ways to access array's element in C++:

int array[5]; //If we have an array of 5 integers

1) Using square brackets

array[i]

2) Using pointers

*(array+i)

My university's teacher forces me to use *(array+i) method, telling me that "it's more optimized".

So, can you please explain, is there any real difference between them? Does the second method has any advantages over the first one?

like image 961
E_Tony Avatar asked Mar 23 '15 19:03

E_Tony


1 Answers

Is one option more optimized than the other ?

Well, let's see in practice the assembler code generated with MSVC2013 (NON-OPTIMIZED debug mode):

; 21   :    array[i] = 8; 

    mov eax, DWORD PTR _i$[ebp]
    mov DWORD PTR _array$[ebp+eax*4], 8

; 22   :    *(array + i) = 8; 

    mov eax, DWORD PTR _i$[ebp]
    mov DWORD PTR _array$[ebp+eax*4], 8

Well, with the best will, I cannot see any difference in the code generated.

By the way, someone recently wrote on SO: premature optimizing is the root of all evil. Your teacher should know that !

Has one an advantage over the other ?

Clearly, option one has the advantage of being intuitive and readable. Option2 becomes quickly UNREADABLE in mathematical applications.

Example 1: distance of a 2D mathematical vector implemented as an array.

double v[2] = { 2.0, 1.0 };

// option 1:  
double d1 = sqrt(v[0] * v[0] + v[1] * v[1]);

//option 2: 
double d2 = sqrt(*v**v + *(v + 1)**(v + 1));

In fact the second option is really misleading due to the **, because you have to read the formula carefully to understand if it's a double dereference or a multiplication by a dereferenced pointer. Not speaking of people who might be mislead by some other languages like ADA in which ** means "power"

Example 2: calculation of the determinant of a 2x2 matrix

double m[2][2] = { { 1.0, 2.0 }, { 3.0, 4.0 } };

// option 1
double dt1 = m[0][0] * m[1][1] - m[1][0] * m[0][1]; 

// option 2
double *x = reinterpret_cast<double*>(m); 
double dt2 = *x **(x+2*1+1) - *(x+2*1) * *(x+1);

With multidimensional arays, option 2 is a nightmare. Note that :

  • I've used a temporary one dimensional pointer x to be able to use the formula. Using m here would have caused misleading compilation error messages.

  • you have to know the precise layout of your object and you have to introduce the size of the first dimension in every formula !

Imagine that later on you want to increase the number of elements in your 2D array. You'll have to rewrite everything !

Semantic gap

What your teacher is missing here, is that the operator [] has a meaning that is well understood by the compiler and the reader. It's an abstraction that is not dependent on how your data structure is implemented in reality.

Suppose you have an array and a very simple code:

int w[10] {0}; 
... // put something in w
int sum = 0; 
for (int i = 0; i < 10; i++)
    sum += w[i];  

Later you decide to use a std::vector instead of an array, because you've learnt that it's much more flexible and powerful. All you have to do is to change the definition (and initialisation) of w :

vector<int> w(10,0); 

The rest of your code will work, because the semantic of [] is the same for the two data strutures. I let you imagine what would have hapened if you'd have used your teacher's advice...

like image 197
Christophe Avatar answered Sep 21 '22 13:09

Christophe