你如何理解错误:无法从'int []'转换为'int []'

Cra*_*ony 4 c++ arrays pointers visual-studio-2005 error-code

编译以下代码时:

void DoSomething(int Numbers[])
{
    int SomeArray[] = Numbers;
}
Run Code Online (Sandbox Code Playgroud)

VS2005编译器抱怨错误C2440:'initializing':无法从'int []'转换为'int []'

我明白,它真的试图将指针强制转换为无法正常工作的数组.但是,如何向学习C++的人解释错误?

Joh*_*itb 12

假设有类型和不完整类型:

struct A;
Run Code Online (Sandbox Code Playgroud)

是一个名为A的结构的不完整类型

struct A { };
Run Code Online (Sandbox Code Playgroud)

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

有不完整的类类型,如上面的结构.但是也有不完整的数组类型:

typedef int A[];
Run Code Online (Sandbox Code Playgroud)

这是一个名为A的不完整数组类型.它的大小尚不清楚.你不能用它创建一个数组,因为编译器不知道数组有多大.但是你可以它来创建一个数组,只有你立即初始化它:

A SomeArray = { 1, 2, 3 };
Run Code Online (Sandbox Code Playgroud)

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


Mic*_*urr 8

在尝试使错误消息更有帮助时,编译器实际上使事情变得混乱.即使Numbers参数声明为数组,C/C++也不会(不能)实际传递数组 - Numbers参数实际上是一个指针.

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

但是int*,有人可能会说,这会产生混淆 - "嘿,没有参与表达".

出于这个原因,最好避免使用数组参数 - 将它们声明为指针,因为这是你真正得到的.对学习C/C++的人的解释应该教育他们关于数组参数是虚构的事实 - 他们真的是指针.


j_r*_*ker 5

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

  1. 数组不能通过值传递给C++中的函数. 要做你想做的事情,你需要传递数组开头的地址DoSomething(),以及一个单独的int(好吧size_t,但我不打扰说)参数的数组大小.您可以myArray使用表达式获取某些数组的起始地址&(myArray[0]).由于这是一个常见的事情,C++允许您只使用数组的名称 - 例如myArray- 来获取其第一个元素的地址.(这可能会有所帮助或令人困惑,具体取决于您查看它的方式.)为了使事情更加混乱,C++允许您指定数组类型(例如int Numbers[])作为函数的参数,但是它秘密地将该参数视为声明为指针(int *Numbers在本例中) - 您甚至可以Numbers += 5在内部DoSomething()使其指向从第六个位置开始的数组!

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

  3. 您不能将一个数组复制到另一个数组中,或者在C++中从另一个数组初始化一个数组. 因此,即使参数Numbers实际上是一个数组(例如大小为1000)而不是指针,并且您指定了大小SomeArray(再次表示为1000),该行int SomeArray[1000] = Numbers;也是非法的.


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

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

如果任何一个问题的答案都是"否",那么你实际上并不需要Numbers首先复制它 - 只是按原样使用它,而忘记制作一个单独的SomeArray数组.

如果回答这两个问题是"是",你需要做的副本NumbersSomeArray,而是在有效的.在这种情况下,你应该真正做SomeArray一个C++ vector<int>而不是另一个数组,因为这真的简化了事情.(解释向量优于手动动态内存分配的好处,包括可以从其他数组或向量初始化它们的事实,并且它们将在必要时调用元素构造函数,这与C风格不同memcpy().)