【问题标题】:Passing arrays as a reference传递数组作为参考
【发布时间】:2011-12-15 12:04:40
【问题描述】:

在 C++ 中,当我在编译时不知道大小时,如何传递 数组作为参考?到目前为止,我发现让它工作的唯一方法是使用类似的东西

const double( &numbers ) [size]

但这意味着我需要在编译时知道数组的大小,因此我不能在外部函数中使用它。

我的问题是:

  1. 如果我不将数组作为( const double( &numbers ) [length] ) 传递,例如因为我不知道它的大小,我如何确保它不会被复制,但它是否被引用
  2. 如果我像上面的例子一样传递一个数组,( double array[] ) 它是引用还是复制

【问题讨论】:

    标签: c++ arrays visual-studio-2010 stl


    【解决方案1】:

    几件事:

    1. C++ 无论如何都不允许可变大小的数组。因此,您的所有数组都需要在编译时具有已知的大小。所以我不完全确定你最初的问题是否适用,因为你一开始就无法制作一个大小未知的数组。

    2. 当你传递一个数组时,它是通过引用来完成的。它没有被复制。

    无论如何,您可能需要考虑改用vector

    编辑:见 cmets。

    double average(const double *arr, size_t len){
        //  Compute average
        return accumulate(arr, arr + len, 0) / (double)len;
    }
    
    int main(){
    
        double array[10] = //  Initialize it
    
        cout << average(array, 10) << endl;
    
        //  Alternatively: This could probably be made a macro.
        //  But be careful though since the function can still take a pointer instead
        //  of an array.
        cout << average(array, sizeof(array) / sizeof(double)) << endl;
    
        return 0;
    }
    

    【讨论】:

    • 我的数组大小在编译时就知道了,但我不能将它硬编码到外部函数文件中。我想要一个 sn-p 我可以保留在 myfunctions.h 之类的东西中,并在需要计算平均值时将其用于数组。
    • 在这种情况下,您应该将其作为带有单独大小参数的指针传递。
    【解决方案2】:

    在 C++ 中,您应该使用std::vector

    在 C/C++ 中,您不能将数组作为副本传递。数组总是通过引用传递。

    编辑

    在 C++ 中,引用传递的数组有不同的含义。在 C 和 C++ 中,数组衰减为指向数组第一个元素的指针。请检查下面的 cmets。

    【讨论】:

    • 数组总是通过引用传递并不完全正确,数组衰减为指针,然后该指针按值传递。不同之处在于类型发生了变化,在函数之外它可以是一个适当的数组(T [10]),而在函数内部它将被视为一个指针(T*),但有一些不同之处(@的结果987654324@是其中最大的)
    • 通过引用传递的数组 - 这意味着如果您修改数组内容,它将反映在函数之外。这就是我的意思。
    • 在 C++(不是 C)中,您可以通过引用传递数组,也可以传递指向第一个元素的指针,两者的语法都是:void f( int (&amp;x)[10] ); void g( int *p );,并且两种操作具有不同的语义。请注意,by-reference 在 C++ 中具有精确的含义,这并不意味着 可以在外部修改对象,否则 void h( int* )通过引用传递一个 int 。评论是因为我已经多次阅读这句话,并且我看到人们因此而感到困惑。数组没有被复制,但也不是通过引用传递,它衰减,指针按值传递。
    • @DavidRodríguez-dribeas:编辑了我的答案。我不知道在 c++ 中数组也可以通过引用传递。谢谢。
    【解决方案3】:

    在 C++ 中,数组的名称只是一个指向其第一个元素的常量指针常量指针表示一个指针,它能够改变它所指向的任何东西,但它不能被改变为指向别的东西。

    这意味着每当你传递一个数组时,你实际上是在传递一个常量指针到那个数组。换句话说,您已经通过引用传递了它,无需额外的努力。更准确地说,实际上复制的是那个常量指针,所以最后的(希望不是那么令人困惑的)措辞是你传递了一个指向数组的常量指针按值

    如果您在编译时不知道数组的大小,只需使用指向数据类型的(普通)指针而不是显式数组。所以无论T my_array[] 是什么(其中T 是一种类型,比如intdouble 甚至是你的一个类)都会变成T* my_array,并且以后的语法完全相同......my_array[i] 将工作正常(另一种语法也存在,但不那么优雅)。对于初始化,使用new 操作符:

    T* my_array;
    
    my_array = new T[3];
    

    T* my_array;
    
    my_array = new T[x];
    

    其中x 是一个整数(不一定像普通数组那样是常量)。这样,您可以在运行时从用户那里获取x,然后创建您的“数组”。请注意不要在使用完毕后忘记delete[] my_array,以避免内存泄漏。

    [Final Note] 使用这样的动态分配 数组是一个不错的选择,只有当你确切地知道你想要多少元素时……在编译时甚至在运行时。因此,例如,如果在用户提供他的x 之后,您将完全使用它们,那很好。否则,您将面临数组溢出的危险(如果您需要的不仅仅是x)——这通常会使应用程序崩溃——或者只是浪费一些空间。但即使是这种情况,您也将自己实现数组操作所需的大部分功能。这就是为什么最好使用 C++ 标准库提供的容器,比如std::vector(如Donotalo 提到的)。我只是想详细说明这一点。

    【讨论】:

      【解决方案4】:

      如果我不将数组作为 ( const double( &numbers ) [length] ) 传递, 因为例如我不知道它的大小,我如何确保它 没有被复制,但是被引用了?

      是的,这意味着您将数组作为引用传递,

      void Foo(const double( &numbers ) [length]);
      

      注意length 是一个常量整数。

      如果我像上面的例子一样传递一个数组,( double array[] ) 是 引用还是抄袭?

      不,它没有被复制。这意味着您正在传递一个指向您的数组的指针,该指针相当于,

      void Foo(const double *length);
      

      【讨论】:

        【解决方案5】:

        Java 和 Python 等其他语言确实会在运行时存储数组的长度。在 C++ 数组中,不存储数组的长度。这意味着您需要手动将其存储在某个地方。

        只要您的代码中有一个固定大小的数组,编译器就会知道该数组的大小,因为它是从源代码本身读取的。但是一旦代码被编译,长度信息就会丢失。例如:

        void f1(double array[10]) {...}
        

        编译器不会强制数组的大小。以下代码将静默编译,因为f1 的数组参数只是指向数组第一个元素的指针:

        void h1() {
            double a[10];
            double b[5];
        
            f1(a); // OK.
            f2(b); // Also OK.
        }
        

        由于编译器在将数组传递给函数时会忽略数组的静态大小,因此您必须知道作为引用传递的任意大小数组的大小的唯一方法是显式声明大小:

        void f2(double array[], size_t array_size) {...}
        

        然后你可以用任何数组调用那个函数:

        void h2() {
            double a[10];
            double b[19];
        
            f2(a, sizeof(a) / sizeof(a[0]));
            f2(b, sizeof(a) / sizeof(a[0]));
        }
        

        参数array_size包含数组的实际大小。

        请注意,sizeof(array) 仅适用于静态定义的数组。当您将该数组传递给另一个函数时,大小信息会丢失。

        数组与指针不同。但是,像f2 的参数这样的未定义大小的数组只是指向序列中第一个double 元素的指针:

        void f3(double array*, size_t array_size) {...}
        

        对于任何实际用途,f2f3 是等效的。

        这正是std::vector 的工作原理。在内部,向量是具有两个字段的类:指向第一个元素的指针和向量中的元素数。当您想要接受任何大小的数组作为参数时,这会使事情变得更简单:

        void g(std::vector& v) {...}
        

        【讨论】:

        • "这指示编译器只接受一个固定大小为 10 的数组作为参数。"不。
        【解决方案6】:

        其他答案很好,但没有人提到使用模板来处理这个问题。你仍然应该让你的函数接受一个指针和一个大小,但是模板可以自动为你填充:

        void f( double const numbers[], std::size_t length )
        { ... }
        
        template< std::size_t Length >
        void f( double const (&numbers)[ Length ] )
        {
            return f( numbers, Length );
        }
        

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-01-17
        • 1970-01-01
        • 2014-03-05
        • 2019-12-28
        • 2016-04-11
        • 2014-02-10
        • 1970-01-01
        • 2023-03-13
        相关资源
        最近更新 更多