You are doing too many allocations. The usual way of implementing multidimensional array is to allocate one continuous buffer and map n-dimensional coordinate to a 1-dimensional one. You then provide get and set functions so that client doesn't have to do the mapping themselves. The functions are pretty simple and you can make them inline.
double ArrayGet(const struct Array * array, size_t x, size_t y) {
return *(array->data + x + y * array->cols);
}
Additionally, you can avoid allocating the struct itself on heap and put it on stack instead. For this you need 2 more functions, but you can reuse them in ArrayNewArrayNew and ArrayFreeArrayFree.
int main()
{
struct Array array;
ArrayInit(&array, 2, 4);
// write some values
ArrayPrint(&array);
ArrayRelease(&array);
}
If you want to go even further and you know the dimensions at compile time, you can put the data buffer on stack as well and just use its address, so avoiding dynamic memory allocation entirely.
int main()
{
double data[8];
struct Array array;
array.rows = 2;
array.cols = 4;
array.data = data;
// write some values
ArrayPrint(&array);
}
EDIT:
alsoAlso notice that you can traverse all elements of the matrix using (x, y) coordinate while internally traversing the one dimensional data buffer in order which is friendly to cached memory access. And you also avoid the few extra instructions for mapping the coordinates. Just make sure your for loops start with y and track the 1-dimensional coordinate i separately.
void ArrayPrint(struct Array * array)
{
size_t i;
// using size_t as everywhere else...
for (size_t y = 0, i = 0; y < array->rows; ++y) {
for (size_t x = 0; x < array->cols; ++x, ++i) {
printf("%.2lf ", array->data[i]);
}
printf("\n");
}
// no return is needed on the end of void function
}