在C语言中传递数组:方括号 vs. 指针

15
我希望您能够将一个数组传递到一个函数中。根据我的观察,有两种方法可以实现这个目标:
1.
void f (int array[]) {
    // Taking an array with square brackets
}

2.

void f (int *array) {
    // Taking a pointer
}

每个都被称为:

int array[] = {0, 1, 2, 3, 4, 5};
f (array);

这两种方法之间是否有实际区别?


6
这个问题可能已经被问过很多次了,但由于某些原因很难找到重复的答案。答案是“没有区别”。 - Sergey Kalinichenko
3
顺便提一句,还有第三种方式:void f(int array[N]),与前两种方式没有任何区别。 - HolyBlackCat
1
相关链接:https://dev59.com/amEh5IYBdhLWcg3wNxEn - M.M
1
就像我之前所说的,它们没有任何区别。 - HolyBlackCat
1
@iONinja 不可以。你可以写 int array[static 10] 来指定源数组至少为 10,但标准实际上并不要求编译器在传递较短的数组时诊断问题!因此,这个特性大多数情况下是无用的。 - M.M
显示剩余8条评论
4个回答

14

在您的具体示例中没有区别。

在更一般的情况下,这两种方法的区别之一源于,在使用 [] 语法时,语言执行“通常”的数组声明正确性检查。例如,当使用 [] 语法时,数组元素类型必须完整。对于指针语法没有此要求。

struct S;
void foo(struct S *a); // OK
void bar(struct S a[]); // ERROR

这个规则的一个具体副作用是,你不能将void *参数声明为void


1
在我看来,这是一个毫无意义的规则,只会让人们感到困惑,并且应该在后续标准中得到修正。 - M.M
@M.M:C++已经解决了这个问题,我还模糊地记得在某处读到过计划在C中修复它的计划。不过具体细节我记不清了。 - AnT stands with Russia

3

除了语法以外,两者没有区别。由于历史原因,即使 int array[] 看起来像应该传递一个数组,它实际上传递的是一个指针(这意味着它与 int *array 相同)。

如果我是你,我会更喜欢使用 int *array,因为它做的就是看起来应该做的事情 - 也就是说,它不太可能让你感到困惑。


2
我觉得很可怕,在这个时代,还会给出这样的建议。 - user3344003
3
你有两个选项 - 一个看起来像声明指针,实际上也是声明指针;另一个看起来像声明数组,但实际上也是声明指针。你为什么要使用第二种方式呢? - user253751
1
@immibis 有些人认为数组声明符表明指针应该是一个数组元素的指针。(当然,这种方法也存在问题...) - M.M
1
@M.M 不用担心...没错。a是指向a[0]的指针 :) 我完全同意immibus的观点,即array是更好的语法(虽然可能不是因为它“更少令人困惑”,而是因为它的语法更明确地表明了它的语义)。 - John Forkosh
@JohnForkosh 这就是我所说的“更少混淆”... 尤其是对于那些刚接触 C 语言并且还没有学习它所有怪癖的人来说。 - user253751
显示剩余2条评论

1
当传递一个数组到函数中时,它们是相同的,但一般情况下它们并不相同。考虑以下代码片段:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *mod_string(char *str) {
  puts(str);
  str[0] = 'h';
  puts(str);
  return str;
}

int main() {
  char hello_world[] = "Hello world";
  mod_string(hello_world);
}

如果你运行这个程序,你会得到:
Hello world
hello world

然而,如果您将程序的第一行更改为:
char *hello_world = "Hello world";

当您运行程序时,输出将为:
Hello world
Segmentation fault (core dumped)

我将把这个问题留给C语言专家来适当解释,但我想指出的是,符号差异并不是语法糖。


定义函数的两种方式实际上完全相同。当然,如果您传递指向只读内存而不是可写内存的指针并尝试写入该内存,您将获得不同的行为,但这并不意味着函数定义不同。 - dbush
称呼我老派,但我对“不同”的定义如下:如果你得到不同的输出,它们就是不同的。 - Eratosthenes
澄清一下:如果函数声明为 char *mod_string(char *str) { 或者 char *mod_string(char str[]) {,你将得到相同的结果,这也是问题所询问的。 - dbush
没错,我之前说过当作为参数传递时它们是相同的。然而,仅仅说它们是可互换的是不正确的,如果你将它们视为同一种类型可能会导致严重的问题。 - Eratosthenes
如果传入不同的值,你会得到不同的结果,但这不是问题所在。问题在于将char *char []作为函数参数的使用,而不是一般情况下的使用。 - dbush

1
他们在定义上是相同的。调用代码总是将数组参数作为指针传递,即使调用者看起来像是在传递一个数组。类似数组的参数声明可能会使调用更加直观,但指针参数声明更准确地反映了实际情况。
另请参见此条目C FAQ列表中。
正如Dennis Ritchie在{{link3:“C语言的发展”}}中所解释的那样,指针声明实际上是一种“活化石”,它来自于C语言的一个非常早期的版本,在那个版本中,数组和指针的工作方式有很大的不同。

澄清一下,在指针声明中使用的数组声明符是“活化石”,用DMR的话来说。 - M.M
@M.M 没错,已经澄清。 - Steve Summit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接