函数参数中的 int * vs int [] vs int (*)[]。我应该使用哪一个?
int * vs int [] vs int (*)[] in function parameters. Which one should I use?
在 C 编程语言中,有许多不同的方法来声明将数组作为通过指针传递的参数的函数的参数。
我准备了一个示例来向您展示我的意思。它是 C++ 中 std::accumulate
函数的一个实现。它是一个函数,执行数组中所有元素的加法和 returns 结果。
我可以这样写:
int accumulate(int n, int *array)
{
int i;
int sum = 0;
for (i = 0; i < n; ++i) {
sum += array[i];
}
return sum;
}
也可以这样写(意思完全一样):
int accumulate(int n, int array[])
{
int i;
int sum = 0;
for (i = 0; i < n; ++i) {
sum += array[i];
}
return sum;
}
我也可以这样写:
int accumulate(int n, int (*array)[])
{
int i;
int sum = 0;
for (i = 0; i < n; ++i) {
sum += (*array)[i];
}
return sum;
}
所有这些选项都非常相似并生成相同的可执行代码,但它们略有不同,即调用者传递参数的方式。
前两个版本是这样调用的:
int main(void)
{
int a[] = {3, 4, 2, 4, 6, 1, -40, 23, 35};
printf("%d\n", accumulate(ARRAY_LENGTH(a), a));
return 0;
}
第三个版本是这样调用的:
int main(void)
{
int a[] = {3, 4, 2, 4, 6, 1, -40, 23, 35};
printf("%d\n", accumulate(ARRAY_LENGTH(a), &a));
return 0;
}
请注意,第三个选项需要用户明确指定 a
和 &a
的地址。前两个选项不需要这样做,因为数组隐式地转换为指向 C 中相同类型的指针。
我一直更喜欢第三种方法。
这就是为什么:
更符合其他类型的指针传递方式
int draw_point(struct point *p);
int main()
{
struct point p = {3, 4};
draw_point(&p); // Here is the 'address of' operator required.
}
这使得使用像ARRAY_LENGTH
这样的宏来获取数组中元素的数量成为可能。
#include <stdio.h>
#define ARRAY_LENGTH(A) (sizeof(A) / sizeof(A[0]))
void this_works(int (*array)[10])
{
/* This works! */
printf("%d\n", ARRAY_LENGTH(*array));
}
void this_is_invalid_and_dangerous(int array[10])
{
/* This does NOT work because `array` is actually a pointer. */
printf("%d\n", ARRAY_LENGTH(array));
}
我看到 int array[]
(和 int *array
)相对于 int (*array)[]
的唯一优势是当您使用 array[X]
而不是 (*array)[X]
时想抢个指数。
但因为我不是专业人士,所以我会问你更喜欢哪个版本。
你什么时候用什么?选择其中一个选项而不是另一个选项的原因是什么?
我主要使用 int (*array)[N]
,但我发现其他两种方法也很常见。
我也比较喜欢第三种,不过不太常用。如果是这样,对于 C99,我会写:
int accumulate(size_t n, int (*array)[n]) { ....
这样 sizeof *array
在函数内的所有情况下都有效。
用作函数参数时,int array[]
和int *array
是一样的。你可以使用任何一个。这是品味问题。 int (*array)[]
很乏味,没有被广泛使用。
int (*array)[n]
在将二维数组传递给函数时使用最广泛。在这种情况下,您可以访问数组元素 array[i][j]
.
在 C 编程语言中,有许多不同的方法来声明将数组作为通过指针传递的参数的函数的参数。
我准备了一个示例来向您展示我的意思。它是 C++ 中 std::accumulate
函数的一个实现。它是一个函数,执行数组中所有元素的加法和 returns 结果。
我可以这样写:
int accumulate(int n, int *array)
{
int i;
int sum = 0;
for (i = 0; i < n; ++i) {
sum += array[i];
}
return sum;
}
也可以这样写(意思完全一样):
int accumulate(int n, int array[])
{
int i;
int sum = 0;
for (i = 0; i < n; ++i) {
sum += array[i];
}
return sum;
}
我也可以这样写:
int accumulate(int n, int (*array)[])
{
int i;
int sum = 0;
for (i = 0; i < n; ++i) {
sum += (*array)[i];
}
return sum;
}
所有这些选项都非常相似并生成相同的可执行代码,但它们略有不同,即调用者传递参数的方式。
前两个版本是这样调用的:
int main(void)
{
int a[] = {3, 4, 2, 4, 6, 1, -40, 23, 35};
printf("%d\n", accumulate(ARRAY_LENGTH(a), a));
return 0;
}
第三个版本是这样调用的:
int main(void)
{
int a[] = {3, 4, 2, 4, 6, 1, -40, 23, 35};
printf("%d\n", accumulate(ARRAY_LENGTH(a), &a));
return 0;
}
请注意,第三个选项需要用户明确指定 a
和 &a
的地址。前两个选项不需要这样做,因为数组隐式地转换为指向 C 中相同类型的指针。
我一直更喜欢第三种方法。
这就是为什么:
更符合其他类型的指针传递方式
int draw_point(struct point *p); int main() { struct point p = {3, 4}; draw_point(&p); // Here is the 'address of' operator required. }
这使得使用像
ARRAY_LENGTH
这样的宏来获取数组中元素的数量成为可能。#include <stdio.h> #define ARRAY_LENGTH(A) (sizeof(A) / sizeof(A[0])) void this_works(int (*array)[10]) { /* This works! */ printf("%d\n", ARRAY_LENGTH(*array)); } void this_is_invalid_and_dangerous(int array[10]) { /* This does NOT work because `array` is actually a pointer. */ printf("%d\n", ARRAY_LENGTH(array)); }
我看到 int array[]
(和 int *array
)相对于 int (*array)[]
的唯一优势是当您使用 array[X]
而不是 (*array)[X]
时想抢个指数。
但因为我不是专业人士,所以我会问你更喜欢哪个版本。
你什么时候用什么?选择其中一个选项而不是另一个选项的原因是什么?
我主要使用 int (*array)[N]
,但我发现其他两种方法也很常见。
我也比较喜欢第三种,不过不太常用。如果是这样,对于 C99,我会写:
int accumulate(size_t n, int (*array)[n]) { ....
这样 sizeof *array
在函数内的所有情况下都有效。
用作函数参数时,int array[]
和int *array
是一样的。你可以使用任何一个。这是品味问题。 int (*array)[]
很乏味,没有被广泛使用。
int (*array)[n]
在将二维数组传递给函数时使用最广泛。在这种情况下,您可以访问数组元素 array[i][j]
.