【问题标题】:While passing an array through a function in C++/C, why address of array is used in actual parameter whereas the array in formal parameter?在 C++/C 中通过函数传递数组时,为什么在实参中使用数组的地址而在形参中使用数组?
【发布时间】:2021-05-07 07:44:57
【问题描述】:
#include <iostream>
using namespace std;
int func(int ar[5]){
    //the code is written here with returning whatever the requirement is
}
int main(){
    int ar[5];
    func(ar);
    return 0;
}

在这种情况下,我们通过函数传递数组,为什么实际参数中使用数组的地址,而形式参数中使用数组?

【问题讨论】:

标签: c++ arrays c function function-call


【解决方案1】:

这是因为 C 处理数组的方式很奇怪。

在 C 中,数组转换为指向其第一个元素的指针,不能作为参数传递给函数,不能从函数返回,也不能通过赋值复制。

最初基于 C 的 C++ 将这些错误的设计决策作为遗留问题进行处理。修复它们会破坏大量的代码。

如果您想要一个行为更合理的数组,请使用std::array

void foo(int[5]);

这实际上是采用int* 参数。

int arr[7];
foo(arr);

这会将 7 元素 arr 转换为指针并将其传递给 foo。这似乎需要int[5],但5 什么都不做

是的,这太疯狂了。

现在,

void bar(int(&)[5])

因为C没有引用,所以上面是对一个数组如果5个元素的实际引用,所以

bar(arr)

不会编译。

【讨论】:

  • 编译器应该有一个开关,在传递数组时需要一个“&”,如果缺少,则生成一个“数组复制”警告或“数组长度未知”错误,视情况而定。
  • 没有人会受益于您对半个世纪前做出的设计决策的最新观点。人们可能会争辩说没有其他选择是可行的,因为尚未开发出必要的语义和支持软件。那时你甚至不能为结构写a = b,更不用说将任何类型的聚合传递给函数了。吐槽它是无益的。在不贬低先驱者的情况下,人们可以很容易地暗示现代设计会有所不同。
  • @eric 将错误称为错误,即使在一个 50 年前的设计中,即使我当时无法做得更好,也是有价值的。说他们犯了错误并不是“贬低”他们。他们编写了一种令人惊叹的语言并用它改变了世界;他们做得并不完美。
  • “搞砸了”和“完全疯了”不是中性的表达方式。即使说这是一个错误,也是一种价值判断,即鉴于做出决定时可用的知识,该决定是错误的。根据当时可用的知识和资源做出合理的决定并不是一个错误,即使它产生了可以避免的不良后果。
【解决方案2】:

没有什么奇怪的,也没有搞砸数组是如何在 C 中传递的。C 的表达非常简单,真的。 C /does/ 有引用;它们是明确的,因此在使用时很容易看到。我们称它们为指针。

人们只需要了解数组类型没有专用存储,数组不是一等类型,因此不会像一等类型那样表现。不能(直接)赋值给函数,也不能直接传入和传出函数。

在 C/C++ 中,我们使用指针来引用存储数组内容的内存块。

所以,剩下的就是我们明白了,当我们声明一个数组时,数组名实际上是一个指向数组开头的指针。

int a[12] ;
/* a's type is this: */
int *a ;

因此,当我们将数组“传递”给函数时,我们将 指针 复制到函数中。语义简单明了,而且完全一致(与 Java 不同)。

数组本身永远不会直接传递。

最后,意识到指向单个整数的指针和指向内存中连续整数块的指针之间没有区别。

请记住,a[i] 等同于 *(a+i)。所以,在这个例子中:

int i = 12 ;
int *p = &i ;

*p*(p+0) 相同; p 可以被认为是一个长度为 1 的数组。

稍微改变一下视角,你应该可以看到简洁、优雅,也就是C。

【讨论】:

  • 你对“一流类型”的定义是什么?这不是标准使用的术语。数组确实具有与任何其他变量相同的存储空间,并且定义数组定义了一个存储块(它没有定义指针)。 a 的类型是 int[12],而不是 int *。如果您对此表示怀疑,请阅读标准,和/或使用 sizeof 进行测试。
  • 它们不是一等的,因为它们不能被分配到函数中,也不能传递到函数中,也不能从函数中返回。如果 int[12] 是一个类型,那么我们可以使用它作为形式参数的类型。你可以这样声明一个参数,但是,12没有意义,如果你检查这个参数的大小,它是指针大小的。说 int a[12] 会导致静态或堆栈存储被搁置,是的,但是,非常薄,a 确实是一个指针。 *(a+5) 工作得很好。语义,当“传递一个数组”到一个函数时,正是传递一个指针的语义。
  • 很抱歉,您不正确。 int[12] 是一个类型,尝试打印 sizeof(int[12])。您还可以有一个指向 int[12] 的指针。确实,函数参数中的声明与函数参数之外的声明具有不同的含义,但是int a[12]; 不是函数参数。您的错误是假设函数参数的行为与所有声明的行为相同。
  • 我既不困惑也不错误。我也没有犯错。很抱歉,我无法帮助您理解什么是一流的数据类型。您是否使用 int[12] 作为形式参数的类型?你检查过它的大小吗?数组不是 C 中的一等类型。它们不能直接传递给函数,也不能直接传递给函数。是的,声明数组有点神奇,但是,在 C 中传递变量的语义非常简单。这包括数组。标准也没有说它们不是大象,但是,你知道吗?他们也不是大象。
  • “一流类型”不是标准术语,谈论数组是否是这样的东西是一个有争议的问题;相反,我们可以直接讨论数组的属性。我并不认为数组不能直接传递给函数或从函数传递,问题是您错误地声称数组没有专用存储,并且您错误地声称 int a[12]; (不在函数参数的上下文中) 表示a 的类型是int *
猜你喜欢
  • 2011-04-05
  • 2011-11-27
  • 2010-10-01
  • 1970-01-01
  • 2019-10-04
  • 2020-01-26
  • 2022-01-02
  • 2015-09-26
相关资源
最近更新 更多