接受 const 二维数组的 C 函数 [英] C function that takes const 2d array

查看:39
本文介绍了接受 const 二维数组的 C 函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想编写一个将动态二维数组作为输入但不改变数组的 C 函数.

I want to write a C function that takes a dynamic 2D array as an input, but doesn't alter the array.

我试图保持 const 正确,不仅是为了让我的代码更清晰,而且因为我的函数将从 C++ 代码中调用,而 C++ 对这些事情非常挑剔.

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.

如何声明一个函数以将const"指针指向一个指针,即如何指示该函数不会改变二维数组的内容?

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?

接下来是一个具体的、超级简单的例子.我正在使用一个二维双精度数组,即双**,来表示一个大小为 n x n 的 C 方阵,我想编写一个函数来计算这些矩阵之一的迹:

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
", sqr_matrix_trace(a, n));
  printf("trace is %g
", sqr_matrix_trace_const(a, n));
  printf("trace is %g
", sqr_matrix_trace_const((const double * const *)a, n));
  sqr_matrix_free(a, n);
}

在上面,跟踪函数的两个版本,sqr_matrix_trace() 和 sqr_matrix_trace_const() 编译干净(后者是我更喜欢的一个,因为它清楚地表明它不会改变给定的矩阵),但是打电话

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)

产生以下警告:

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)

但是使用强制转换来克服编译器的不便感觉是错误的.

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?

推荐答案

C const 提升规则不允许从 T ** 提升到 constT const *.根据 6.5.16.1 1(适用于函数调用以及根据 6.5.2.2 2 的赋值),指针的转换只能向指向的类型添加限定符.

The C const promotion rules don't allow promotion from T ** to const T const *. Per 6.5.16.1 1 (which applies to function calls as well as assignments per 6.5.2.2 2), conversion of pointers can only add qualifiers to the pointed-to type.

这是为了防止类似的代码(例如 6.5.16.1 6):

This is to prevent code like (example from 6.5.16.1 6):

const char **cpp;
char *p;
const char c = 'A';
cpp = &p; // constraint violation
*cpp = &c; // valid
*p = 0; // valid

观察到 const *const *cpp = &p 是安全的是正确的,因为这样 *cpp = &c 被阻止了,但这是一个足够模糊的标准中未涵盖的情况.

It's correct to observe that const *const *cpp = &p is safe because then *cpp = &c is prevented, but this is a sufficiently obscure case that it's not covered in the standard.

结论:您可以并且应该自己转换为 const double *const *.

Conclusion: you can and should cast to const double *const * yourself.

请注意,使用长度为 n * ndouble * 类型的单个数组并自己进行任何必要的数组索引会更有效:d[i][j] 变成 d[i * n + j].

Note that it would be more efficient to use a single array of type double * with length n * n and do any necessary array indexing yourself: d[i][j] becomes d[i * n + j].

这篇关于接受 const 二维数组的 C 函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