動的 2D 配列を入力として受け取り、配列を変更しない C 関数を作成したいと考えています。
コードをより明確にするためだけでなく、関数が C++ コード内から呼び出されるため、const を正しくしようとしています。C++ はこれらのことについてかなり熱心です。
ポインタへの 'const' ポインタを取る関数を宣言するにはどうすればよいですか。つまり、関数が 2 次元配列の内容を変更しないことを示すにはどうすればよいですか?
以下は、具体的で非常に単純な例です。サイズ nxn の C の正方行列を表すために double の 2D 配列、つまり double** を使用しています。これらの行列の 1 つのトレースを計算する関数を書きたいと思います。
#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);
}
上記では、トレース関数 sqr_matrix_trace() と sqr_matrix_trace_const() の両方のバージョンがきれいにコンパイルされます (与えられた行列が変更されないことが明確に示されているため、後者の方が好みです)。
sqr_matrix_trace_const(a, n)
次の警告が生成されます。
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 **'
キャストはこれを克服します:
sqr_matrix_trace_const((const double * const *)a, n)
しかし、コンパイラの不便さを克服するためにキャストを使用するのは間違っていると感じます。
または、コンパイラの警告を抑制することもできますが、それは失敗です。
そのため、コードをきれいにコンパイルし、キャストに頼らずに関数に与えられた動的 2D 配列の const 性を伝えたいと考えています。正当な目的のようです。これは可能ですか?そうでない場合、これを行うための標準/受け入れられている方法は何ですか?