cmultidimensional-arrayimplicit-conversionpointer-arithmeticdouble-pointer

"C" Trying to understand **pointer and how to access all values of value[][]


#include "stdio.h"

int main()
{
    int *pI, *values[2];
    int i1[] = {1, 2}, i2[][2] = {{5, 10}, {20, 30}};
// SOME LINES ARE EDITED, AFTER READING COMMENTS
    *values = i2[*i1];          // i2[1] = 20 // values[0] = &i2[1][0];
    values[1] = i1;             // values[1] = 1 
    pI = &i2[0][0];             //pI = 5
    printf(" %d %d\n", **values, *&values[1][1]); //...
    // (Edited) expectation: **values = 20 *&values[1][1] = 2
    // Result:               **values = 20 *&values[1][1] = 2
    
    *pI += pI[i1[1]];           // pI[0] += pI[2] = 5 + 20 = 25
    *values = pI;               // values points to the 25 (pI)
    *(i1 + 1) *= *(values[1] + 1);  // i1[1]=2 // i1[1] *= i1[1] = 2*2
    printf(" %d %d\n", **values, *&values[1][1]);
    // (Edited) expectation: **values = 25 *&values = 4
    // Result:               **values = 25 *&values = 4

    return 0;
}

As you can see my understanding of this code is not the yellow from the egg. But I would like to understand the steps, that i can solve it by myself the next time


Solution

  • The expression *values is the same as values[0] due to the definition of the subscript operator.

    Thus this statement

    *values = i2[*i1];
    

    may be rewritten the following way

    values[0] = i2[i1[0]];
    

    As i1[0] yields the value 1 then

    values[0] = i2[1];
    

    The expression i2[1] yields the second element of the array i2 that is the one-dimensional array of the type int[2] with values {20, 30}.

    Array designators used in expression with rare exceptions are converted to pointers to their first elements. So you may write

    values[0] = &i2[1][0];
    

    Thus the value of the expression **values is equal to 20.

    Again in this statement

    values[1] = i1;
    

    the array designator i1 is converted to pointer to its first element. That is you may write

    values[1] = &i1[0];
    

    In this expression *&values[1][1] the pair of operators *& in fact does not have an effect. You may write values[1][1]. So this expression yields the second element of the array i1 that is equal to 2.

    The variable pI

    pI = &i2[0][0];
    

    points to the element &i2[0][0]. This record may be interpreted as

    pI = ( int * )i2;
    

    This statement

    *pI += pI[i1[1]];
    

    may be rewritten like

    *pI += pI[2];
    

    The value of pI[2] is 20 (the third element of the type int of the array i2. SP you have

    *pI += 20;
    

    As a result the element i2[0][0] will contain 25.

    This statement

     *values = pI;
    

    is equivalent to

    values[0] = pI;
    

    So now the pointer values[0] points to the element i2[0][0] that is to the value 25 that is outputted using the expression **values.

    This expression statement

    *(i1 + 1) *= *(values[1] + 1);
    

    may be rewritten like

    i1[1] *= *( values[1] + 1 );
    

    Due to the statement above

    values[1] = i1; 
    

    values[1] points to the first element of the array i1. So the expression values[1] + 1 points to the second element of the array i1 that is equal to 2.

    So you have

    i1[1] *= 2;
    

    As a result i1[1] is equal to 4.

    This value is outputted by the expression *&values[1][1] that as it was mentioned above is equivalent to values[1][1]

    To understand the pointer arithmetic and the implicit conversion of array designators to pointers to their first elements there is no need to write such an obfuscated code.