【问题标题】:How do you make sense of the error: cannot convert from 'int []' to 'int []'您如何理解错误:无法从 'int []' 转换为 'int []'
【发布时间】:2010-10-06 20:22:24
【问题描述】:

编译以下代码时:

void DoSomething(int Numbers[])
{
    int SomeArray[] = Numbers;
}

VS2005 编译器报错 C2440: 'initializing' : cannot convert from 'int []' to 'int []'

我知道它实际上是在尝试将一个指针转换为一个不起作用的数组。但是你如何向学习 C++ 的人解释这个错误呢?

【问题讨论】:

    标签: c++ arrays visual-studio-2005 pointers error-code


    【解决方案1】:

    说有类型和不完全类型:

    struct A;
    

    是结构体的不完整类型,称为 A. While

    struct A { };
    

    是一个名为 A 的结构的完整类型。第一个的大小尚不清楚,而第二个的大小是已知的。

    存在不完整的类类型,如上述结构。但也有不完整的数组类型:

    typedef int A[];
    

    这是一个不完整的数组类型,称为 A。它的大小尚不清楚。您不能从中创建数组,因为编译器不知道数组有多大。但是你可以使用它来创建一个数组,只有如果你直接初始化它:

    A SomeArray = { 1, 2, 3 };
    

    现在,编译器知道该数组是一个包含 3 个元素的 int 数组。如果您尝试使用指针初始化数组,编译器将不会比以前更聪明,并且会拒绝,因为这不会给它要创建的数组的大小。

    【讨论】:

    • -1 抱歉。都是真的,但我认为这个答案可能过于抽象,对提问者没有用处。根据他的示例代码,我的猜测是,他可能认为数组是按值传递给接收 int[] 参数的函数的。
    • 我的意思是提问者试图帮助的人...... :)
    • 我认为有两个问题。一个是使用指针初始化数组,另一个是为什么它说“无法从 T 转换为 T”。你是对的,我只解释了其中的一小部分。写出好的长答案更难,所以我保持简短,因为我会搞砸:)
    【解决方案2】:

    在试图使错误消息更有帮助时,编译器实际上是在混淆事情。即使Numbers 参数被声明为一个数组,C/C++ 并不(不能)实际传递一个数组——Numbers 参数实际上是一个指针。

    所以错误真的应该说"cannot convert from 'int *' to 'int []'"

    但随后会有混乱 - “嘿,表达式中没有 int*”,有人可能会说。

    出于这个原因,最好避免使用数组参数——将它们声明为指针,因为这就是你真正得到的东西。对学习 C/C++ 的人的解释应该让他们明白数组参数是虚构的——它们实际上是指针。

    【讨论】:

    • 您实际上说得很好:) 我尝试同样直接地制定有关数组参数的业务,但随后限制自己解释有关初始化的内容。无论如何,你会得到 +1 :p
    【解决方案3】:

    您需要向您要帮助的人解释三件事:

    1. 数组不能按值传递给 C++ 中的函数。 要执行您想做的事情,您需要将数组的起始地址传递给 @ 987654321@,以及单独的int(好吧,size_t,但我不会这么说)参数中的数组大小。您可以使用表达式&(myArray[0]) 获取某个数组myArray 的开始地址。由于这是一件很常见的事情,C++ 允许您只使用数组的名称——例如myArray -- 获取其第一个元素的地址。 (这可能会有所帮助或令人困惑,这取决于您看待它的方式。)为了使事情更加混乱,C++ 允许您将数组类型(例如int Numbers[])指定为函数的参数,但它偷偷地对待该参数就好像它被声明为一个指针(在这种情况下为int *Numbers)——您甚至可以在DoSomething() 中执行Numbers += 5,使其指向从第六个位置开始的数组!

    2. 当您在 C++ 中声明数组变量(例如 SomeArray)时,您必须提供显式大小或“初始化器列表”,这是一个逗号分隔的值列表大括号之间。编译器不可能根据您尝试初始化它的另一个数组来推断数组的大小,因为...

    3. 您不能将一个数组复制到另一个数组中,或者在 C++ 中从另一个数组初始化一个数组。 所以即使参数 Numbers 确实是一个数组(比如大小为 1000)而不是指针,并且您指定了 SomeArray 的大小(同样是 1000),int SomeArray[1000] = Numbers; 行将是非法的。


    DoSomething()做你想做的事,先问问自己:

    1. 是否需要更改Numbers 中的任何值?
    2. 如果是这样,我是否要阻止调用者看到这些更改?

    如果任何一个问题的答案都是“否”,那么实际上您一开始就不需要复制Numbers - 只需按原样使用它,而无需单独制作SomeArray数组。

    如果这两个问题的答案都是“是”,您将需要在SomeArray 中复制Numbers 并继续处理。在这种情况下,您真的应该将 SomeArray 设为 C++ vector<int> 而不是另一个数组,因为这确实简化了事情。 (解释向量相对于手动动态内存分配的好处,包括它们可以从其他数组或向量初始化的事实,并且它们会在必要时调用元素构造函数,这与 C 风格 memcpy() .)

    【讨论】:

      【解决方案4】:

      当我试图解释某事时,我总是试图从最底层开始,然后从那里开始。这就是我喜欢的学习方式,我发现如果你从人们所知道的基础开始,然后从那里开始积累,他们会更自在。

      在这种情况下,我可能会从以下内容开始:

      编译器正在尝试执行 作业,因为你写了一个 赋值操作。在 C++ 中,你 不能直接分配给数组, 因为它没有内置赋值 运算符(任何类型的,仅 支持初始化器和索引 对于数组)。因为 C++ 支持 类型的重载运算符, 然后编译器寻找一个重载的 的赋值运算符 “分配给”类型,它采用 “assigned-from”类型作为其参数。 由于也没有重载 int[] 的运算符,它采用 int[] 作为参数,编译器错误 这条线,错误告诉你 为什么编译器无法处理该行。

      是的,这可能有点矫枉过正,而只是说一些关于大小、不完整类型等的知识。我意识到它也不完整(例如:没有讨论初始化赋值与正常赋值等)。但是,我的目标通常是让人们自己找到下一个答案,为此,您通常需要列出得出答案的思考过程。

      【讨论】:

      • 我喜欢这个答案,因为它确实解释了错误措辞
      • 是的,这是处理它的好方法。很遗憾,在这种情况下编译器的错误消息真的没有帮助......
      【解决方案5】:

      也许您的答案可能是,“因为编译器不知道数组有多大。”

      如果有明确的数组大小(为了清楚起见,可能使用 typedef),您的示例可以工作,然后您可以在引入可变大小分配时解释指针。

      【讨论】:

      • 这只是一半。在 C/C++ 中,看起来像数组类型的参数类型(令人困惑)实际上是指针类型——编译器将忽略在顶行 [] 之间给出的任何大小,并且仍然抱怨您试图将地址分配给即使您提供数组的大小,也可以使用数组。
      猜你喜欢
      • 1970-01-01
      • 2021-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-02
      相关资源
      最近更新 更多