传递const大小的二维数组

时间:2013-07-16 23:29:34

标签: c++ c multidimensional-array parameter-passing

如何使用常量大小的数组:

const int m = 5, n = 3;
int arr[m][n];

以兼容C89和C ++的方式传递给函数吗?

void func(const int m, const int n, int arr[][n]) { }

是无效的C ++(给出错误,例如“不允许参数”和“变量'n'未在此范围内声明”),即使arr的大小在编译时是确定的。 (但它是有效的C.)#define mn有效但由于范围问题而不是首选。将指针传递给数组的第一个元素会导致函数体中出现丑陋的代码。

请随意查看this FAQ上下文。

5 个答案:

答案 0 :(得分:2)

我试过这段代码:

void func(const int m, const int n, int arr[][n])
{
  printf("%d\n", arr[4][2]);
}

int             main()
{
 const int m = 5, n = 3;
 int arr[m][n];

 arr[4][2] = 10;
 func(m, n, arr);
}

并且这项工作没有任何警告

答案 1 :(得分:2)

在C ++中,您可以使用模板和数组引用函数参数将数组传递给具有完整类型信息的函数:

template <unsigned M, unsigned N>
void func (int (&arr)[M][N]) {
    //...
}

您正在使用的函数原型使用名为VLA的C99功能来提供数组维度的动态绑定。这不是C ++特性,尽管一些C ++编译器允许它作为C ++语言的扩展。

C-FAQ是在C99批准之前编写的,因此可变长度数组功能还不是C的标准功能。对于支持VLA的现代C编译器,您提供的函数原型工作正常。

如果您的旧编译器没有VLA支持,则可以使用另一种方法。那就是将二维数组视为一个扁平的一维数组,并使用手动计算来索引正确的整数:

void func(const int m, const int n, void *p) {
    int *a = p;
    int i, j;

    for (i = 0; i < m; ++i) {
        for (j = 0; j < n; ++j) {
            printf(" %d", a[i*n + j]);
        }
        puts("");
    }
}

然后你致电func(m, n, arr)。在函数的侧面,表达式

a[i*n + j]

逐步n inti次,然后逐步j int秒。由于每行的长度为n int,因此计算会返回i行和j列,这与arr[i][j]精确对应。

答案 2 :(得分:0)

这里的问题是C ++中对动态数组的“缺失”支持。

const int m = 5, n = 3;
int arr[m][n];

可以使用,因为m和n是编译时常量,可以直接在数组的声明中访问。

void func(const int m, const int n, int arr[][n]) { }

编译器处理您的函数,无论它在何处被调用。 因此n是未知/可变的,因此被禁止作为数组维度。

由于同样的原因,以下示例也不起作用:

void foo (const int n)
{
  int arr[n]; // error, n is const but not compile time constant
}

int main (void) 
{ 
  foo(4);
}

jxh answered该怎么做。

答案 3 :(得分:0)

你的数组arr [m] [n]不是常数。但是你有常量变量M和N.你还应该将arr [m] [n]定义为常量而不仅仅是一个int数组。

答案 4 :(得分:0)

您可能需要考虑动态分配数组,以便只需向下传递指针地址。

const int m = 5, n = 3;
int i = 0;
int* *arr; //Pointer to an integer pointer (Note can also be int **arr or int** arr)

arr = malloc(sizeof(int*)*(m+1)); //I add one because I am assuming that 'm' does not account for the terminating null character. But if you do not need a terminating null then you can remove this and the perantheses around the 'm'.

for(i = 0; i < m; i++)
{
    arr[i] = malloc(sizeof(int*)*(n+1)); //Same as before
}

inital malloc()调用为整数数组数组分配内存,或者用另一种方式表示,它会为一系列其他指针分配指针。 for循环将为原始数组的每个元素分配一个'm'大小的整数数组,或者说它将为原始指针地址指向的每个指针地址分配空间。我省略了错误检查,以便简化我的示例,但这里是错误检查的相同示例。

const int m = 5, n = 3;
int i = 0;
int* *arr = NULL;

if((arr = malloc(sizeof(int*)*(m+1))) == NULL)
{
   perror("ERROR(1): Failed to allocate memory for the initial pointer address ");
   return 1;
}

for(i = 0; i < m; i++)
{
   if((arr = malloc(sizeof(int*)*(m+1))) == NULL)
   {
      perror("ERROR(2): Failed to allocate memory for a subsequent pointer address ");
      return 2;
   }
}

现在您已经动态分配了数组,您只需传递指针地址即可。 int * * arr在下面的方式。

void fun(const int n, const int m, int* *arr) {}

如果大小是常量并且使用空终止数组,则不一定要跟踪数组的大小。你只需要使用常量整数变量的实际值来malloc数组,然后在迭代抛出数组时检查终止空字节。

int* *arr = NULL;

if((arr = malloc(sizeof(int*)*6)) == NULL)'m'+1 = 6;
{
   perror("ERROR(1): Failed to allocate memory for the initial pointer address ");
   return 1;
}

for(i = 0; i < m; i++)
{
   if((arr = malloc(sizeof(int*)*4) == NULL)//'n'+1 = 4
   {
      perror("ERROR(2): Failed to allocate memory for a subsequent pointer address ");
      return 2;
   }
}

然后,您可以按以下方式显示整个二维数组。请注意,'\ 000'是空字节(00000000)的八角形值。

int i, j;
for(i = 0; arr[i] != '\000'; i++)
{
    for(j = 0; arr[i][j] != '\000'; j++)
    {
      printf("%i ", arr[i][j]); //Prints the current element of the current array
    }

    printf("\n"); //This just ends the line so that each of the arrays is printed on it's own line. 
}

当然,上面提到的循环将具有与以下相同的结果。

int i, j;
int m = 5;
int n = 3;

for(i = 0; i < m; i++)
{
    for(j = 0; i < n; j++)
    {
      printf("%i ", arr[i][j]); //Prints the current element of the current array
    }

    printf("\n"); //This just ends the line so that each of the arrays is printed on it's own line. 
}

这意味着,在大多数情况下,不需要跟踪数组的大小,但有些情况下是必要的。例如,如果一个数组可能包含一个空字节而不是终止空字节。新的空字节会将数组的大小缩短为新的空字节的索引。如果您有任何问题或意见,请随时在下面发表评论或给我发消息。