C ++动态整数数组有时会导致崩溃
C++ dynamic array of ints sometimes causes crash
我写了一个简单的代码如下:
void show(const int a[], unsigned elements);
int main()
{
show(new int[]{1, 2, 3, 45}, 4); //does not work
}
void show(const int a[], unsigned elements)
{
cout << "{ ";
for (int i = 0; i < elements; i++)
{
cout << a[i];
if (i != elements - 1)
cout << ",";
cout << " ";
}
cout << "}";
}
它应该只输出 { 1, 2, 3, 45 }。如果我在括号
中包含一个尺寸
show(new int[4]{1, 2, 3, 45}, 4);
然后就可以了。所以我很自然地假设如果我这样写 new
我必须指定大小(尽管我认为给它一个初始化列表会暗示大小)。但是,奇怪的是,当在 show 函数调用处设置断点并且我 运行 它一步步通过调试器时,程序正确输出所有内容并像它应该的那样在 main 结束时终止。如果我不使用调试器,它要么在输出“{”后崩溃,要么输出整个“{ 1, 2, 3, 45 }”和断言失败“程序:... "Expression: _CrtIsValidHeapPointer(pUserData) ... "
我很想知道为什么会这样。另外,我在 Windows 8.
上使用 Visual Studio
编辑:我是 using namepsace std
。请不要评论使用名称空间或如何更好地编写此代码。我只对这个问题的原因感兴趣。
编辑 回复评论中的其他问题。
快速地说,是的,它会 "still" 是一个指针,是的,当您添加 4.
时,它会使用 clang 和 gcc 进行编译。
然而,有一些事情正在发生,我最初的回答是一个简化。问题是您的表达式一开始就不是格式正确的,因此不清楚它应该评估什么或类型应该是什么。考虑
If type is an array type, all dimensions other than the first must be specified as positive integral constant expression (until C++14)converted constant expression of type std::size_t (since C++14), but the first dimension may be any expression convertible to std::size_t.
来源:http://en.cppreference.com/w/cpp/language/new
正如它所说,无论哪种方式,括号中都必须有一个表达式。这使得很难说表达式是否 仍然 计算为指针。一个格式正确的 new
表达式确实会计算为一个指针,无论它有多少维度,即使它的值为零。当我在这里说指针时,我严格来说是指表示,而不是类型。
关键是类型,至少"inside" new
,根据你有多少维度是不同的。所以,无论你
new int
new int[6]
new int[12][14]
表示是相同的(指针),但是 new
看到的类型在每种情况下都不同。编译器能够响应 new
中的不同类型(类比函数重载)。特别是,当类型为数组类型时,可以使用包含多个元素的花括号初始化列表来初始化新内存。
我最好的猜测是,由于 VS 在没有表达式的情况下接受括号,它正在为单个 int
或 int[0]
分配内存。在前一种情况下,它错误地允许您将其初始化为数组类型,而在后一种情况下,分配的内存无论如何都不够用。你的 main
然后写了一个堆守卫,它可以在调试模式下捕获这种东西。当在 main
末尾或程序终止时对此进行检查时,您会看到这些症状。输出中的不稳定是由于不同的堆布局或由于输出流中的缓冲。
原回答
您的 new
表达式,如果格式正确,将具有标量类型,这意味着结果是 "single value"。该单个值是一个指向整数的指针,特别是指向您要创建的数组开头的那个。这就是 "dynamic arrays" 在 C++ 中的表示方式。类型系统不 "know" 它们的大小。
您正在尝试使用包含 4 个值的初始化程序列表来初始化此单个指针值。这不应该工作。我不确定这是否应该编译。它肯定没有用 clang 或 gcc 编译,我很惊讶它在 Visual Studio.
中工作
我写了一个简单的代码如下:
void show(const int a[], unsigned elements);
int main()
{
show(new int[]{1, 2, 3, 45}, 4); //does not work
}
void show(const int a[], unsigned elements)
{
cout << "{ ";
for (int i = 0; i < elements; i++)
{
cout << a[i];
if (i != elements - 1)
cout << ",";
cout << " ";
}
cout << "}";
}
它应该只输出 { 1, 2, 3, 45 }。如果我在括号
中包含一个尺寸show(new int[4]{1, 2, 3, 45}, 4);
然后就可以了。所以我很自然地假设如果我这样写 new
我必须指定大小(尽管我认为给它一个初始化列表会暗示大小)。但是,奇怪的是,当在 show 函数调用处设置断点并且我 运行 它一步步通过调试器时,程序正确输出所有内容并像它应该的那样在 main 结束时终止。如果我不使用调试器,它要么在输出“{”后崩溃,要么输出整个“{ 1, 2, 3, 45 }”和断言失败“程序:... "Expression: _CrtIsValidHeapPointer(pUserData) ... "
我很想知道为什么会这样。另外,我在 Windows 8.
上使用 Visual Studio编辑:我是 using namepsace std
。请不要评论使用名称空间或如何更好地编写此代码。我只对这个问题的原因感兴趣。
编辑 回复评论中的其他问题。
快速地说,是的,它会 "still" 是一个指针,是的,当您添加 4.
时,它会使用 clang 和 gcc 进行编译。然而,有一些事情正在发生,我最初的回答是一个简化。问题是您的表达式一开始就不是格式正确的,因此不清楚它应该评估什么或类型应该是什么。考虑
If type is an array type, all dimensions other than the first must be specified as positive integral constant expression (until C++14)converted constant expression of type std::size_t (since C++14), but the first dimension may be any expression convertible to std::size_t.
来源:http://en.cppreference.com/w/cpp/language/new
正如它所说,无论哪种方式,括号中都必须有一个表达式。这使得很难说表达式是否 仍然 计算为指针。一个格式正确的 new
表达式确实会计算为一个指针,无论它有多少维度,即使它的值为零。当我在这里说指针时,我严格来说是指表示,而不是类型。
关键是类型,至少"inside" new
,根据你有多少维度是不同的。所以,无论你
new int
new int[6]
new int[12][14]
表示是相同的(指针),但是 new
看到的类型在每种情况下都不同。编译器能够响应 new
中的不同类型(类比函数重载)。特别是,当类型为数组类型时,可以使用包含多个元素的花括号初始化列表来初始化新内存。
我最好的猜测是,由于 VS 在没有表达式的情况下接受括号,它正在为单个 int
或 int[0]
分配内存。在前一种情况下,它错误地允许您将其初始化为数组类型,而在后一种情况下,分配的内存无论如何都不够用。你的 main
然后写了一个堆守卫,它可以在调试模式下捕获这种东西。当在 main
末尾或程序终止时对此进行检查时,您会看到这些症状。输出中的不稳定是由于不同的堆布局或由于输出流中的缓冲。
原回答
您的 new
表达式,如果格式正确,将具有标量类型,这意味着结果是 "single value"。该单个值是一个指向整数的指针,特别是指向您要创建的数组开头的那个。这就是 "dynamic arrays" 在 C++ 中的表示方式。类型系统不 "know" 它们的大小。
您正在尝试使用包含 4 个值的初始化程序列表来初始化此单个指针值。这不应该工作。我不确定这是否应该编译。它肯定没有用 clang 或 gcc 编译,我很惊讶它在 Visual Studio.
中工作