const double( &numbers ) [size]
但这意味着我需要在编译时知道数组的大小,因此我无法在外部函数中使用它。
我的问题是:
1.如果我不将数组作为
(const double(& numbers)[length])
传递,因为例如我不知道它的大小,那么我如何确保它不会被复制,而是被引用?
2.如果我像上面的例子一样传递一个数组,(double array[])
是被引用还是被复制?const double( &numbers ) [size]
(const double(& numbers)[length])
传递,因为例如我不知道它的大小,那么我如何确保它不会被复制,而是被引用?
2.如果我像上面的例子一样传递一个数组,(double array[])
是被引用还是被复制?其他答案都很好,但没有人提到使用模板来处理这个问题。你仍然应该让你的函数接受一个指针和一个大小参数,但是模板可以自动填充它们:
void f( double const numbers[], std::size_t length )
{ ... }
template< std::size_t Length >
void f( double const (&numbers)[ Length ] )
{
return f( numbers, Length );
}
在C++中,你应该使用std::vector。
在C/C++中,你不能将数组作为副本传递。数组始终是按引用传递的。
编辑
在C++中,按引用传递的数组有不同的含义。在C和C++中,数组会衰减为指向数组第一个元素的指针。请查看下面的评论。
T [10]
),而在函数内部它将被视为指针(T*
),其中包含一些差异(sizeof
的结果是其中最大的差异)。 - David Rodríguez - dribeasvoid f( int (&x)[10] ); void g( int *p );
并且这两种操作具有不同的语义。请注意,在C++中,“按引用传递”具有特定的含义,并不意味着“可以在外部修改对象”,否则void h( int* )
将成为“按引用传递int”。这句话是因为我已经读了很多遍,而且我看到有人因此感到困惑。数组没有被复制,但也不是通过引用传递的,而是“衰减”,即传递了指针的值。 - David Rodríguez - dribeasvoid Foo(const double( &numbers ) [length]);
length
是一个常量整数。
如果我像上面的例子一样传递一个数组(double array []),它是引用还是副本?
不,它没有被复制。这意味着您正在传递指向数组的指针,这等同于:
void Foo(const double *length);
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;
}
T my_array[]
(其中T
是一种类型,如int
,double
或甚至是您的某个类),都会变成 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
以避免内存泄漏。
[最终注释]仅当您确切知道需要多少元素时(无论是在编译时还是在运行时),使用此类动态分配数组才是一个好选择。因此,例如,如果用户提供了他的x
,您将准确地使用它们,那么这很好。否则,您面临着溢出数组的危险(如果需要超过x
)-这通常会导致应用程序崩溃-或者只是浪费一些空间。但即使是这种情况,您也将自己实现大多数所需的数组操作函数。这就是为什么最好使用C ++标准库提供的容器,如std::vector
(正如Donotalo所提到的)。我只是想更详细地阐述这一点。
像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) {...}
对于任何实践目的,f2
和f3
是等效的。
这正是std::vector
的工作方式。在内部,向量是一个具有两个字段的类:指向第一个元素的指针和向量中的元素数量。当您想要接受任何大小的数组作为参数时,这使事情变得更简单:
void g(std::vector& v) {...}