为什么在将2D数组作为参数传递时需要指定列大小?

Hoo*_*lum 33 c arrays parameters parameter-passing multidimensional-array

为什么我的参数不能

void example(int Array[][]){ /*statements*/}
Run Code Online (Sandbox Code Playgroud)

为什么我需要指定数组的列大小?比如说3

void example(int Array[][3]){/*statements*/}
Run Code Online (Sandbox Code Playgroud)

我的教授说它是强制性的,但我在学校开始之前编码,我记得当我把它作为我的参数时没有语法或语义错误?还是我错过了什么?

Mak*_*zin 33

在描述参数时,数组总是衰减成指向第一个元素的指针.

当你传递一个声明为int Array[3]函数的数组时void foo(int array[]),它会衰减成一个指向数组开头的指针,即int *Array;.顺便说一句,您可以将参数描述为int array[3]int array[6]int *array至 - 所有这些都是等效的,您可以毫无问题地传递任何整数数组.

在阵列阵列(2D阵列)的情况下,它也会衰减到指向其第一个元素的指针,这恰好是一个单维数组,即我们得到的int (*Array)[3].

在此指定大小非常重要.例如,如果它不是强制性的,那么编译器就没有办法知道如何处理表达式Array[2][1].

要取消引用编译器需要在连续的内存块中计算所需项的偏移量(int Array[2][3]是一个连续的整数块),这对于指针应该很容易.如果a是指针,则a[N]展开为start_address_in_a + N * size_of_item_being_pointed_by_a.如果Array[2][1]在函数内部表达式(我们想要访问此元素),Array则是指向单维数组的指针,并且应用相同的公式.需要查找最后一个方括号中的字节数size_of_item_being_pointed_by_a.如果我们只是Array[][]不可能找到它,因此不可能取消引用我们需要的数组元素.

没有大小,指针算术不适用于数组的数组.会Array + 2产生什么地址:提前Array2个字节(错误)推进地址或提前指针3* sizeof(int) * 2字节?

  • “(注意,一个指针数组而不是它的第一个元素)”这没有意义或不清楚。当数组衰减为指针时,它总是成为指向其第一个元素的指针。二维数组的第一个元素是一维数组;因此二维数组衰减为指向一维数组的指针。`int (*)[3]` 类型是指向数组的指针的类型。 (2认同)

pen*_*ope 11

在C/C++中,甚至2-D数组也按顺序存储,在内存中依次存储.所以,当你有(在一个函数中):

int a[5][3];
int *head;

head = &a[0][0];
a[2][1] = 2; // <--
Run Code Online (Sandbox Code Playgroud)

您实际访问的元素a[2][1]*(head + 2*3 + 1),顺序地,该元素在该0行的3个元素之后,以及该行的3个元素之后1,然后再一个索引.

如果你声明一个像这样的函数:

void some_function(int array[][]) {...}
Run Code Online (Sandbox Code Playgroud)

语法上,它不应该是一个错误.但是,当您尝试array[2][3]现在访问时,您无法分辨应该访问哪个元素.另一方面,当你有:

void some_function(int array[][5]) {...}
Run Code Online (Sandbox Code Playgroud)

你知道吗array[2][3],可以确定你实际上是在内存地址访问元素,*(&array[0][0] + 2*5 + 3) 因为函数知道第二个维度的大小.

还有另外一个选项,如前所述,您可以声明如下函数:

void some_function(int *array, int cols) { ... }
Run Code Online (Sandbox Code Playgroud)

因为这样,您使用与以前相同的"信息"调用函数 - 列数.您可以稍微不同地访问数组元素:您必须编写*(array + i*cols + j)通常写入的位置array[i][j],因为array现在是指向整数(而不是指针)的指针.

当您声明这样的函数时,您必须小心地使用实际为该数组声明的列数来调用它,而不仅仅是使用它.所以,例如:

int main(){
   int a[5][5];
   int i, j;

   for (i = 0; i < 3; ++i){
       for (int j=0; j < 3; ++j){
           scanf("%d", &a[i][j]);
       }
   }

   some_function(&a[i][j], 5); // <- correct
   some_function(&a[i][j], 3); // <- wrong

   return 0;
}
Run Code Online (Sandbox Code Playgroud)