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

时间:2022-12-06 21:47:36

Why can't my parameter be

为什么我的参数不能是

void example(int Array[][]){ /*statements*/}

Why do I need to specify the column size of the array? Say for example, 3

为什么需要指定数组的列大小?例如,3

void example(int Array[][3]){/*statements*/}

My professor said its mandatory, but I was coding before school started and I remembered that there was no syntactical or semantic error when I made this my parameter? Or did I miss something?

我的教授说这是强制性的,但是我在学校开始之前就已经编码了,我记得我的参数是没有语法和语义错误的。还是我漏掉了什么?

6 个解决方案

#1


27  

When it comes to describing parameters, arrays always decay into pointers to their first element.

当涉及到描述参数时,数组总是会衰减成指向第一个元素的指针。

When you pass an array declared as int Array[3] to the function void foo(int array[]), it decays into a pointer to the beginning of the array i.e. int *Array;. Btw, you can describe a parameter as int array[3] or int array[6] or even int *array - all these will be equivalent and you can pass any integer array without problems.

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

In case of arrays of arrays (2D arrays), it decays to a pointer to its first element as well, which happens to be a single dimensional array i.e. we get int (*Array)[3].

对于数组(2D数组),它也会衰减到指向它的第一个元素的指针,这恰好是一个一维数组,也就是说我们得到int (* array)[3]。

Specifying the size here is important. If it were not mandatory, there won't be any way for compiler to know how to deal with expression Array[2][1], for example.

在这里指定大小是很重要的。如果不是强制的,编译器就不会知道如何处理表达式数组[2][1],例如。

To dereference that a compiler needs to compute the offset of the item we need in a contiguous block of memory (int Array[2][3] is a contiguous block of integers), which should be easy for pointers. If a is a pointer, then a[N] is expanded as start_address_in_a + N * size_of_item_being_pointed_by_a. In case of expression Array[2][1] inside a function (we want to access this element) the Array is a pointer to a single dimensional array and the same formula applies. The number of bytes in the last square bracket is required to find size_of_item_being_pointed_by_a. If we had just Array[][] it would be impossible to find it out and hence impossible to dereference an array element we need.

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

Without the size, pointers arithmetics wouldn't work for arrays of arrays. What address would Array + 2 produce: advance the address in Array 2 bytes ahead (wrong) or advance the pointer 3* sizeof(int) * 2 bytes ahead?

如果没有这个大小,指针算法就不会对数组的数组起作用。数组+ 2会产生什么地址:将地址提前2字节(错误)或者提前3* sizeof(int) * 2字节?

#2


10  

In C/C++, even 2-D arrays are stored sequentially, one row after another in memory. So, when you have (in a single function):

在C/ c++中,甚至连2-D数组都是按顺序存储的,一行接一行地存储在内存中。所以,当你有(在单个函数中)

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

head = &a[0][0];
a[2][1] = 2; // <--

The element you are actually accessing with a[2][1] is *(head + 2*3 + 1), cause sequentially, that element is after 3 elements of the 0 row, and 3 elements of the 1 row, and then one more index further.

实际上,使用[2][1]访问的元素是*(head + 2*3 + 1),因为按顺序,该元素位于0行的3个元素和1行的3个元素之后,然后还有一个索引。

If you declare a function like:

如果您声明一个函数,如:

void some_function(int array[][]) {...}

syntactically, it should not be an error. But, when you try to access array[2][3] now, you can't tell which element is supposed to be accessed. On the other hand, when you have:

从句法上讲,它不应该是一个错误。但是,当您尝试访问数组[2][3]时,您无法判断应该访问哪个元素。另一方面,当你有:

void some_function(int array[][5]) {...}

you know that with array[2][3], it can be determined that you are actually accessing element at the memory address *(&array[0][0] + 2*5 + 3) because the function knows the size of the second dimension.

您知道,对于数组[2][3],可以确定您实际上正在访问内存地址*(&array[0][0] + 2*5 + 3)处的元素,因为函数知道第二个维度的大小。

There is one other option, as previously suggested, you can declare a function like:

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

void some_function(int *array, int cols) { ... }

