除非它是sizeof
, _Alignof
, 或一元运算符的操作数&
,或者是用于在声明中初始化另一个数组的字符串文字,否则“N-element array of”类型的表达式T
将被转换(“decay”)为“pointer to T
”类型的表达式,其值将是数组中第一个元素的地址(6.3.2.1/3)。
在行return hws;
中populate
,表达式的类型hws
是“100 元素数组的 20 元素数组int
”;根据上面的规则,它将被转换为类型“指向 20 元素数组的指针int
”,或者int (*)[20]
. 因此,正确的声明populate
需要是
int (*populate())[20]
{
...
return hws;
}
读作
populate -- populate
populate() -- is a function
*populate() -- returning a pointer
(*populate())[20] -- to a 20-element array
int (*populate())[20] -- of int.
并且您返回结果的任何类型也需要是int (*)[20]
。
话说回来...
出于多种原因,强烈建议不要以这种方式使用全局变量。最好将数组populate
作为参数传递,如下所示:
void populate(int (*arr)[20], size_t rows)
{
size_t i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < 20; j++)
{
arr[i][j] = randomize();
}
}
}
你可以简单地称之为
populate(hws, sizeof hws / sizeof hws[0]);
如果您使用的是支持可变长度数组的编译器(C99 编译器或未定义__STDC_NO_VLA__
或将其定义为 0 的 C2011 编译器),您可以将函数定义为
void populate(size_t cols, size_t rows, int (*arr)[cols]) // cols must be declared
{ // before it can be used
size_t i, j; // to declare arr
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
arr[i][j] = randomize();
}
}
}
并将其称为
size_t rows = sizeof hws[0] / sizeof hws[0][0]; // dividing the size of the array
size_t cols = sizeof hws / sizeof hws[0]; // by the size of the first element
populate(cols, rows, hws); // gives the number of elements
所以你不会在任何地方对 20 进行硬编码。
如果您没有使用支持可变长度数组的编译器,并且不想硬编码函数原型中的行数,则可以执行以下操作:
void populate(int *arr, size_t rows, size_t cols)
{
size_t i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
arr[i * rows + j] = randomize();
}
}
}
并将其称为
// rows and cols calculated as above
populate(&hws[0][0], rows, cols);
在这种情况下,我们不是传递指向数组的指针,而是传递指向第一个元素的指针(地址值相同,但类型int *
不是int (*)[20]
. 所以populate
函数将其视为一维数组,并计算偏移量与i * rows + j
. 请注意,此技巧仅适用于已连续分配的 2D 数组。
这也意味着它populate
可以处理任何大小的数组,而不仅仅是 Nx20。