当编译以下代码时:
void DoSomething(int Numbers[])
{
int SomeArray[] = Numbers;
}
VS2005编译器报错:C2440: 'initializing' : 无法将'int []'转换为'int []'。
我理解实际上它试图将指针转换为数组,这是行不通的。但是如何向学习C++的人解释这个错误呢?
当编译以下代码时:
void DoSomething(int Numbers[])
{
int SomeArray[] = Numbers;
}
VS2005编译器报错:C2440: 'initializing' : 无法将'int []'转换为'int []'。
我理解实际上它试图将指针转换为数组,这是行不通的。但是如何向学习C++的人解释这个错误呢?
假设存在类型和不完整类型:
struct A;
一个被称为A的结构体的不完全类型。
struct A { };
一个名为A的结构体被称为完整类型。第一个结构体的大小尚未知道,而第二个结构体的大小已知。
像上面的结构体一样,存在不完整的类类型。但也存在不完整的数组类型:
typedef int A[];
这是一个名为A的不完整数组类型。它的大小尚未确定。您不能创建一个数组,因为编译器不知道数组有多大。但是您可以使用它来创建一个数组,只有在立即初始化它的情况下才能这样做:
A SomeArray = { 1, 2, 3 };
现在,编译器知道该数组是一个有3个元素的int数组。如果你尝试用指针初始化该数组,编译器不会比之前聪明多少,并且会拒绝,因为这样无法给它创建数组的大小。
Numbers
参数被声明为一个数组,但C/C++实际上不会(也不能)传递一个数组——Numbers
参数实际上是一个指针。"无法将'int *'转换为'int []'"
。int*
啊",有人可能会说。C++中无法将数组以值传递给函数。 为了实现你想做的事情,你需要将数组开始的地址和数组大小(用一个单独的int
参数表示,实际上应该使用size_t
,但是我不会特别强调)一起传递给DoSomething()
。你可以通过表达式&(myArray[0])
获取某个数组myArray
的开始地址。由于这是一个非常普遍的需求,C++允许你只使用数组的名称,例如myArray
,来获取它的第一个元素的地址。(根据你的角度看,这可能会有所帮助或者混淆。)更令人困惑的是,C++允许你将数组类型(例如int Numbers[]
)指定为函数的参数,但是在内部,它将该参数视为一个指针(在本例中为int *Numbers
)--你甚至可以在DoSomething()
内部使用Numbers += 5
,使其指向从第六个位置开始的数组!
在C++中声明数组变量时,必须提供显式大小或“初始化器列表”,后者是用花括号括起来的逗号分隔值的列表。编译器无法根据你正在尝试初始化它的另一个数组来推断数组的大小,因为...
在C++中无法将一个数组复制到另一个数组中,也无法从另一个数组初始化一个数组。 因此,即使参数Numbers
实际上是一个数组(例如大小为1000),而不是一个指针,并且你指定了SomeArray
的大小(例如同样为1000),行int SomeArray[1000] = Numbers;
仍然是非法的。
要在DoSomething()
中实现你想要的功能,请首先问自己:
Numbers
中的任何值吗?如果两个问题的答案都是“否”,那么实际上你根本不需要首先复制Numbers
--只需直接使用它,并忘记创建一个单独的SomeArray
数组。
Numbers
复制到SomeArray
中并在其上进行操作。在这种情况下,你应该真正地将SomeArray
作为C++vector<int>
而不是另一个数组,因为这真的简化了事情。(解释向量相对于手动动态内存分配的好处,包括它们可以从其他数组或向量初始化,并且当必要时它们会调用元素构造函数,而不像C风格的memcpy()
。)