【问题标题】:C++ arrays as function argumentsC++ 数组作为函数参数
【发布时间】:2011-02-21 12:08:21
【问题描述】:
  • 我能否像处理 int 和 bool 等基元一样将数组传递给函数?
  • 我可以按值传递它们吗?
  • 函数如何知道它所传递的数组的大小?

【问题讨论】:

    标签: c++ arrays arguments


    【解决方案1】:

    您可以按值传递std::vector 和类似的精心设计的对象(尽管这并不常见)。通常,您通过引用或 const 引用传递。

    一个 C/C++ 数组,如

    void foo(int x[])
    

    总是通过引用传递。此外,该函数无法确定调用者传入的参数的真实大小,您必须假设一个大小(或将其作为单独的参数传递)。

    【讨论】:

    • 准确地说,数组的按值语法将数组衰减为指向第一个元素的指针,然后按值传递该指针。这与通过引用传递数组不同: void foo( int (&a)[10] )
    【解决方案2】:
    1. 是的。例如:void f(int a[]); 并这样称呼它:int myArr[size]; f(myArr);
    2. 不,数组是通过引用自动传递的。如果要模拟按值传递,则必须将数组包装在结构或类中。
    3. 它没有。您必须自己传递尺寸。

    【讨论】:

    • 准确地说,数组的按值语法将数组衰减为指向第一个元素的指针,然后按值传递该指针。这与通过引用传递数组不同:void foo( int (&a)[10] )
    【解决方案3】:

    我可以将数组传递给函数吗? 我会使用诸如 int 之类的原语 和布尔?

    是的,但只能使用指针(即:通过引用)。

    我可以按值传递它们吗?

    没有。您可以创建支持该功能的类,但普通数组不支持。

    函数如何知道它传递的数组的大小?

    它没有。这就是使用 vector<T> 之类的东西而不是 T * 的原因。

    澄清

    一个函数可以获取一个特定大小的数组的引用或指针:

    void func(char (*p)[13])
    {
        for (int n = 0; n < 13; ++n)
            printf("%c", (*p)[n]);
    }
    
    int main()
    {
        char a[13] = "hello, world";
        func(&a);
    
        char b[5] = "oops";
        // next line won't compile
        // func(&b);
    
        return 0;
    }
    

    不过,我很确定这不是 OP 想要的。

    【讨论】:

    • 赞成,因为我在它出现之前输入了完全相同的答案。
    • C++ 中的数组可以通过引用传递,在这种情况下您可以知道数组的大小。当然,这不适用于在运行时创建的数组。
    • @AraK - 不确定你的意思。您可以在答案中添加一个示例吗?
    • @egrunin: 并且不需要模板化:void foo( int (&amp;a)[10] ) 将通过引用接收正好 10 个整数的数组。动态分配数组的问题稍微复杂一点...new int[10] 的类型是int *,而不是int [10],但是您可以动态创建一个包含 10 个整数的数组:int (*p)[10] = new int[1][10];,然后调用前面的函数:foo(*p).
    • @AraK, @David:我知道排列组合,只是不确定我们想的是同一个排列。附上了一个简单的例子。
    【解决方案4】:

    您可以按照 C 的常用方式传递数组(数组衰减为指针),或者您可以通过引用传递它们,但它们不能通过值传递。对于第二种方法,它们会随身携带它们的尺寸:

    template <std::size_t size>
    void fun( int (&arr)[size] )
    {
       for(std::size_t i = 0; i < size; ++i) /* do something with arr[i] */ ;
    }
    

    大多数时候,除非您特别需要原生数组,否则在标准库中使用 std::vector 或其他序列会更优雅。

    【讨论】:

    • 这几乎不是他们随身携带的尺寸;)尺寸可作为模板参数使用(或者您可以在某处定义合适的const 的非模板版本)。您无法从 arr 本身获得大小,我认为您当前的措辞有点误导。
    • @Troubadour:在 c++ 中,大小不是数组的一部分,而是数组类型的一部分。如果您将其设为非模板,则无需添加 const,唯一的区别是它可以在与签名中定义的大小完全相同的数组中工作:void foo( int (&amp;a)[3] ) 将只接受 3 个整数的数组。跨度>
    • @dribeas:我没有意识到它强制执行正确数量的元素。很好,感谢您让我知道,但它仍然没有在我的观点的函数中提供这么多的元素。另外,我无法让int N=10; void fun( int (&amp;arr)[N] ) {} 编译。是我做错了什么还是我们的目的不同?
    【解决方案5】:

    是的,您可以像原始类型一样传递它们。 是的,如果您真的想使用一些包装代码,您可以按值传递,但您可能不应该这样做。 它将函数原型的大小作为长度——它可能匹配也可能不匹配传入的数据——所以不,它真的不知道。

    或者!

    将引用或 const 引用传递给向量,这样更安全,而且大小信息触手可及。

    【讨论】:

      【解决方案6】:

      你可以传递一个数组,但如果你想确定它,你必须传递它的大小:

      function(array, size);
      

      数组总是通过引用传递,函数可以写成以下两种方式之一:

      Declaration:    void function (class*, int);
      Implementation: void function(class array[]; int size) {}
      

      Declaration:    void function (class*, int);
      Implementation: void function(class *array; int size) {}
      

      当您将数组传递给函数时,函数实质上会接收指向该数组的指针,如上面的第二个示例所示。这两个示例将完成相同的事情。

      【讨论】:

        【解决方案7】:

        我可以将数组传递给函数吗? 我会使用诸如 int 之类的原语 和布尔?

        是的,你可以。将数组名称作为参数传递给函数会传递第一个元素的地址。

        简而言之:

        void foo(int a[]);
        

        等价于

        void foo(int * a);
        

        我可以按值传递它们吗?

        不是真的。与数组名称一起传递的“值”是第一个元素的地址。

        传递 C 样式数组副本的唯一方法是将其包装在实现深拷贝语义的 classstruct 中。

        函数如何知道大小 它传递的数组是什么?

        它不会,除非你让你的函数接受一个额外的参数,即数组的大小。

        【讨论】:

        • Re:int a[]int * b 之间的等价性:但有一个区别:第一种形式不允许您使用指针(例如,a++ 是非法的)。跨度>
        • @RaphaelSP,不,没有那样的区别。第一种形式同样允许a++ - 它们是完全等价的。 @John,不过,“没有办法接受或传递 C 样式数组的副本”是错误的。如果将数组包装到结构中并按值获取结构,则包装的数组被复制,并且函数接收 c 样式数组的副本。
        • @RaphaelSP: void bar( int a[] ) { ++a; *a = 7; } 在 g++ 和 comeau 中编译。
        • 对——我也试过了——我本来想说int * const a,然后试了一下,发现你可以修改指针。我会向不那么绝对的事情澄清“没办法”。
        • @Johannes, @dribeas:哇哦,我不知道数组变量和数组参数是不同的。对我无懈可击的知识来说就这么多。
        【解决方案8】:

        C 风格的数组在传递给函数时表现得非常奇怪。对于固定大小的数组,我会推荐std::array&lt;int, 10&gt;,它可以像内置类型一样按值传递。对于可变大小的数组,我推荐std::vector&lt;int&gt;,正如其他答案中所建议的那样。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-06-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多