carrayspointers

Create a pointer to two-dimensional array


I need a pointer to a static 2-dimensional array. How is this done?

static uint8_t l_matrix[10][20];

void test(){
   uint8_t **matrix_ptr = l_matrix; //wrong idea 
}

I get all kinds of errors like:


Solution

  • Here you wanna make a pointer to the first element of the array

    uint8_t (*matrix_ptr)[20] = l_matrix;
    

    With typedef, this looks cleaner

    typedef uint8_t array_of_20_uint8_t[20];
    array_of_20_uint8_t *matrix_ptr = l_matrix;
    

    Then you can enjoy life again :)

    matrix_ptr[0][1] = ...;
    

    Beware of the pointer/array world in C, much confusion is around this.


    Edit

    Reviewing some of the other answers here, because the comment fields are too short to do there. Multiple alternatives were proposed, but it wasn't shown how they behave. Here is how they do

    uint8_t (*matrix_ptr)[][20] = l_matrix;
    

    If you fix the error and add the address-of operator & like in the following snippet

    uint8_t (*matrix_ptr)[][20] = &l_matrix;
    

    Then that one creates a pointer to an incomplete array type of elements of type array of 20 uint8_t. Because the pointer is to an array of arrays, you have to access it with

    (*matrix_ptr)[0][1] = ...;
    

    And because it's a pointer to an incomplete array, you cannot do as a shortcut

    matrix_ptr[0][0][1] = ...;
    

    Because indexing requires the element type's size to be known (indexing implies an addition of an integer to the pointer, so it won't work with incomplete types). Note that this only works in C, because T[] and T[N] are compatible types. C++ does not have a concept of compatible types, and so it will reject that code, because T[] and T[10] are different types.


    The following alternative doesn't work at all, because the element type of the array, when you view it as a one-dimensional array, is not uint8_t, but uint8_t[20]

    uint8_t *matrix_ptr = l_matrix; // fail
    

    The following is a good alternative

    uint8_t (*matrix_ptr)[10][20] = &l_matrix;
    

    You access it with

    (*matrix_ptr)[0][1] = ...;
    matrix_ptr[0][0][1] = ...; // also possible now
    

    It has the benefit that it preserves the outer dimension's size. So you can apply sizeof on it

    sizeof (*matrix_ptr) == sizeof(uint8_t) * 10 * 20
    

    There is one other answer that makes use of the fact that items in an array are contiguously stored

    uint8_t *matrix_ptr = l_matrix[0];
    

    Now, that formally only allows you to access the elements of the first element of the two dimensional array. That is, the following condition hold

    matrix_ptr[0] = ...; // valid
    matrix_ptr[19] = ...; // valid
    
    matrix_ptr[20] = ...; // undefined behavior
    matrix_ptr[10*20-1] = ...; // undefined behavior
    

    You will notice it probably works up to 10*20-1, but if you throw on alias analysis and other aggressive optimizations, some compiler could make an assumption that may break that code. Having said that, i've never encountered a compiler that fails on it (but then again, i've not used that technique in real code), and even the C FAQ has that technique contained (with a warning about its UB'ness), and if you cannot change the array type, this is a last option to save you :)