函数参数中的int * vs int vs int(*)。 我应该使用哪一个?
在C编程语言中,有许多不同的方法来声明函数的参数,该函数将数组作为通过指针传递的参数。
我准备了一个例子,告诉你我的意思。 它是C ++中std::accumulate
函数的一个实现。 它是一个函数,它可以在数组中添加所有元素并返回结果。
我可以这样写:
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; }
这就是调用thrid版本的方式:
int main(void) { int a[] = {3, 4, 2, 4, 6, 1, -40, 23, 35}; printf("%d\n", accumulate(ARRAY_LENGTH(a), &a)); return 0; }
请注意,第三个选项要求用户明确指定with &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 #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]
但我看到其他两种方法也很常见。
当用作函数参数时, int array[]
和int *array
是相同的。 你可以使用其中之一。 这是品味的问题。 int (*array)[]
很繁琐而且没有广泛使用。
当2D数组传递给函数时, int (*array)[n]
被最广泛地使用。 在这种情况下,您可以作为array[i][j]
访问数组元素。
我也更喜欢第三种变体,但它并不常用。 如果是这样,用C99我会写:
int accumulate(size_t n, int (*array)[n]) { ....
这样sizeof *array
在函数内的所有情况下都有效。