It seems that you want to pass the address of a pointer to your freeDoubleArr like freeDoubleArr(&G, numnodes) (which I would rather call deleteDoubleArr). Then you need to have
void freeDoubleArr(double ***arrptr, int size)
{
double** arr = *arrptr;
for (int i = 0; i < size; i++)
free(arr[i]);
free (arr);
*arrptr = NULL;
}
However, you could decide that your square matrix is not represented as an array of pointers to arrays, but just as a plain array. Perhaps using flexible array members (of C99 and later) like
struct matrix_st {
unsigned size;
double arr[]; /* flexible array of size*size elements */
};
could be useful, with the convention that arr is really an array of size*size elements (each being a double).
Then you can define quick access and mutator inline functions.
inline double get_element(struct matrix_st *m, int i, int j) {
assert (m != NULL);
unsigned s = m->size;
assert (i>=0 && i<s && j>=0 && j<s);
return m->arr[s*i+j];
}
inline void put_element(struct matrix_st* m, int i, int j, double x) {
assert (m != NULL);
unsigned s = m->size;
assert (i>=0 && i<s && j>=0 && j<s);
m->arr[i*s+j] = x;
}
When optimizing and with <assert.h> (see assert(3) ...) and compiling with -DNDEBUG the above accessor get_element and mutator put_element would be perhaps faster than your code.
And the matrix creation is just (to create a zero-ed matrix):
struct matrix_st* make_matrix (unsigned size) {
struct matrix_st* m = malloc(sizeof (struct matrix_st)
+ size*size*sizeof(double);
if (!m) { perror("malloc"); exit(EXIT_FAILURE); };
m->size = size;
memset(m->arr, 0, sizeof(double)*size*size);
return m;
}
Then the user could just use one single call to free to free such a matrix.
BTW, if coding on Linux, compile with gcc -Wall -g and use valgrind memory leak detector and gdb debugger.