C++ Matrix Multiplication Using Classes
I will be assuming that you use at least C++11. It also seems that you are coming from C, is that correct?


double (*matrix_a)[ncols] = (double (*)[ncols])malloc(sizeof(double) * (nrows) * (ncols));:

There is no reason to use dynamic allocation, ncols and nrows are constant expressions!. Just use double matrix_a[ncols][nrows]; or better std::array&lt;std::array&lt;double,ncols&gt;,nrows&gt; matrix_a;. That said you usually want to have dynamic sizes or your matrix may be larger than the stack limit. Then you should use std::vector&lt;std::vector&lt;double&gt;&gt; matrix_a{nrows, {ncols}}. C-style arrays and dynamic allocation should always be limited as much as possible. Using proper class objects wrapping them is much safer. std::vector will take care of all memory management for you. If you are concerned that std::vector will layout rows non-continuously, then use std::vector&lt;double&gt; matrix_a{nrows*ncols} instead and properly access the elements by ncols*row+col.

Also, in C++, you do not use malloc and free. Instead you use new and delete. The difference is that new not only allocates memory but also constructs the object in that memory. In most cases you would need to manually construct the object in the allocated space (although for double it is technically ok here).
You should not declare a free method, but rather everything freeing memory belongs in the destructor, which is automatically called as soon as the object itself goes out of scope or is destroyed:

~matrix()
{
     free(matrix_a); // should be "delete[] matrix_a;"
     free(matrix_b); // ^^^
     free(matrix_c); // ^^^
}


Note that you would not need a destructor if you were using std::array or std::vector.

If you stick to dynamic memory allocation, you probably also need to implement a custom copy and/or move constructor and assignment operator.
The whole idea of a class is that it represents a certain closed/separate entity. Your class does not follow this, it is merely a wrapper to call the multilication method. If you were following OOP principles, you would create a class matrix holding one of the matrices with an overloaded operator+(const matrix&amp;), operator*(const matrix&amp;) and so on, then create two matrix instances in main and call * on them. Like so:

class Matrix {
private:
    std::size_t ncol;
    std::site_t nrow;
    std::vector&lt;double&gt; storage;
public:
    Matrix() : storage() {}
    Matrix(std::size_t ncol, std::size_t nrow) : ncol(ncol), nrow(nrow), storage(ncol*nrow) {}

    std::size_t getColCount() const { return ncol; }
    std::size_t getRowCount() const { return nrow; }

    double getAt(std::size_t col, std::size_t row) { [implement this] }
    Matrix operator+(const Matrix&amp; other) const { [implement this] }
    Matrix operator*(const Matrix&amp; other) const { [implement this] }
    [other operators...]

    static Matrix randomMatrix(std::size_t ncol, std::size_t nrow) { [ implement this ] }
};

int main() {
    Matrix matrixA = Matrix::randomMatrix();
    Matrix matrixB = Matrix::randomMatrix();
    Matrix matrixC = matrixA*matrixB;
}