如何将非const动态多维数组传递给想要const多维数组的函数?

时间:2018-07-19 23:32:10

标签: c multidimensional-array dynamic parameter-passing const

我已经在 C 中编写了以下函数,以打印出动态创建的矩阵,但要保证在函数I内

  1. 无法修改我得到的指针
  2. 不能修改任何内部指针
  3. 不能修改矩阵中的任何数字

class CustomButton: UIButton {
    var isFocusable = true 
    canBecomeFocused: Bool {
        return isFocusable
    }
}

我尝试如下在main中调用该函数

 void const2dPrinter(const int *const *const mat, const int numRows, const int numCols){
  for(int i =0; i < numRows; ++i){
    for(int j =0; j < numCols; ++j){
      printf("%d ", mat[i][j]);
    }
    printf("\n");
  }
 }

但是我从编译器中收到以下错误

int main(){
  int numRows = 3;
  int numCols = 4;
  int** mat = (int**) malloc(numRows * sizeof(int*);
  for(int i = 0; i < numRows; ++i){
    mat[i] = (int*)malloc(numCols * sizeof(int));
    for(int j = 0; j < numCols; ++j){
      mat[i][j] = (i +1) * (j+1);
    }
  }
  const2dPrinter(mat, numRows, numCols);
...
}

我的IDE出现以下错误:

error: passing argument 1 of 'const2dPrinter' from incompatible pointer type [-Werror=incompatible-pointer-types]
   const2dPrinter(mat, numRows, numCols);
note: expected 'const int * const* const' but argument is of type 'int **'
   void const2dPrinter(const int *const *const const mat, const int numRows, const int numCols)

如果我在函数声明中删除第一个const,则代码将起作用。来自    void const2dPrinter( const int * const * const mat,...){

到    void const2dPrinter(int * const * const mat,...){

但是我可以在const2dPrinter中修改矩阵的值,而我不想这么做。

我知道我可以在调用函数以使事情正常工作时将Parameter type mismatch: Assigning int** to const int* const* const* discards const qualifier. 强制转换为int**,如下所示,但是我对为什么现在拥有的功能感到困惑正如我所阅读的所有内容所说,您应该能够将const指针指向非const值。

const int *const *const

我尝试搜索解决方案,但找不到。该代码可以在C ++编译器上编译而不会出现问题,但无法在我的C编译器(gcc)上运行。

任何有关如何解决我的问题的建议以及为什么我现在的东西都行不通的解释将不胜感激。

2 个答案:

答案 0 :(得分:2)

您必须编写难看的演员表(尽管最后一个const是多余的)。在C规范中,没有一个隐式转换,无法将T **更改为T const * const *

我认为在实践中,由于这个问题,人们倾向于最终不使用const,因为在这种情况下将存在指向指针的指针或指向数组的指针。您可以使用强制转换和/或通用选择器等来解决该问题,但是为了支持应该是简单的操作,事情似乎很快变得复杂起来。


对于您的特定情况,另一种方法可能是使用一维数组存储矩阵。 (由于需要较少的分配,这可能会在运行时效率更高。)

答案 1 :(得分:1)

要将参数作为常量指针传递给 constant int ,您希望参数为:

void const2dprinter (const int* const* mat, const int numrows, const int numcols)

无需强制返回malloc,这是不必要的。请参阅:Do I cast the result of malloc?。您的分配还应使用取消引用的指针,以确保始终获得正确的类型大小,例如

    int **mat = malloc (numrows * sizeof *mat);
    ...
        mat[i] = malloc (numcols * sizeof *mat[i]);

现在养成良好的习惯。如果分配内存,则对分配的任何内存块都有2个职责:(1)始终为该内存块保留指向起始地址的指针,因此,(2 ),可以在不再需要时将其释放。跟踪分配的内容,然后free内存,然后再丢失指针。只需一个简单的免费功能即可,例如

void mat_free (int **mat, const int numrows)
{
    for (int i = 0; i < numrows; i++)
        free (mat[i]);      /* free rows */
    free (mat);             /* free pointers */
}

将其完全放在一起,您可以执行以下操作:

#include <stdio.h>
#include <stdlib.h>

void const2dprinter (const int* const* mat, const int numrows, const int numcols)
{
    for (int i =0; i < numrows; ++i){
        for(int j =0; j < numcols; ++j)
            printf("%d ", mat[i][j]);
        printf("\n");
    }
}

void mat_free (int **mat, const int numrows)
{
    for (int i = 0; i < numrows; i++)
        free (mat[i]);      /* free rows */
    free (mat);             /* free pointers */
}

int main (void) {

    int numrows = 3;
    int numcols = 4;
    int **mat = malloc (numrows * sizeof *mat);

    for (int i = 0; i < numrows; ++i) {
        mat[i] = malloc (numcols * sizeof *mat[i]);
        for (int j = 0; j < numcols; ++j)
            mat[i][j] = (i +1) * (j+1);
    }
    const2dprinter ((int const * const *)mat, numrows, numcols);
    mat_free (mat, numrows);
}

使用/输出示例

$. /bin/mat_const_int_2d
1 2 3 4
2 4 6 8
3 6 9 12

仔细研究一下,如果您有任何疑问,请告诉我。