为什么在C / C ++中,接收MD arr的func param需要具有所有子数组/维度的大小?
here(PDF):它说MD的唯一不同之处在于 “编译器会记住每个想象的维度”但是当我违反这些维度时,编译器什么都不做,例如:
char arr[3][5];
arr[0][5] = 10;
那么,记住那些尺寸有什么意义呢?
答案 0 :(得分:7)
对数组的索引访问必须根据索引值和声明的较低维度,按行主要顺序计算内存偏移量计算。更多相关内容。
但首先,你的问题与这个简单的观察紧密相关:
void foo( char a[] )
{
a[5] = 'a';
}
// caller of foo() from somewhere
char arr[5];
foo(arr);
为什么编译器允许你那个?因为这是C,你完全有权利用未定义的行为射击自己的脚。记住这一点:
void foo( char a[][5] )
{
a[0][5] = 'a';
}
// caller of foo() from somewhere
char arr[4][5];
foo(arr);
它与先前的代码一样“有效”(即您自己有权进入UB,风险和风险)。在这种情况下,它将“工作”,但仅仅因为底层数组的线性背景是20个元素宽,我们只访问第六个元素,技术上arr[1][0]
。
这些劣等维度的目的是正确计算 this :
之类的访问权限void foo( char a[][5] )
{
a[2][1] = 'b';
}
2
上级索引必须使用声明的下级维度(在本例中为5
)来有效地计算适当元素的线性偏移量。在一维线性块中布置2D数组,用于执行此操作:
char arr[20]; // 4*5
arr[2*5+1] = 'b';
请注意5
。必须知道声明的劣等维度才能正确计算行间距(演说)。
我希望这至少让它更清晰。
我应该注意这种化合物。即,以下内容:
char arr[3][4][5];
arr[1][2][3] = 'c';
有效地计算与底层数组的线性背景相对应的正确位置:
char arr[60]; // 3*4*5
arr[ 1*(4*5) + 2*(5) + 3 ] = 'c';
等等。把它带到你想要的那么多尺寸。必须知道所有较低的尺寸才能正确地做到这一点。
答案 1 :(得分:2)
数组不是一种特殊的对象,它只是一长串的项目。您的arr[3][5]
实际上只是arr[15]
,而arr[0][5]
则被编译器重定向到arr[5]
。
由于C / C ++不存储尺寸,因此您需要对它们进行硬编码以使[0][5]
地图正确地映射到[5]
。
有些编译器可能会强制[0][5]
出错(或警告它),但由于它映射到[5]
,它至少会做一些事情。