您如何理解错误:无法从“int []”转换? 到“int []”
编译以下代码时:
void DoSomething(int Numbers[])
{
int SomeArray[] = Numbers;
}
VS2005 编译器抱怨错误 C2440: 'initializing' :无法从 'int []' 转换为 'int []'
我明白它实际上是在尝试将指针转换为一个不会发生的数组上班。 但是你如何向学习 C++ 的人解释这个错误呢?
When compiling the following code:
void DoSomething(int Numbers[])
{
int SomeArray[] = Numbers;
}
the VS2005 compiler complains with the error C2440: 'initializing' : cannot convert from 'int []' to 'int []'
I understand that really it's trying to cast a pointer to an array which is not going to work. But how do you explain the error to someone learning C++?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
假设存在类型和不完整类型:
是名为 A 的结构体的不完整类型。 而
是名为 A 的结构体的完整类型。第一个的大小尚不知道,而第二个的大小已知。
存在像上面的结构体这样的不完整的类类型。 但也有不完全数组类型:
那就是一种不完全数组类型,称为 A。它的大小尚不清楚。 您无法用它创建数组,因为编译器不知道该数组有多大。 但是您可以使用它来创建一个数组,仅如果您立即初始化它:
现在,编译器知道该数组是一个包含 3 个元素的 int 数组。 如果你尝试用指针初始化数组,编译器不会比以前更聪明,并且会拒绝,因为这不会给它要创建的数组的大小。
Say that there are types and incomplete types:
Is an incomplete type of a struct called A. While
Is a complete type of a struct called A. The size of the first is not yet known, while the size of the second is known.
There are incomplete class types like the above struct. But there are also incomplete array types:
That is an incomplete array type called A. Its size is not yet known. You cannot create an array out of it, because the compiler does not know how big the array is. But you can use it to create an array, only if you initialize it straight away:
Now, the compiler knows the array is an int array with 3 elements. If you try to initialize the array with a pointer, the compiler will not be any more clever than before, and refuse, because that won't give it the size of the array to be created.
为了让错误消息更有帮助,编译器实际上是在混淆事情。 即使
Numbers
参数被声明为数组,C/C++ 实际上不会(不能)传递数组 -Numbers
参数实际上是一个指针。因此,错误实际上应该是“无法从 'int *' 转换为 'int []'”
但这样就会出现混乱 - “嘿,不涉及
int*
在表达中”,有人可能会说。出于这个原因,最好避免数组参数 - 将它们声明为指针,因为这才是您真正得到的。 对学习 C/C++ 的人的解释应该让他们了解数组参数是虚构的 - 它们实际上是指针。
In trying to make the error message more helpful, the compiler is actually confusing things. Even though the
Numbers
parameter is declared as an array, C/C++ do not (cannot) actually pass an array - theNumbers
parameter is actually a pointer.So the error really should say
"cannot convert from 'int *' to 'int []'"
But then there would be confusion - "hey, there's no
int*
involved in the expression", someone might say.For this reason it really is better to avoid array parameters - declare them as pointers, since that's what you're really getting anyway. And the explanation to someone learning C/C++ should educate them on the fact that array parameters are a fiction - they're really pointers.
您需要向您想要帮助的人解释三件事:
数组不能按值传递给 C++ 中的函数。要做您想做的事情,您需要将数组的开头地址传递给 DoSomething(),以及单独的
int
中的数组大小(嗯,size_t
,但我懒得这么说)争论。 您可以使用表达式&(myArray[0])
获取某个数组myArray
的起始地址。 由于这是很常见的事情,C++ 允许您仅使用数组的名称(例如myArray
)来获取其第一个元素的地址。 (这可能有用,也可能令人困惑,具体取决于您看待它的方式。)为了让事情变得更加混乱,C++ 允许您指定数组类型(例如int Numbers[]
)作为参数到一个函数,但秘密地,它将该参数视为声明为指针(在本例中为int *Numbers
)——您甚至可以执行Numbers += 5
> 在DoSomething()
中使其指向从第六个位置开始的数组!在 C++ 中声明数组变量(例如
SomeArray
)时,必须提供显式大小或“初始化列表”,这是一个以逗号分隔的列表大括号之间的值。 编译器不可能根据您尝试初始化的另一个数组来推断数组的大小,因为...您无法将一个数组复制到另一个数组中,或初始化一个数组因此,即使参数
Numbers
实际上是一个数组(比如大小为 1000)而不是指针,并且您指定了SomeArray
的大小> (再次说 1000),行int SomeArray[1000] = Numbers;
是非法的。要在
DoSomething()
中执行您想要执行的操作,请首先问自己:Numbers
中的任何值吗?如果任一问题的答案是“否”,那么您实际上不需要首先复制
Numbers
—— 只需按原样使用它,而无需创建单独的 <代码>SomeArray 数组。如果两个问题的答案都是“是”,您将需要在
SomeArray
中复制Numbers
并对其进行处理。 在这种情况下,您确实应该将SomeArray
设为 C++vector
而不是另一个数组,因为这确实可以简化事情。 (解释向量相对于手动动态内存分配的优势,包括它们可以从其他数组或向量初始化,并且它们将在必要时调用元素构造函数,这与 C 风格不同memcpy()
。)There are three things you need to explain to the person you're trying to help:
Arrays can't be passed by value to a function in C++. To do what you are trying to do, you need to pass the address of the start of the array to
DoSomething()
, as well as the size of the array in a separateint
(well,size_t
, but I wouldn't bother saying that) argument. You can get the address of the start of some arraymyArray
with the expression&(myArray[0])
. Since this is such a common thing to want to do, C++ lets you use just the name of the array -- e.g.myArray
-- to get the address of its first element. (Which can be helpful or confusing, depending on which way you look at it.) To make things even more confusing, C++ allows you to specify an array type (e.g.int Numbers[]
) as a parameter to a function, but secretly it treats that parameter as though it was a declared as a pointer (int *Numbers
in this case) -- you can even doNumbers += 5
insideDoSomething()
to make it point to an array starting at the sixth position!When you declare an array variable such as
SomeArray
in C++, you must either provide an explicit size or an "initialiser list", which is a comma-separated list of values between braces. It's not possible for the compiler to infer the size of the array based on another array that you are trying to initialise it with, because...You can't copy one array into another, or initialise one array from another in C++. So even if the parameter
Numbers
was really an array (say of size 1000) and not a pointer, and you specified the size ofSomeArray
(again as say 1000), the lineint SomeArray[1000] = Numbers;
would be illegal.To do what you want to do in
DoSomething()
, first ask yourself:Numbers
?If the answer to either question is "No", you don't in fact need to make a copy of
Numbers
in the first place -- just use it as is, and forget about making a separateSomeArray
array.If the answer to both questions is "Yes", you will need to make a copy of
Numbers
inSomeArray
and work on that instead. In this case, you should really makeSomeArray
a C++vector<int>
instead of another array, as this really simplifies things. (Explain the benefits of vectors over manual dynamic memory allocation, including the facts that they can be initialised from other arrays or vectors, and they will call element constructors when necessary, unlike a C-stylememcpy()
.)当我试图解释某件事时,我总是尝试深入到最低的层次,然后从那里开始逐步展开。 这就是我喜欢学习东西的方式,我发现如果你从人们所知道的基础知识开始,然后从那里开始积累,人们会更舒服。
在这种情况下,我可能会从以下内容开始:
是的,与仅仅谈论有关大小、不完整类型等的知识相比,这可能有点矫枉过正。我意识到它也不完整(例如:没有讨论初始化器分配与正常分配等)。 然而,我的目标通常是让人们能够自己找出下一个答案,为此,你通常需要列出得出答案的思维过程。
When I'm trying to explain something, I always try to go down to the lowest level, and build up from there. That's they way I like to learn things, and I find that people are more comfortable if you start with the basics which they know, and build up from there.
In this case, I'd probably start with something like:
Yes, it's probably overkill vs just saying something about knowledge of size, incomplete types, etc. I realize it's also not complete (eg: no discussion of initializer assignment vs normal assignment, etc.). However, my goal is usually to get people to where they can figure out the next answer themselves, and for that you usually want to lay out the thought process for arriving at the answer.
也许你的答案可能是,“因为编译器不知道数组有多大。”
如果有明确的数组大小(为了清楚起见,可能使用 typedef),您的示例可以工作,然后您可以在引入可变大小分配时解释指针。
Perhaps your answer could be, "Because the compiler doesn't know how big the array is."
Your example could work if there were explicit array sizes (perhaps with a typedef for clarity), and then you can explain pointers while introducing variable size allocations.