Matrix struct with random values allocation and deallocation
Improve your error reporting:

Your detectError function is not very useful. The name is also not good. It doesn't "detect errors", but rather it detects an out-of-memory condition if called after malloc.


int detectError(void *ptr) {
     if (ptr == NULL)
    {
            printf("operation failed\n");
            printf("%s\n", strerror(errno));
            return ERROR;
    }
    return SUCCESS;
}



If malloc fails, there is only one possible reason, it can't allocate any more memory. On a POSIX implementation if that happens malloc will set errno to ENOMEM. So by calling strerror you are just inventing a very complicated way of printing "out-of-memory" to stdout. Your code would be simpler and more idiomatic if instead of calling detectError you would just check the return of malloc for NULL:

matrix-&gt;values = malloc(n * sizeof(int*));
if (matrix-&gt;values == NULL) {
    fprintf(stderr, "Out-of-memory");
    return ERROR;
}


Also note that on some implementations malloc might not set errno at all or set it to EAGAIN, which would print an unclear or wrong message if using errno with strerror.

Still looking at the error reporting, it is more conventional to print error messages to stderr, so that users can filter normal program output from errors more easily.

Use booleans whenever possible instead of error codes:


#define ERROR -1
#define SUCCESS 0



I would not define those constants and instead use bool. If there are only two possible outcomes, success or failure, then just returning true or false is simpler and avoids confusion. It is very common for libraries to mix the use of integers as booleans and as error codes, which complicates things and leads to error if you misinterpret a return value. Keep it simple.

Awkward pointer manipulation:

From getMatrixProps, which already takes matrix by pointer:


return allocateMatrix(&amp;(*matrix), n, m);



That dereference followed by taking the address is nonsensical. Pass it directly as is.

Allocate a flat array:

Lastly, you could simplify a lot if you'd allocate the whole matrix as a sequential memory block. Instead of having to call a malloc per column, you can allocate a flat array of columns.

Since we are dealing with a 2D matrix, in the following example I'll call
the columns width and rows height, using x and y as the respective indexes.

typedef struct {
    int width;
    int height;
    int * values;
} Matrix;

bool allocMatrix(Matrix * mat, int width, int height)
{
    // The total number of elements in the matrix is
    // the number of columns times the number of rows
    //
    mat-&gt;values = malloc(width * height * sizeof(int));
    if (mat-&gt;values == NULL) {
        fprintf(stderr, "Out-of-memory");
        return false;
    }

    mat-&gt;width  = width;
    mat-&gt;height = height;
    return true;
}

//
// To access a given 2D index, now that the matrix is flat, you'll need to 
// calculate the proper offsets with the formula: 'x + y * width'
//
// To simplify element access, I suggest defining a couple helper functions:
//

int getMatrixElement(const Matrix * mat, int x, int y)
{
    return mat-&gt;values[x + (y * mat-&gt;width)];
}

void setMatrixElement(Matrix * mat, int x, int y, int value)
{
    mat-&gt;values[x + (y * mat-&gt;width)] = value;
}