cmatrixdynamic-memory-allocationpointer-arithmeticpointer-to-pointer

How to iterate through a dynamic, rectangular matrix in C?


I have to create a matrix with pointers in dynamic memory in C, fill it with random numbers then print it.

This is part of a larger assignment from college (I had to do a whole library of functions for matrixes) but for the purposes of the post, I think I managed to track down and isolate the problematic bits. Here's the code:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>

int main()
{
    int rows = 2;
    int cols = 3;
    int **matrix = malloc(sizeof(int*) * rows); //declaring and allocating dynamic memory for the matrix

    for(int i=0;i<rows;i++)
        *(matrix+i) = malloc(sizeof(int) * cols);

    //generating random numbers for the matrix:
    srand(time(NULL));

    for(int i=0;i<rows;i++)
        for(int j=0;j<cols;j++)
            *(*(matrix+j)+i) = rand() % 20;

    //printing matrix:
    printf("{\t");
    for(int i=0;i<rows;i++)
    {
        int j;

        if(i>0)
            printf("\t");
        printf("{\t");

        for(j=0;j<cols;j++)
            printf("%d\t",*(*(matrix + j) + i));

        printf("}");
        if(i<rows-1)
            printf("\n");
    }
    printf("\t}\n\n");

    //destroying the matrix
    for(int i=0;i<rows;i++)
        free(matrix[i]);

    free(matrix);
    matrix = NULL;

    return 0;
}

The debugger stops here:

*(*(matrix+j)+i) = rand() % 20;

Apparently, when trying to generate a random number for the first column of the second row (i.e. when it first changes rows) the debugger "cannot access memory" for that position, then the program crashes.

I tried changing the amount of rows and columns and I found it only crashes when row size is less than column size, which is weird because when it's equal or more, it works just fine.

I'm trying with 2 rows by 3 columns. Expectation:

{       {       5       17      3       }
        {       1       8       11      }       }

What actually happens:

Process returned -1073741819 (0xC0000005)

Values of the variables when the debugger stops (at generating random numbers):

i = 0
j = 2
**(matrix + 2) (aka matrix[0][2]) = Cannot access memory at address 0xabababababababab

At first I suspected I messed up when allocating memory for the matrix, but as I said when the matrix is square it does work fine, so I really don't know what's the issue here. I know the stackOverflow community doesn't like when someone posts "I don't know what I did wrong please help" kind of thing but I've really been a long time trying and couldn't get to the root of the problem.

Can someone please shed some light on this for me?


Solution

  • These nested for loops contain a bug

    for(int i=0;i<rows;i++)
        for(int j=0;j<cols;j++)
            *(*(matrix+j)+i) = rand() % 20;
    

    The pointer matrix points to an array of pointers that in turn point to "rows". So the expression matrix + i points to the i-th "row". However instead you are using the index j.

    That is you need to write

    *(*(matrix+i)+j) = rand() % 20;
    

    instead of

    *(*(matrix+j)+i) = rand() % 20;
    

    Otherwise when the value of cols is greater than the value of rows the expression matrix + j can access memory outside the allocated array of pointers (rows).

    The same problem exists in this call of printf

     printf("%d\t",*(*(matrix + j) + i));
    

    where you have to write

     printf("%d\t",*(*(matrix + i) + j));
    

    That is you need actually to access an element matrix[i][j]. This expression may be rewritten like

    ( *( matrix + i ) )[j]
    

    that in turn may be rewritten like

    *( *( matrix + i ) + j )
    

    Or in other way it may be rewritten like

    *( matrix[i] + j )
    

    and then

    *( *( matrix + i ) + j )
    

    To raise your interest to the subscript operator investigate these equivalent expressions to access elements of a two-dimensional array declared for example like

    T a[M][N];
    

    The expressions are

    a[i][j]
    i[a][j]
    j[a[i]]
    j[i[a]]
    *( *( a + i ) + j )
    *( a[i] + j )
    *( i[a] + j )
    ( *( a + i ) )[j]
    j[*( a + i ) ]