【问题标题】:int * vs int [] vs int (*)[] in function parameters. Which one should I use?函数参数中的 int * vs int [] vs int (*)[]。我应该使用哪一个?
【发布时间】:2015-01-11 18:09:07
【问题描述】:

在 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;
}

这是第三版的调用方式:

int main(void)
{
    int a[] = {3, 4, 2, 4, 6, 1, -40, 23, 35};
    printf("%d\n", accumulate(ARRAY_LENGTH(a), &a));
    return 0;
}

请注意,第三个选项要求用户使用&amp;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],但我发现其他两种方法也很常见。

【问题讨论】:

  • 为什么这被否决了?
  • 我对这两个答案都不满意。他们都没有提到pointer to array——这是int array[](在函数参数列表的上下文中实际上是int *)和int (*array)[]之间的定义区别。
  • @Jonathan 如果您(或其他人)有什么要补充的,您可以提出一个新的答案,如果它更好,我会接受。也许我这次很早就接受了一个答案,这会阻止新的答案出现。当我回顾这个问题时,我也意识到这个问答网站可能过于“基于意见”,但如果您认为其他答案遗漏了什么,请继续提出新的答案。

标签: c arrays function pointers parameters


【解决方案1】:

用作函数参数时,int array[]int *array 相同。你可以使用任何一个。这是品味的问题。 int (*array)[] 很繁琐,没有广泛使用。

int (*array)[n] 在将二维数组传递给函数时使用最广泛。在这种情况下,您可以使用array[i][j] 访问数组元素。

【讨论】:

  • 不是一个真正的答案。您的答案的第一部分已经在问题中说明。然后,这个问题与二维数组无关……不,int accumulate(int n, int (*array)[]) 不足以使用array[i][j]。为此,您必须将n 放入:int (*array)[n]
  • @JensGustedt;你的观点是有效的。我做了一些修正。但是,对我来说,这个问题主要是基于意见的。
【解决方案2】:

我也更喜欢第三种变体,但它不是很常用。如果是这样,我会用 C99 写:

int accumulate(size_t n, int (*array)[n]) { ....

这样sizeof *array 在函数内部的所有情况下都有效。

【讨论】:

  • 你说的是二维数组吗?那么 sizeof 知道行长吗?
  • @hacks,不,[*] 仅用于函数原型,用于参数名称不可用的情况。要真正了解sizeof *array,编译器必须看到真正的表达式,它是被评估的函数定义之一。
  • @PaulOgilvie,不,我不是在谈论 2D 数组,在这里。这是一种将指针传递给一维数组并知道函数内部数组大小的方言。
  • @JensGustedt;你说的对。它仅用于原型。
猜你喜欢
  • 1970-01-01
  • 2012-04-04
  • 2013-02-19
  • 2021-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
  • 1970-01-01
相关资源
最近更新 更多