because this way, you are calling the function with the same "information" as before -- the number of columns. You access the array elements a bit differently then: you have to write *(array + i*cols + j) where you would usually write array[i][j], cause array is now a pointer to integer (not to a pointer).

因为通过这种方式,您调用的函数具有与以前相同的“信息”——列的数量。你对数组元素的访问有点不同:你必须写*(数组+ i*cols + j)在那里你通常会写数组[i][j],因为数组现在是一个指向整型的指针(不是指向指针)。

When you declare a function like this, you have to be careful to call it with the number of columns that are actually declared for the array, not only used. So, for example:

当您像这样声明一个函数时,您必须小心地使用实际为数组声明的列数来调用它,而不仅仅是使用。举个例子:

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

#3


0  

There is a similar post regarding this. You can refer below link. Creating Array in C and passing pointer to said array to function Hope it helps.

关于这一点也有类似的文章。你可以参考下面的链接。在C中创建数组,并将指针传递给所述数组以函数,希望这能有所帮助。

On the other hand, compiler needs to the second dimension so that it can move "Array" from one pointer to next since the whole memory is arranged in a linear fashion

另一方面,编译器需要第二个维度,这样它就可以从一个指针移动到下一个指针,因为整个内存是以线性方式排列的。

#4


-1  

When you create a 2D array, anytype a[3][4], in memory what you actually create is 3 contiguous blocks of 4 anytype objects.

当你创建一个2D数组时,anytype a[3][4],在内存中你实际创建的是3个相邻的块,包含4个anytype对象。

a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3]

一个[0][0][0][1]一个[0][2][0][3][1][0]一个[1][1]一个[1][2][1][3][2][0]一个[2][1][2][2][2][3]

Now the next question is, why is that so? Because, keeping with the spec and structure of the language, anytype a[3][4] actually expands out into anytype (*a)[4], because arrays decay into pointers. And in fact that also expands out into anytype (*(*a)), however, you've now completely lost the size of the 2D array. So, you must help the compiler out a bit.

下一个问题是,为什么是这样?因为,按照语言的规范和结构,任何类型的[3][4]实际上扩展为任何类型(*a)[4],因为数组会衰减为指针。实际上,它也扩展为any类型(*(*a)),但是,您现在完全失去了2D数组的大小。因此,您必须帮助编译器解决一些问题。

If you ask the program for a[2], the program can follow the exact same steps that it does for 1D arrays. It simply can return the 3rd element of sizeof(object pointed to), the object pointed to here is of size 4 anytype objects.

如果您向程序请求[2],程序可以按照与一维数组相同的步骤执行。它可以返回sizeof(对象指向)的第3个元素,指向这里的对象是大小为4的anytype对象。

#5


-1  

It all has to do with internal array representation. So array like int arr_2 [2][2] = {{1,2},{3,4}}; looks in memory like 1,2,3,4 each being integer type. arr_2 is roughly equivalent to &arr[0][0] (pointer to the first element) when passed to a function.

