1

一个恒定大小的数组应该如何:

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。) #defineingm并且n可以工作,但由于范围问题而不是首选。将指针传递给数组的第一个元素会导致函数体中出现丑陋的代码。

请随时查看此常见问题解答以了解上下文。

4

5 回答 5

3

在 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 intsi次,然后跨过j ints。由于每行都是n ints 长,因此计算返回第ith 行和第jth 列,精确对应于arr[i][j]

于 2013-07-17T00:18:39.690 回答
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);
}

这项工作没有任何警告

于 2013-07-16T23:56:51.113 回答
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 回答了该怎么做。

于 2013-07-17T00:30:14.290 回答
0

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

于 2013-07-17T01:14:50.450 回答
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
}

初始 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) {}

此外,如果大小是恒定的并且如果您使用以空值结尾的数组,则不必跟踪数组的大小。您只需使用常量整数变量的实际值对数组进行 m​​alloc,然后在迭代抛出数组时检查终止的空字节。

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. 
}

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

于 2013-07-17T01:56:37.363 回答