为什么我们在传递动态 2D 数组时不需要列数?
Why we don't need number of column when passing the dynamic 2d array?
假设我有两个数组,我将它们传递给一个函数:
void func(int arr1[][4], int **arr2) { // <- I need to give n in only one, why?
...
}
int main() {
int n = 5, m = 4;
int arr1[n][m];
int **arr2 = (int**)malloc(n * sizeof(int*));
for(int i = 0;i < n;i++)
arr2[i] = (int*)malloc(m * sizeof(int));
func(arr1, arr2);
return 0;
}
为什么我们不能以类似的方式处理两个数组传递?
编辑:代码中存在错误。
与你所说的相反的是:你不必传递行数。假设数组索引的工作方式如下:
int arr[MAX_ROW][MAX_COL]; /* with both 3 */
col
--------------->
| 0,0 0,1 0,2
row | 1,0 1,1 1,2
V 2,0 2,1 2,2
当您传递int arr[][MAX_COL]
编译器知道当您像arr[row][col]
这样的地址时下一行将从哪里开始。
如果您使用指针手动执行此操作,它将如下所示:&arr[0][0] + row * MAX_COL + col
.在该示例中,您还必须知道数组的列大小MAX_COL
才能计算下一行。
这样做的原因是,数组在内存中是连续的。上面的数组在内存中表示,如下所示:
| row = 0 | row = 1 | row = 2 |
| 0,0 0,1 0,2 | 1,0 1,1 1,2 | 2,0 2,1 2,2 |
编译器还必须知道行偏移量,因为当您将声明为int arr[MAX_SIZE]
的数组传递给函数void foo (int arr[])
时,它会衰减为指向数组开头的指针int* arr
。在数组数组(2D 数组)的情况下,它也衰减到指向其第一个元素的指针,该元素是指向单个数组int (*arr)[MAX_COL]
的指针。
简而言之:有了int arr[][MAX_COL]
编译器就拥有使用arr[row][col]
对数组进行寻址所需的所有信息。
实际上恰恰相反,您只能省略索引中的一个(在多维数组的情况下),即最里面的索引。
这是因为,数组虽然作为函数参数传递,但衰减到指向第一个元素的指针。引用C11
,章节§6.3.2.1
除非它是
sizeof
运算符、_Alignof
运算符或 一元&
运算符,或者 是用于初始化数组的字符串文本,该表达式具有 类型"类型数组"转换为类型为"指向类型的指针">的表达式,该表达式指向 到数组对象的初始元素,并且不是左值。[...]
因此,像这样的符号
void func(int arr1[][5], int **arr2) //an array of array of 5 ints
和
void func(int (*arr1) [5], int **arr2) //pointer to the starting element of an array of 5 ints
是等效的。
你实际上只有一个整数数组(即int arr1[][5]
) 和一个指向 int 指针的指针,即int **arr2
.即使像arr1[10][5]
这样的数组,当作为参数传递给函数时,衰减到指向元素所在的内存开头的指针,内存布局和编译器处理这些指针的方式也存在(很大)差异。
顺便说一句,主要是它应该是int n=5,m=4;int arr1[m][n]
,而不是int n=5,m=4;int arr1[n][m]
.
关于内存布局:
形式为int [10][5]
的 2D 整数数组表示为 10 个连续的"行",每个"行"包含 5 个"列"(即整数值)。这个数组的大小是10 * 5 * sizeof(int)
,一个"行"的大小是5 * sizeof(int)
。
指向 intint **p
的指针的指针只是一个指针; 它的大小是sizeof(int**)
的,即使你已经"错误定位"了一连串的整数指针 lilep = malloc(10 * sizeof (int*))
;请注意sizeof(int *)
中的"*",因为您创建指向整数的指针序列,而不是整数序列。这是内存布局的主要区别:它不是整数的 2D 数组,而是指向整数的指针的 1D 数组。如果实际上为"10"个整数分配了 10 个"行",则每行可能位于内存的不同部分。管理这样一个(分散的)10x5整数值所需的空间是"10*sizeof(int*) + 10*5*sizeof(int)"。
关于访问:
让我们假设一个类型int arr[][5]
的变量,它是一个整数的 2D 数组,其中列的大小是5
的,行数是不确定的。非正式地,像int x = arr[3][4]
这样的访问被转换为数组第(3*5 + 4)
个元素的访问,即"行乘以行大小加列";请注意,基于此公式,编译器不需要知道数组实际有多少行。
相反,让我们假设一个类型int **p
的变量。您可以将像x = p[3][4]
这样的访问视为等效于int *r = p[3]; int x = r[4]
;请注意,r
的类型为int *
,即它是一个指针,然后r[4]
取消引用此指针并返回一个整数值。
这是相当非正式的描述。 然而,主要问题是arr[][5]
的内存布局仅包含连续的整数值,而int **arrr
可能是指针的序列(甚至只是一个这样的指针),每个指针都可能指向一系列整数值(或仅一个整数值)。
- 如何计算数组中元素的位数?(不是数组的长度),并计算其数字的总和
- 如何使用C++初始化向量;脚本化值不是数组、指针或矢量错误
- 我正在尝试解决一个需要数组总和值但代码不起作用的问题,我想做这样的事情
- 如何对不在数组中的变量进行排序?
- 从用户那里获得无限量的输入,而不是打印最大的3个,而不使用数组
- (C++)我的函数不返回数组
- 用c++排序,不带数组
- Sizeof返回的是指针大小,而不是数组大小.有其他方法可以找到尺寸吗
- 在 c++ 中比较不相等数组或字符串的方法
- 为什么会出现一些垃圾而不是数组值?
- 是否可以在不使用数组的情况下将不同数量的相同类型的参数传递给函数?
- 使用指针交换而不引用数组C++
- 使用 auto 时不检查数组边界
- 我想返回数组索引,而不是数组值
- 我不明白数组名称是如何指向数组的指针
- 下标需要数组或指针类型表达式必须具有指针对象类型
- 如何将值分配给递增变量(如数组),但不使用数组
- 我试图释放数据的某些部分,并用特定的整数值标记其休息,以表明它不是有效的指针.(不是数组)
- 当循环崩溃时,不向数组添加单词
- C++如果我不知道数组大小并且需要接收数组怎么办