这都与内部数组表示有关。比如int arr_2 [2][2] = {{{1,2} {3,4}};在内存中看起来像1、2、3、4每个都是整数类型。当传递给一个函数时,arr_2大致等同于&arr[0][0](指向第一个元素的指针)。

Usual arrays are stored and accessed similarly int arr[2] = {2,5}; in memory 2,5. Compiler gets to them through their base plus offset times type base_ptr + index * type. To get value stored at index 1 of type int we write &arr[0] + 1 * sizeof(int) = 5

通常的数组被存储和访问类似的int arr[2] = {2,5};在内存中2 5。编译器通过它们的基加上偏移量乘以类型base_ptr + index *类型访问它们。要获取类型为int的索引1的值,我们写入&arr[0] + 1 * sizeof(int) = 5

So two dimensional arrays are accessed like so base_ptr + type * 2nd_dem_len + index. To get value stored at [1][1] we write &arr_2[0][0] + sizeof(int) * 1 + 1 = 4

二维数组的访问方式类似于base_ptr + type * 2nd_dem_len + index。要获取存储在[1][1]的值,我们编写&arr_2[0][0] + sizeof(int) * 1 + 1 = 4

So if the compiler doesn't know 2nd_dem_len or length of second dimension it cannot access that array. It doesn't know it because array gets watered down to that representation when passed to function because compiler converts it to a pointer which has no information about the size.

所以如果编译器不知道2nd_dem_len或第二个维度的长度,它就不能访问这个数组。它不知道,因为数组在传递给函数时被冲淡为那个表示,因为编译器将它转换为一个没有大小信息的指针。

#6


-1  

Actually whether it is a 2d array or a 1d array, it is stored in the memory in a single line.So to say the compiler where should it break the row indicating the next numbers to be in the next rows we are supposed to provide the column size. And breaking the rows appropriately will give the size of the rows.

实际上,无论是二维数组还是一维数组,它都存储在内存中的一行中。也就是说,编译器应该在哪里断行表明下一个数字在下一行我们应该提供列的大小。适当地对行进行拆分将给出行的大小。

Let's see an example:

让我们看一个例子:

int a[][3]={ 1,2,3,4,5,6,7,8,9,0 };

This array a is stored in the memory as:

该数组a存储在内存中,为:

  1  2  3  4  5  6  7  8  9  0

But since we have specified the column size as 3 the memory splits after every 3 numbers.

但是由于我们将列的大小指定为3,所以每3个数字后内存就会分裂。

#include<stdio.h>

int main() {
   int a[][3]={1,2,3,4,5,6},i,j;
   for(i=0;i<2;i++)
   {
       for(j=0;j<3;j++)
       {
           printf("%d  ",a[i][j]);
       }
       printf("\n");
   }

}

OUTPUT:

输出:

 1  2  3  
 4  5  6  

In the other case,

在其他情况下,

int a[3][]={1,2,3,4,5,6,7,8,9,0};

The compiler only knows that there are 3 rows but it doesn't know the number of elements in each row so it cannot allocate memory and will show an error.

编译器只知道有3行,但是它不知道每一行的元素数量,所以它不能分配内存,会显示错误。

#include<stdio.h>

int main() {
   int a[3][]={1,2,3,4,5,6},i,j;
   for(i=0;i<3;i++)
   {
       for(j=0;j<2;j++)
       {
           printf("%d  ",a[i][j]);
       }
       printf("\n");
   }

}

OUTPUT:

输出:

 c: In function 'main':
    c:4:8: error: array type has incomplete element type 'int[]'
    int a[3][]={1,2,3,4,5,6},i,j;
        ^

#1


27  

When it comes to describing parameters, arrays always decay into pointers to their first element.

当涉及到描述参数时,数组总是会衰减成指向第一个元素的指针。

When you pass an array declared as int Array[3] to the function void foo(int array[]), it decays into a pointer to the beginning of the array i.e. int *Array;. Btw, you can describe a parameter as int array[3] or int array[6] or even int *array - all these will be equivalent and you can pass any integer array without problems.

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

In case of arrays of arrays (2D arrays), it decays to a pointer to its first element as well, which happens to be a single dimensional array i.e. we get int (*Array)[3].

对于数组(2D数组),它也会衰减到指向它的第一个元素的指针,这恰好是一个一维数组,也就是说我们得到int (* array)[3]。

Specifying the size here is important. If it were not mandatory, there won't be any way for compiler to know how to deal with expression Array[2][1], for example.

在这里指定大小是很重要的。如果不是强制的,编译器就不会知道如何处理表达式数组[2][1],例如。

To dereference that a compiler needs to compute the offset of the item we need in a contiguous block of memory (int Array[2][3] is a contiguous block of integers), which should be easy for pointers. If a is a pointer, then a[N] is expanded as start_address_in_a + N * size_of_item_being_pointed_by_a. In case of expression Array[2][1] inside a function (we want to access this element) the Array is a pointer to a single dimensional array and the same formula applies. The number of bytes in the last square bracket is required to find size_of_item_being_pointed_by_a. If we had just Array[][] it would be impossible to find it out and hence impossible to dereference an array element we need.

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

Without the size, pointers arithmetics wouldn't work for arrays of arrays. What address would Array + 2 produce: advance the address in Array 2 bytes ahead (wrong) or advance the pointer 3* sizeof(int) * 2 bytes ahead?

如果没有这个大小,指针算法就不会对数组的数组起作用。数组+ 2会产生什么地址:将地址提前2字节(错误)或者提前3* sizeof(int) * 2字节?

#2


10  

In C/C++, even 2-D arrays are stored sequentially, one row after another in memory. So, when you have (in a single function):

在C/ c++中,甚至连2-D数组都是按顺序存储的,一行接一行地存储在内存中。所以,当你有(在单个函数中)

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

head = &a[0][0];
a[2][1] = 2; // <--

The element you are actually accessing with a[2][1] is *(head + 2*3 + 1), cause sequentially, that element is after 3 elements of the 0 row, and 3 elements of the 1 row, and then one more index further.

实际上,使用[2][1]访问的元素是*(head + 2*3 + 1),因为按顺序,该元素位于0行的3个元素和1行的3个元素之后,然后还有一个索引。

If you declare a function like:

如果您声明一个函数,如:

void some_function(int array[][]) {...}

syntactically, it should not be an error. But, when you try to access array[2][3] now, you can't tell which element is supposed to be accessed. On the other hand, when you have:

从句法上讲,它不应该是一个错误。但是,当您尝试访问数组[2][3]时,您无法判断应该访问哪个元素。另一方面,当你有:

void some_function(int array[][5]) {...}

you know that with array[2][3], it can be determined that you are actually accessing element at the memory address *(&array[0][0] + 2*5 + 3) because the function knows the size of the second dimension.

您知道,对于数组[2][3],可以确定您实际上正在访问内存地址*(&array[0][0] + 2*5 + 3)处的元素,因为函数知道第二个维度的大小。

There is one other option, as previously suggested, you can declare a function like:

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

void some_function(int *array, int cols) { ... }

because this way, you are calling the function with the same "information" as before -- the number of columns. You access the array elements a bit differently then: you have to write *(array + i*cols + j) where you would usually write array[i][j], cause array is now a pointer to integer (not to a pointer).

因为通过这种方式,您调用的函数具有与以前相同的“信息”——列的数量。你对数组元素的访问有点不同:你必须写*(数组+ i*cols + j)在那里你通常会写数组[i][j],因为数组现在是一个指向整型的指针(不是指向指针)。

When you declare a function like this, you have to be careful to call it with the number of columns that are actually declared for the array, not only used. So, for example:

当您像这样声明一个函数时,您必须小心地使用实际为数组声明的列数来调用它,而不仅仅是使用。举个例子:

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

#3


0  

There is a similar post regarding this. You can refer below link. Creating Array in C and passing pointer to said array to function Hope it helps.

关于这一点也有类似的文章。你可以参考下面的链接。在C中创建数组,并将指针传递给所述数组以函数,希望这能有所帮助。

On the other hand, compiler needs to the second dimension so that it can move "Array" from one pointer to next since the whole memory is arranged in a linear fashion

另一方面,编译器需要第二个维度,这样它就可以从一个指针移动到下一个指针,因为整个内存是以线性方式排列的。

#4


-1  

When you create a 2D array, anytype a[3][4], in memory what you actually create is 3 contiguous blocks of 4 anytype objects.

当你创建一个2D数组时,anytype a[3][4],在内存中你实际创建的是3个相邻的块,包含4个anytype对象。

a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3]

