Search code examples
cpointersmultidimensional-arraysizeof

Why is the Index NOT out of bounds although it intuitively should?


I'm relatively new to C programming and I stumbled upon a for me unexplainable behaviour while running the following code and debugging it using gdb and lldb.

In short: When swapping the indices i and j (max i != max j) when accessing a value in a two-dimensional Array inside a double nested for-loop it does not seem to matter if I access the value using array[i][j] or array[j][i].

The two loops and arrays are mostly identical.

 unsigned matrix[3][1] =
   {
       {3},
       {4},
       {5}
   };

   //Loop1
   for (size_t i = 0; i < sizeof(matrix) / sizeof(*matrix); i++)
   {
        for (size_t j = 0; j < sizeof(matrix[i]) / sizeof(*matrix[i]); j++)
        {
            matrix[i][j] <<= 1;
            printf("matrix[%zu][%zu]  has the value: %d\n", i, j, matrix[i][j]);
        }
   }

   //same two dimensional array as matrix
   unsigned matrix2[3][1] =
   {
       {3},
       {4},
       {5}
   };

   //Loop2, basically the same loop as Loop1
   for (size_t i = 0; i < sizeof(matrix2) / sizeof(*matrix2); i++)
   {
        for (size_t j = 0; j < sizeof(matrix2[i]) / sizeof(*matrix2[i]); j++)
        {
            //swapped i and j here
            matrix2[j][i] <<= 1;
            printf("matrix2[%zu][%zu]  has the value: %d\n", j, i, matrix2[j][i]);
        }
   }

Am I missing here something?

In both cases i is passed the value 2 at the end of the outer loop and j the value 0 at the end of the inner loop.

Intuitively, matrix[0][2] should throw an exception as each row only has one element.


Solution

  • I will take a slightly different approach than the other respondents.

    You are technically not reading outside of the array's boundary as far as the memory layout is concerned. Looking at it from a human perspective you are (the index [0][2] doesn't exist!), but the memory layout of the array is contiguous. Each of the "rows" of the matrix are stored next to each other.

    In memory, your array is stored as: | ? | 3 | 4 | 5 | ? | So when you index to matrix[1][0] or matrix [0][1] you are accessing the same position in memory. This would not be the case if your array was larger than 1 dimension wide.

    For example, replace your array with the following one and experiment. You can access integer '4' either by indexing matrix[0][2], or matrix [1][0]. The position [0][2] shouldn't exist, but it does because the memory is contiguous.

    unsigned matrix[3][2] =
       {
           {3, 6},
           {4, 8},
           {5, 10}
       };