【问题标题】:Passing arrays in C: square brackets vs. pointer在 C 中传递数组:方括号与指针
【发布时间】:2017-11-13 08:37:30
【问题描述】:

我想将数组传递给函数。据我所知,有两种方法可以做到这一点:

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);

这两种方法有什么实际区别吗?

【问题讨论】:

  • 这肯定被问过很多次了,但由于某种原因,真的很难找到重复的。答案是“没有区别”。
  • 顺便说一句,还有第三种方式:void f(int array[N]),和这两种方式没有区别。
  • 正如我所说,没有区别。
  • 'int 数组 = {0, 1, 2, 3, 4, 5};'这不是有效的数组声明。您可以将其更正为 'int array[] = {0, 1, 2, 3, 4, 5};'

标签: c arrays function pointers memory


【解决方案1】:

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

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

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

此规则的一个特定副作用是您可以将 void * 参数声明为 void [] 参数。

如果你指定数组大小,它必须是正数(即使它之后被忽略)。

【讨论】:

  • IMO 一条毫无意义的规则,只会让人绊倒,应该由以后的标准修复
  • @M.M:C++ 修复了它,并且隐约记得在某处读过关于用 C 修复它的计划。不过不要记住细节。
【解决方案2】:

除了语法没有区别。由于历史原因,尽管int array[] 看起来 应该传递一个数组,但它实际上传递了一个指针(意味着它与int *array 相同)。

如果我是你,我会更喜欢 int *array,因为它的功能与它看起来一样 - 也就是说,它不太可能让你感到困惑。

【讨论】:

  • 我觉得可怕的是,在这个时代,给出这样的建议。
  • @user3344003 您有两种选择——一种看起来像是声明了一个指针并声明了一个指针,另一种看起来像是声明了一个数组并声明了一个指针。你一直使用第二个的理由是什么?
  • @immibis 有些人认为数组声明器记录了指针应该是指向数组元素的指针的意图。 (这当然有问题……)
  • @M.M 别担心……它是。 *a 是指向 a[0] 的指针 :) 我 110% 同意 immibus 的观点,即 *array 是更好的语法(尽管可能不是因为它“不那么令人困惑”,而仅仅是因为它的语法更明确地暗示了它的语义)。
  • @JohnForkosh 这就是我所说的“不那么令人困惑”的意思......尤其是对于那些刚接触 C 并且还没有学会所有怪癖的人。
【解决方案3】:

根据定义,它们是相同的。调用代码总是将数组参数作为指针传递,即使看起来调用者正在传递一个数组。类似数组的参数声明可能使它看起来更像调用,但指针参数声明更准确地反映了实际情况。

另请参阅C FAQ list 中的this entry

正如 Dennis Ritchie 在 "The Development of the C Language" 中解释的那样,指针声明实际上是“活化石”,是早期 C 版本的遗物,其中数组和指针的工作方式截然不同。

【讨论】:

  • 澄清一下,用 DMR 的话来说,是用于指针声明的数组声明器是活化石
  • @MM 对。澄清。
【解决方案4】:

将数组传递给函数时它们是相同的,但是,它们通常不一样。考虑以下代码 sn-p:

#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 专家来正确解释这一点,但我只是想指出符号差异不是语法糖。

【讨论】:

  • 这两种定义函数的方式其实是完全一样的。如果您将指针传递给只读内存而不是可写内存并尝试写入该内存,您当然会得到不同的行为,但这并不意味着函数定义不同。
  • 称我为老式但我对“不同”的定义如下:如果你得到不同的输出,它们就会不同。
  • 澄清一下:如果函数被声明为 char *mod_string(char *str) {char *mod_string(char str[]) { 这就是问题所要问的,你会得到相同的结果。
  • 对,我前面说过,当它们作为参数传递时,它们是相同的。但是,仅仅说它们可以互换是不正确的,如果你这样对待它们可能会导致严重的问题。
  • 如果你传入不同的值,你会得到不同的结果,但这不是问题所在。这是关于 char *char [] 的用法作为函数的参数,而不是一般。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-16
  • 1970-01-01
  • 2017-10-23
  • 2019-11-26
相关资源
最近更新 更多