一个[0][0][0][1]一个[0][2][0][3][1][0]一个[1][1]一个[1][2][1][3][2][0]一个[2][1][2][2][2][3]

Now the next question is, why is that so? Because, keeping with the spec and structure of the language, anytype a[3][4] actually expands out into anytype (*a)[4], because arrays decay into pointers. And in fact that also expands out into anytype (*(*a)), however, you've now completely lost the size of the 2D array. So, you must help the compiler out a bit.

下一个问题是,为什么是这样?因为,按照语言的规范和结构,任何类型的[3][4]实际上扩展为任何类型(*a)[4],因为数组会衰减为指针。实际上,它也扩展为any类型(*(*a)),但是,您现在完全失去了2D数组的大小。因此,您必须帮助编译器解决一些问题。

If you ask the program for a[2], the program can follow the exact same steps that it does for 1D arrays. It simply can return the 3rd element of sizeof(object pointed to), the object pointed to here is of size 4 anytype objects.

如果您向程序请求[2],程序可以按照与一维数组相同的步骤执行。它可以返回sizeof(对象指向)的第3个元素,指向这里的对象是大小为4的anytype对象。

#5


-1  

It all has to do with internal array representation. So array like int arr_2 [2][2] = {{1,2},{3,4}}; looks in memory like 1,2,3,4 each being integer type. arr_2 is roughly equivalent to &arr[0][0] (pointer to the first element) when passed to a function.

这都与内部数组表示有关。比如int arr_2 [2][2] = {{{1,2} {3,4}};在内存中看起来像1、2、3、4每个都是整数类型。当传递给一个函数时,arr_2大致等同于&arr[0][0](指向第一个元素的指针)。

Usual arrays are stored and accessed similarly int arr[2] = {2,5}; in memory 2,5. Compiler gets to them through their base plus offset times type base_ptr + index * type. To get value stored at index 1 of type int we write &arr[0] + 1 * sizeof(int) = 5

通常的数组被存储和访问类似的int arr[2] = {2,5};在内存中2 5。编译器通过它们的基加上偏移量乘以类型base_ptr + index *类型访问它们。要获取类型为int的索引1的值,我们写入&arr[0] + 1 * sizeof(int) = 5

So two dimensional arrays are accessed like so base_ptr + type * 2nd_dem_len + index. To get value stored at [1][1] we write &arr_2[0][0] + sizeof(int) * 1 + 1 = 4

二维数组的访问方式类似于base_ptr + type * 2nd_dem_len + index。要获取存储在[1][1]的值,我们编写&arr_2[0][0] + sizeof(int) * 1 + 1 = 4

So if the compiler doesn't know 2nd_dem_len or length of second dimension it cannot access that array. It doesn't know it because array gets watered down to that representation when passed to function because compiler converts it to a pointer which has no information about the size.

所以如果编译器不知道2nd_dem_len或第二个维度的长度,它就不能访问这个数组。它不知道,因为数组在传递给函数时被冲淡为那个表示,因为编译器将它转换为一个没有大小信息的指针。

#6


-1  

Actually whether it is a 2d array or a 1d array, it is stored in the memory in a single line.So to say the compiler where should it break the row indicating the next numbers to be in the next rows we are supposed to provide the column size. And breaking the rows appropriately will give the size of the rows.

实际上,无论是二维数组还是一维数组,它都存储在内存中的一行中。也就是说,编译器应该在哪里断行表明下一个数字在下一行我们应该提供列的大小。适当地对行进行拆分将给出行的大小。

Let's see an example:

让我们看一个例子:

int a[][3]={ 1,2,3,4,5,6,7,8,9,0 };

This array a is stored in the memory as:

该数组a存储在内存中,为:

  1  2  3  4  5  6  7  8  9  0

But since we have specified the column size as 3 the memory splits after every 3 numbers.

但是由于我们将列的大小指定为3,所以每3个数字后内存就会分裂。

#include<stdio.h>

int main() {
   int a[][3]={1,2,3,4,5,6},i,j;
   for(i=0;i<2;i++)
   {
       for(j=0;j<3;j++)
       {
           printf("%d  ",a[i][j]);
       }
       printf("\n");
   }

}

OUTPUT:

输出:

 1  2  3  
 4  5  6  

In the other case,

在其他情况下,

int a[3][]={1,2,3,4,5,6,7,8,9,0};

The compiler only knows that there are 3 rows but it doesn't know the number of elements in each row so it cannot allocate memory and will show an error.

编译器只知道有3行,但是它不知道每一行的元素数量,所以它不能分配内存,会显示错误。

#include<stdio.h>

int main() {
   int a[3][]={1,2,3,4,5,6},i,j;
   for(i=0;i<3;i++)
   {
       for(j=0;j<2;j++)
       {
           printf("%d  ",a[i][j]);
       }
       printf("\n");
   }

}

OUTPUT:

输出:

 c: In function 'main':
    c:4:8: error: array type has incomplete element type 'int[]'
    int a[3][]={1,2,3,4,5,6},i,j;
        ^