我肯定这是一个相当愚蠢的问题,但它真的让我猝不及防,可能是我没有正确地思考这个问题。在使用OpenGL ES 2.0时,我遇到了以下代码行
/////////////////////////////////////////////////////////////////
// Forward declarations
static void SceneMeshInitIndices(
GLushort meshIndices[NUM_MESH_INDICES]);
static void SceneMeshUpdateNormals(
SceneMeshVertex mesh[NUM_MESH_COLUMNS][NUM_MESH_ROWS]);
static void SceneMeshUpdateMeshWithDefaultPositions(
SceneMeshVertex mesh[NUM_MESH_COLUMNS][NUM_MESH_ROWS]);现在,让我猝不及防的是,函数将其输入声明为具有特定大小的2D数组。我从来没有见过这样做,完全不确定它是否合法,或者它如何在Objective-C中合法。我总是被告知要使用指向原始数组的指针并将其传递给它。但是,这看起来很奇怪。有没有人可以试着给我解释一下,或者指出我推断错误的地方?
发布于 2013-02-14 04:57:34
当将数组传递给函数时,它们会根据一组规则衰减为指针。它们是:
一。第一级间接(即数组的第一个维度/索引)衰减为一个指针,因此不需要指定它的大小(也不使用它)。
二。数组的更多维度保持不变,并且不会衰减为指针。需要指定它们,并且它们是参数类型的一部分。
这就是为什么从本质上讲,以下内容是等效的和合法的:
void foo(int arr[]);
void foo(int arr[MAX_ARRAY_SIZE]);
void foo(int *arr);但以下是不等价的,还合法:
void foo(int arr[MAX_ROWS][MAX_COLUMNS]);
void foo(int **arr);以下内容同样具有等价性和合法性:
void foo(int arr[MAX_ROWS][MAX_COLUMNS]);
void foo(int arr[][MAX_COLUMNS]);(它们被解释为int (*arr)[MAX_COLUMNS]),即指向数组的指针)。
下面的代码是非法的,也就是说,它生成了一个编译器错误:
void foo(int arr[MAX_ROWS][]);发布于 2013-02-14 04:59:58
,我一直被告知要使用指向原始数组的指针,并将其传入。
您已经被告知要使用指向原始数组元素的指针。你被告知这一点是因为,如果你试图声明一个通过值接受数组的函数,语言会指定参数类型被“调整”为接受指向元素类型的指针(有效地导致数组参数类型忘记了它的大小,并通过引用而不是通过值传递)。所以基本上你已经被告知要手动进行调整,这样源代码才能准确而明确地表示实际情况。
您显示的声明也可以使用以下建议进行声明:
static void SceneMeshInitIndices(GLushort *meshIndices);
static void SceneMeshUpdateNormals(SceneMeshVertex (*mesh)[NUM_MESH_ROWS]);
static void SceneMeshUpdateMeshWithDefaultPositions(SceneMeshVertex (*mesh)[NUM_MESH_ROWS]);应该清楚的是,一种类型的int [X][Y]意味着“一个由X个Y数组组成的数组”。因此,元素类型是“一个Y整型数组”。因此,调整后的类型是“int(*)Y”或“指向Y整型数组的指针”。
“调整”参数类型的规则是原始数组糟糕的几个原因之一,如果有可能避免它们,就不应该使用它。不幸的是,C并没有一个很好的方法来做到这一点,但是C++有std::array,它的行为就像数组应该的那样;例如,你可以通过值传递它们,你可以通过值返回它们,它们永远不会自动转换为指向元素类型的指针(所以它们永远不会忘记它们的大小)等等。
也许更多的例子会让它变得更清晰。如果你写道:
void foo(int param[10]);int bar[5];
foo(bar); // error? an array of 5 ints is not the expected type.对于这段代码:
int baz[10];
foo(baz);您可能希望将数组bar复制到参数中,并且对参数所做的任何修改都不会对原始数组产生任何影响。不幸的是,这些完全合理的预期是错误的。当您编写void foo(int param[10]);时,编译器会看到具有数组类型的参数并将其修改为与您编写的void foo(int *param);相同
因此,当您编写foo(bar)时,编译器会看到该函数接受int* (而不是您编写的int[10] ),并且会看到它可以将bar转换为int *,因此编译器不会报告错误,而是会恶意生成一个调用该函数的程序。无论您编写的类型与传递的变量不兼容,也不管foo()的主体可以做类似param[9] *= 2;的事情,都应该确保这是定义良好的。
这与通常的C语义完全不同,在C中,一切都是通过值/副本传递的,而“通过引用传递”的唯一方法是获得一个指针值,作为对另一个对象的引用。
此外,请注意,无论是编写void foo(int [10])还是void foo(int [100])都无关紧要;在这两种情况下,参数类型都调整为int *,因此这些声明声明了相同的函数,即使它们看起来不同。
发布于 2013-02-15 02:29:33
为了验证上面提到的内容,我还找到了下面的解释(基本上是说我很长一段时间都不需要传递2D数组了),它只是迭代上面的内容。
在将一维数组声明为函数内的形参时,您了解到不需要数组的实际维数;只需使用一对空方括号通知C编译器该参数实际上不是完全适用于多维数组的array.This。对于二维数组,可以省略数组中的行数,但声明必须包含数组中的列数。所以这些声明
int array_values[100][50]和int array_values
都是名为array_values的形式参数数组的有效声明,该参数数组包含100行x 50列;但声明
int array_values[100][]和
int array_values[][]不是因为必须指定数组中的列数。
https://stackoverflow.com/questions/14862860
复制相似问题