【发布时间】:2012-12-25 10:48:54
【问题描述】:
为什么在 C/C++ 中,接收 MD arr 的 func 参数需要具有所有子数组/维度的大小?
here(PDF): 它说 MD arrs 的唯一区别是 “编译器会记住每个虚构的维度”但是当我违反这些维度时,编译器什么也不做,例如:
char arr[3][5];
arr[0][5] = 10;
那么,记住这些尺寸有什么意义呢?
【问题讨论】:
为什么在 C/C++ 中,接收 MD arr 的 func 参数需要具有所有子数组/维度的大小?
here(PDF): 它说 MD arrs 的唯一区别是 “编译器会记住每个虚构的维度”但是当我违反这些维度时,编译器什么也不做,例如:
char arr[3][5];
arr[0][5] = 10;
那么,记住这些尺寸有什么意义呢?
【问题讨论】:
对数组的索引访问必须根据索引值和声明的次要维度以行优先顺序计算内存偏移量。稍后会详细介绍。
但首先,您的问题与这个简单的观察密切相关:
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)来有效计算正确元素的线性偏移。在一维线性块中布置二维数组,它用于执行此操作:
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';
等等。把它带到你想要的尽可能多的维度。必须知道所有次等尺寸才能正确执行此操作。
【讨论】:
数组不是一种特殊的对象,它只是一长串项目。您的arr[3][5] 实际上只是一个arr[15],然后arr[0][5] 会被编译器重定向到arr[5]。
由于 C/C++ 不存储大小,您需要对它们进行硬编码以使 [0][5] 正确映射到 [5]。
一些编译器可能会强制 [0][5] 出错(或警告它),但由于它映射到 [5],它至少会做一些事情。
【讨论】: