- 我能像传递 int 和 bool 等基本类型一样传递数组给函数吗?
- 我能按值传递它们吗?
- 函数如何知道它所传递的数组的大小?
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;
}
你可以像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
或其他序列容器会更加优雅,除非你特别需要使用原生数组。
arr
本身获取大小,这就是我认为您当前措辞有点误导的地方。 - Troubadourconst
,唯一的区别是它只能在签名中定义的确切大小的数组中工作:void foo(int(&a)[3])
仅接受3个整数的数组。 - David Rodríguez - dribeasint N=10; void fun( int (&arr)[N] ) {}
。我做错了什么还是我们有不同的目的? - Troubadour我可以像传递int和bool等原始类型一样将数组传递给函数吗?
是的,你可以。将数组名称作为参数传递到函数会传递第一个元素的地址。
简而言之:
void foo(int a[]);
等同于
void foo(int * a);
我能通过值传递它们吗?
实际上不行。使用数组名称传递的“值”是第一个元素的地址。
传递 C 风格数组的唯一方法是将其包装在实现深拷贝语义的类或结构中。
函数如何知道它所传递的数组的大小?除非您的函数接受一个额外的参数,该参数是数组的大小,否则它不知道。
int a[]
和int* b
的等效性:实际上还存在一个区别,就是第一种形式不允许你操作指针(如a++
是非法的)。 - Raphaël Saint-Pierrea++
,它们是完全等价的。
@John,“没有办法接受或传递C风格数组的副本”在严谨性上是错误的。如果将数组包装到结构体中并按值取该结构体,则会复制包装的数组,并且函数将接收到C风格数组的副本。 - Johannes Schaub - litbvoid bar(int a[]) { ++a; *a = 7; }
在g++和comeau编译都通过。 - David Rodríguez - dribeas你可以传递一个数组,但是如果你想确切地知道它的大小,你必须同时传递大小:
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) {}
std::vector
和其他设计良好的对象(尽管这相对较少见)。通常情况下,你应该通过引用或 const 引用进行传递。void foo(int x[])
在it技术中,函数参数始终通过引用传递。此外,函数无法确定调用者传入的参数的真实大小,因此您必须假定一个大小(或将其作为单独的参数传递)。
C风格的数组在传入函数时表现非常奇怪。对于固定大小的数组,我建议使用std::array<int, 10>
代替,它可以像内置类型一样通过值传递。对于可变大小的数组,我建议使用std::vector<int>
,正如其他答案中所建议的。
void f(int a[]);
,可以这样调用:int myArr[size]; f(myArr);
2. 不需要,数组自动以引用方式传递。如果要模拟按值传递,必须将数组封装在结构体或类中。
3. 不会自动获取数组大小,需要手动传递大小。void foo(int(&a)[10])
。 - David Rodríguez - dribeas是的,您可以像原始类型一样传递它们。
如果您真的想要使用一些包装器代码按值传递,那么您也可以这样做,但您可能不应该这样做。
它将采用函数原型的大小作为长度 - 这可能与传入的数据匹配,也可能不匹配 - 因此它并不真正知道。
或者!
传递向量的引用或常量引用,更安全,并且可以轻松获取大小信息。
void foo(int (&a)[10])
将通过引用接收一个包含确切10个整数的数组。动态分配数组的问题有点复杂...new int[10]
的类型是int *
,而不是int [10]
,但您可以动态创建一个包含10个整数的数组:int (*p)[10] = new int[1][10];
,然后调用上一个函数:foo(*p)
。 - David Rodríguez - dribeasfunc(b)
虽然能编译通过,但是它的行为是未定义的。p
是一个指针参数,而不是一个数组。在func
函数签名中的char p[13]
可以被替换成char *p
。如果你想要实现你的目标(并且阻止那一行代码的编译),你可以使用void func(char (&p)[13])
,就像 dribeas 所说的那样。 - Steve Jessop