编译以下代码时:
void DoSomething(int Numbers[])
{
int SomeArray[] = Numbers;
}
VS2005编译器抱怨错误C2440:'初始化':无法从'int []'转换为'int []'
我知道它确实在尝试将指针强制转换为不起作用的数组。但是,如何向学习C ++的人解释错误?
答案 0 :(得分:12)
说有类型和不完整的类型:
struct A;
是一个名为A.的结构的不完整类型。
struct A { };
是一个名为A的结构的完整类型。第一个的大小尚不清楚,而第二个的大小是已知的。
有不完整的类类型,如上面的结构。但是也存在不完整的数组类型:
typedef int A[];
这是一个名为A的不完整数组类型。它的大小尚不清楚。你不能用它创建一个数组,因为编译器不知道数组有多大。但是你可以使用来创建一个数组,只有 才能立即初始化它:
A SomeArray = { 1, 2, 3 };
现在,编译器知道数组是一个包含3个元素的int数组。如果您尝试使用指针初始化数组,编译器将不再比以前更聪明,并且拒绝,因为这不会给它创建要创建的数组的大小。
答案 1 :(得分:8)
在尝试使错误消息更有用时,编译器实际上是混乱的。即使Numbers
参数声明为数组,C / C ++也不会(不能)实际传递数组 - Numbers
参数实际上是指针。
所以错误确实应该说"cannot convert from 'int *' to 'int []'"
但是那会有混乱 - “嘿,表达中没有int*
参与”,有人可能会说。
由于这个原因,最好避免使用数组参数 - 将它们声明为指针,因为这是你真正得到的。对学习C / C ++的人的解释应该教育他们关于数组参数是虚构的事实 - 他们真的是指针。
答案 2 :(得分:5)
您需要向您尝试提供帮助的人解释三件事:
数组不能通过值传递给C ++中的函数。要执行您要执行的操作,您需要将数组开头的地址传递给{ {1}},以及单独的DoSomething()
(嗯,int
中的数组大小,但我不打算说)参数。您可以使用表达式size_t
获取某个数组myArray
的开头地址。由于这是一个很常见的事情,C ++允许你只使用数组的名称 - 例如&(myArray[0])
- 获取其第一个元素的地址。 (这可能会有所帮助或混淆,具体取决于您查看它的方式。)为了使事情更加混乱,C ++允许您指定一个数组类型(例如myArray
)作为函数的参数,但是秘密地它将该参数视为声明为指针(在这种情况下为int Numbers[]
) - 您甚至可以在int *Numbers
内Numbers += 5
使其指向从...开始的数组第六名!
在C ++中声明数组变量(例如DoSomething()
)时,必须提供显式大小或“初始化列表”,这是逗号分隔的列表大括号之间的值。编译器无法根据您尝试初始化的另一个数组来推断数组的大小,因为......
您不能将一个数组复制到另一个数组中,或者在C ++中从另一个数组初始化一个数组。所以即使参数SomeArray
实际上是一个数组(比如大小) 1000)而不是指针,并且您指定了Numbers
的大小(再次说1000),行SomeArray
将是非法的。
要在int SomeArray[1000] = Numbers;
做你想做的事,先问自己:
DoSomething()
中的任何值?如果对这两个问题的回答都是“否”,那么您实际上并不需要首先复制Numbers
- 只是按原样使用它,而忘记单独生成{ {1}}数组。
如果这两个问题的答案都是“是”,则您需要在Numbers
中复制SomeArray
并对其进行处理。在这种情况下,你应该真正使Numbers
成为C ++ SomeArray
而不是另一个数组,因为这真的简化了事情。 (解释向量优于手动动态内存分配的好处,包括它们可以从其他数组或向量初始化的事实,并且它们将在必要时调用元素构造函数,这与C风格{{1 }}。)
答案 3 :(得分:4)
当我试图解释一些事情时,我总是试着降到最低级别,并从那里开始建立。这就是我喜欢学习的方式,我发现如果你从他们所知道的基础开始,并从那里建立起来,人们就会感到更舒服。
在这种情况下,我可能会从以下内容开始:
编译器正在尝试执行此操作 任务,因为你写了一个 分配操作。在C ++中,你 无法直接分配给数组, 因为它没有内置的任务 运营商(任何类型,仅限 支持初始化和索引 对于数组)。因为C ++支持 重载运算符的类型, 然后编译器查找重载 赋值运算符 “分配给”类型 “assigned-from”类型作为其参数。 因为也没有超载 int []的运算符,它接受int [] 作为参数,编译器错误 这条线,错误告诉你 为什么编译器无法处理该行。
是的,这可能是过度杀戮而只是说一些关于大小,不完整类型等的知识。我意识到它也不完整(例如:没有初始化者分配与正常分配的讨论等)。然而,我的目标通常是让人们到达他们自己能够找到下一个答案的地方,为此你通常想要制定思考过程以获得答案。
答案 4 :(得分:3)
也许你的回答可能是,“因为编译器不知道数组有多大。”
如果存在明确的数组大小(为清晰起见可能使用typedef),您的示例可以工作,然后您可以在引入可变大小分配时解释指针。