【问题标题】:Why do I get segmentation fault if I don't use "new" keyword?如果我不使用“new”关键字,为什么会出现分段错误?
【发布时间】:2019-11-13 14:29:33
【问题描述】:

以下代码会产生分段错误。如果我在堆上为我的 node1 分配内存,我不会遇到分段错误。 (Node* node1 = new Node)。我的问题是为什么我现在会出现分段错误? Node* node1; 行不应该在堆栈上为我的 node1 获取内存吗?

class Node{
    public:
        int data;
        Node* next;
};

int main(){
    Node* node1;
    node1->data = 5;

    cout << node1->data << endl;
}

我打印了 node1 的地址并添加了一条 cout 行:

int main(){
    Node* node1;
    cout << &node1 << endl;
    node1->data = 5;

    cout << node1->data << endl;
}

现在错误消失了。每当我评论 cout 行时,错误就会回来。谁能解释这种行为?

【问题讨论】:

  • node1 未初始化
  • 详细来说,Node*Node 在内存中的地址。如果你不初始化它,它将指向任何旧地址。因此,当您尝试访问那里的节点时,操作系统会伸出手臂并发出段错误,因为您正在尝试访问您无权访问的内存段。
  • @parktomatomi 我编辑了这个问题。所以试图到达指针的地址给了我权限,对吗?这是错误消失的原因吗?
  • 谁能解释这种行为? 这就是未定义的行为。当您违反语言规则时,任何事情都可能发生。
  • @NoN 只有操作系统可以任意访问内存中的地址。您的程序在所谓的用户空间中运行,因此您必须向操作系统询问您可以访问的内存块。这就是 new 在幕后所做的。

标签: c++ linked-list segmentation-fault


【解决方案1】:

Node* node1; 行不应该在堆栈上为我的node1 获取内存吗?

Node* node1; 在堆栈上为指针node1 获取内存。然而,在那之后,指针node1 未初始化并且没有指向任何有效的地方。这就是为什么您需要在更改它指向的数据之前使其指向某个有效的位置,而这样做的一种方法是使用new

【讨论】:

  • 请注意,如果您不使用指针,而只是初始化Node node1,则不需要使用new,但这(通常)不是您想要的。
  • 我编辑了这个问题。为什么当我尝试到达node1的地址时,分段错误消失了?
  • @NoN 您不应该将问题编辑成不同的问题。无论如何,您所做的是未定义的行为,并且 UB 无法保证。它有时似乎可以工作,但有时会使您的程序崩溃,或者做一些完全不同的事情。因此,试图弄清楚为什么 UB 会这样做并没有任何好处。
  • 请停止推荐new朋友。
  • 我希望这个学术练习需要使用new
【解决方案2】:

问题:为什么我现在会出现分段错误?

Answer: 每当我们访问超出程序段的内存时,就会出现分段错误。

问题:不应该 Node* node1;行为我的 node1 获取内存 堆栈?

回答: 1. 在Node * node1; 中,node1 只是指向 Node 对象的指针类型变量。 node1 指针大小不依赖于 Node 结构的成员。它在 32 位操作系统/平台中只有 4 个字节长。此指针变量应仅用于存储地址 这里的指针类型是Node

  1. 目前它持有垃圾值。

  2. 我们必须使用 "Node *node1 = new Node;" 或本地(非动态)创建类型为 Node 的对象(分配内存)为 "Node node1;,现在我们可以使用 -> (pointer) 访问为 Node 创建的内存到成员)操作员或使用。 (点)运算符。

问题:我打印了node1的地址加cout行?

答案:您打印的是指针变量的地址,而不是 Node 对象。

问题:每当我评论 cout 行时,错误就会回来。能 有人解释这种行为吗?

答案:1. 行为将是不可预测的,因为您正在使用垃圾地址(存在于 node1 指针变量中)。

  1. 如果指针变量(垃圾)指向被其他进程保护/使用的内存,那么我们将得到分段错误。

  2. 如果垃圾地址指向尚未被其他进程使用/保护的内存,我们可能不会收到任何错误。

我希望它现在清楚了。如果有任何后续问题,请告诉我。

【讨论】:

    【解决方案3】:

    为了使用您的对象,构造函数必须存在并在您实例化对象时使用。如果您不提供任何构造函数,编译器可以在某些条件下隐式定义构造函数,但最终,如果您希望实例化对象,则构造函数必须存在。

    【讨论】:

      猜你喜欢
      • 2018-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-23
      相关资源
      最近更新 更多