I want to write a C function that takes a dynamic 2D array as an input, but doesn't alter the array.
I'm trying to be const correct, not only to make my code clearer, but because my functions are going to be called from within C++ code, and C++ is pretty persnickety about these things.
How do I declare a function to take 'const' pointer to a pointer, i.e. how do I indicate that the function will not alter the contents of the 2d array?
What follows is a specific, super-simple example. I'm using a 2D array of doubles, i.e. double**, to represent a square matrix in C of size n x n, and I want to write a function that computes the trace of one of these matrices:
#include <stdlib.h>
#include <stdio.h>
double **sqr_matrix_new(int n)
{
double **a = calloc(n, sizeof(double*));
int i;
for (i=0; i < n; ++i) a[i] = calloc(n, sizeof(double));
return a;
}
void sqr_matrix_free(double **a, int n)
{
int i;
for (i=0; i < n; ++i) free(a[i]);
free(a);
}
double sqr_matrix_trace(double **a, int n)
{
double trace;
int i;
for (i=0, trace=0.0; i < n; ++i) trace += a[i][i];
return trace;
}
double sqr_matrix_trace_const(const double * const *a, int n)
{
double trace;
int i;
for (i=0, trace=0.0; i < n; ++i) trace += a[i][i];
return trace;
}
int main(int argc, char *argv[])
{
int n = 10;
double **a = sqr_matrix_new(n);
int i, j, k;
for (i=0, k=0; i < n; ++i){
for (j=0; j < n; ++j) a[i][j] = k++;
}
printf("trace is %g\n", sqr_matrix_trace(a, n));
printf("trace is %g\n", sqr_matrix_trace_const(a, n));
printf("trace is %g\n", sqr_matrix_trace_const((const double * const *)a, n));
sqr_matrix_free(a, n);
}
In the above, both versions of the trace function, sqr_matrix_trace() and sqr_matrix_trace_const() compile cleanly (the latter is the one I prefer because it clearly demonstrates that there will be no alteration of the matrix it's given), but the call
sqr_matrix_trace_const(a, n)
produces the following warning:
sqr_matrix.c: In function 'main':
sqr_matrix.c:44: warning: passing argument 1 of 'sqr_matrix_trace_const' from incompatible pointer type
sqr_matrix.c:27: note: expected 'const double * const*' but argument is of type 'double **'
The cast overcomes this:
sqr_matrix_trace_const((const double * const *)a, n)
but it feels wrong to use a cast to use to overcome compiler inconveniences.
Alternatively, I could suppress the compiler warning, but that's a cop-out.
So, I want my code to compile cleanly and I want to convey the const-ness of a dynamic 2D array given to a function without resorting to a cast. It seems like a legitimate aim. Is this possible? If not, what's the standard/accepted practice for doing this?