动态二维数组。为啥是分段错误?
Posted
技术标签:
【中文标题】动态二维数组。为啥是分段错误?【英文标题】:Dynamic 2D array. Why is segmentation fault?动态二维数组。为什么是分段错误? 【发布时间】:2019-11-23 23:16:56 【问题描述】:我的问题很简单。看看这段代码。
#include <iostream>
using namespace std;
int main()
int **arr = new int*[3];
cout << "arr : " << arr << endl; // It will display address, may be 0xffc1e...
cout << "*arr : " << *arr << endl; // will be just 0(zero), may be default value
cout << "**arr : " << **arr << endl; // it will display nothing, and after that program terminates
cout << "Program completed." << endl; // This will not display because program terminated
由于检索 **arr,此程序终止。如果我们摆脱线是 **arr。程序将正常完成,并会写成“程序完成”。 gdb 说这是分段错误。这样这段代码就可以工作了。
#include <iostream>
using namespace std;
int main()
int **arr = new int*[3];
cout << "arr : " << arr << endl; // It will display address, may be 0xffc1e...
cout << "*arr : " << *arr << endl; // will be just 0(zero), may be default value
cout << "Program completed." << endl; // This at last will be displayed
所以没有 **arr 所在的行,代码可以正常工作。为什么???
【问题讨论】:
'new' 分配了一个包含 3 个指向 int 的指针的数组,但它们没有设置为任何值。在它们出现之前,您可以阅读其中一个,但您无法阅读它所指向的内容。 @TedLyngmo 谢谢你,我有正确的感谢你。 您期望**arr
的值是多少?你能说服a rubber duck 你在某个时候设置了这个值吗?
同时打印*arr
和**arr
的语句具有未定义的行为。 arr
是三个未初始化指针的动态分配数组,因此访问 *arr
具有未定义的行为。评估**arr
过程的一部分涉及评估*arr
,因此它也具有未定义的行为。当行为未定义时,您可能会很幸运(或不幸,取决于您如何看待它)并且代码似乎可以工作。您的第二个代码示例(删除了打印**arr
)似乎工作的事实只是偶然 - 打印*arr
STILL 的语句具有未定义的行为。
@Makari21 - new int *[3]
动态分配三个指针的数组,但不初始化这些指针。因此,访问*arr
(或该数组的任何元素的值,例如arr[0]
、arr[1]
或arr[2]
)会给出未定义的行为。你很幸运——使用你的编译器/库,当你运行你的代码时——数组元素被初始化为空指针。标准没有要求。
【参考方案1】:
您已默认初始化动态数组。它是一个指针数组。默认初始化的指针有一个不确定的值。读取不确定值的行为是未定义的。
为什么???
因为程序的行为是未定义的。
未定义的行为意味着程序的行为没有任何保证。就语言而言,该程序可能:
产生您期望的输出。 产生出乎意料的输出。 生成您想要生成的输出。 产生一些您不想要的输出。 根本不产生输出。 崩溃 不会崩溃 在另一个系统上表现不同。 在同一系统上表现不同。 调试时表现不同。 只有在度假时才能表现得与众不同。 出于任何可能的原因采取不同的行为方式。 似乎完全没有理由表现出不同的行为。 始终保持一致 不要那样做。 有任何行为。应避免未定义的行为。
【讨论】:
谢谢你,你的回答这么快,太好了。你能告诉我这种行为的线索,我可以在其中读到吗?我的意思是一些文章或手册。 @Makari21:您可以阅读有关未定义行为的更多信息here。简而言之,这意味着如果您做了不允许做的事情,那么任何事情都可能发生(出错),例如您的程序可能由于分段错误而崩溃。但是,在我看来,您需要先阅读有关指针如何工作以及如何使用它们的正确 C/C++ 教程。 @Makari21 我添加了对未定义行为含义的解释。 @AndreasWenzel 谢谢。我是新手,我认为这些答案会对其他人有所帮助,因为我们描述了特定的实例。【参考方案2】:你已经为 3 个int*
分配了空间,但是你还没有初始化它们中的任何一个,所以像*arr
那样读取它们会使你的程序有未定义的行为。
从*arr
(如果有)返回的地址中读取,就像**arr
所做的那样,也会使其具有未定义的行为 - 并且经常导致崩溃(如果你幸运的话)。
你需要让int*
s 指向at。初始化指针。另请注意,对于每个new
,您都需要一个delete
,对于每个new[]
,您都需要一个delete[]
。
一些例子:
int main()
int** arr = new int*[3];
arr[0] = new int[5]; // an array of 5 int
arr[1] = new int[10]; // 10...
arr[2] = new int[20]; // 20...
// use arr
// cleanup
delete[] arr[2];
delete[] arr[1];
delete[] arr[0];
delete[] arr;
请注意,分配的内存仍未初始化,因此在将数据存储在其中之前,您不应该从中读取。
如果发生任何事情(如异常),清理工作很容易被遗忘或跳过。为此,有智能指针。起初它们可能看起来很尴尬,但会为您省去很多麻烦。
#include <iostream>
#include <memory>
int main()
std::unique_ptr<std::unique_ptr<int[]>[]> arr =
std::make_unique<std::unique_ptr<int[]>[]>(3);
arr[0] = std::make_unique<int[]>(5);
arr[1] = std::make_unique<int[]>(10);
arr[2] = std::make_unique<int[]>(20);
// using arr
std::cout << arr[0][4] << "\n"; // Using make_unique also default initialized the
std::cout << arr[1][9] << "\n"; // elements in the arrays, so reading from them is
std::cout << arr[2][19] << "\n"; // fine.
// all arrays held by smart pointers are automatically deleted when arr
// goes out of scope
【讨论】:
非常感谢。我的掌握变得更加完整。以上是关于动态二维数组。为啥是分段错误?的主要内容,如果未能解决你的问题,请参考以下文章