C++ 指针空值检查的计算结果为true,即使未为其分配空值

C++ 指针空值检查的计算结果为true,即使未为其分配空值,c++,pointers,binary-tree,C++,Pointers,Binary Tree,这是一个用于创建二叉树的代码,它正在完美地执行。我不明白的是,在我看来,insert(string)函数中的if()语句的temp->left==NULL或temp->right==NULL条件是如何计算为TRUE的,它应该抛出一个分段错误,因为我没有将节点的left或right指针初始化为NULL #include<iostream> using namespace std; class node { public: string data; node *le

这是一个用于创建二叉树的代码,它正在完美地执行。我不明白的是,在我看来,
insert(string)
函数中的
if()
语句的
temp->left==NULL
temp->right==NULL
条件是如何计算为
TRUE
的,它应该抛出一个分段错误,因为我没有将节点的
left
right
指针初始化为
NULL

#include<iostream>
using namespace std;

class node
{
  public:
    string data;
    node *left,*right;
};

class btree
{
  private:
    node *root;

  public:
    btree()
    {
      root=NULL;
    }
    void create();
    void insert(string);
};

void btree:: create()
{
  cout<<"\n\nEnter the no. of nodes you want to create: ";
  int n;
  cin>>n;
  cin.ignore();
  for(int i=0;i<n;i++)
  {
    cout<<"\nEnter data for node "<<i+1<<": ";
    string input;
    getline(cin,input);
    insert(input);
  }
}

void btree:: insert(string str)
{
  if(root==NULL)
  {
    root=new node;
    root->data=str;
    return;
  }
  node *temp=root;
  while(temp!=NULL)
  {
    cout<<"\n\nDo you want to enter the node in the left subtree or the right subtree of "<<temp->data<<"?(l/r): ";
    char dir;
    cin>>dir;
    cin.ignore();
    if(dir=='l')
    {
      if(temp->left==NULL)
      {
        temp->left=new node;
        temp->left->data=str;
        return;
      }
      else
        temp=temp->left;
    }
    if(dir=='r')
    {
      if(temp->right==NULL)
      {
        temp->right=new node;
        temp->right->data=str;
        return;
      }
      else
        temp=temp->right;
    }
  }
}

int main()
{
  btree bt;
  bt.create();

  return 0;
}
为了检查这是否真的只是UB或是
new
操作符的影响,我运行了一个测试代码:

#include<iostream>
using namespace std;

class node
{
  public:
    int data;
    node *left,*right;
};

int main()
{
  node *root=new node;
  root=NULL;
  cout<<"\nroot = "<<root; //This cout is executed since root has been initialized to NULL 
  std::cout.flush();
  cout<<"\nroot->left = "<<root->left; //This line immediately throws segmentation fault
  std::cout.flush();

  return 0;
}
root = 0
Segmentation fault (core dumped)
因此,测试代码似乎能够识别UB并抛出SEGFULT。为什么不是第一个代码


我试图寻找一个类似的问题,但没有找到

您应该显式地初始化
NULL
0
nullptr
(首选
nullptr
)。正如其他评论者所提到的,当指针未初始化时,很有可能出现未定义的行为

最佳做法(IMHO):


“…因为我没有初始化过…”:未定义的行为包括出现在工作状态(可能是偶然获得内存/初始化为0)。@RichardCriten:我不认为这是未定义的行为,因为代码中多次检查该条件,但它从不生成错误。我不知道我遗漏了什么。至少我猜:您正在使用的内存分配器(what
new
calls)正在初始化所有
0
s的新内存。UB的行为未定义-segfault只是一种可能的结果,您的测试没有证明什么它取决于很多事情。可能内存分配器正在将所有内容设置为0,正如Richard Criten所指出的那样。它也可能是您的编译器初始化指向null的指针以帮助您进行调试。或者这可能只是纯粹的运气,记忆碰巧是0。这就是未定义行为的工作方式。您可能会遇到崩溃,但程序也可能看起来正常工作,或者由于编译器优化,您会得到非常奇怪的结果。从字面上说,任何事情都可能发生,没有“识别”UB这样的事情。但这正是我的观点!我从未将这些指针初始化为NULL,但是NULL检查的结果仍然是TRUE,其余的代码都被执行。为什么它不抛出错误?它就像一个未初始化的
int
。编译器不会生成错误。我们需要确保它已初始化,或者不会立即用作r值。@shaun022如果不初始化变量(指针或其他),它有一个不确定的值。您可以读取这样的值,但将其用于任何事情(如比较)都是未定义的行为。UB表示根据标准,您的程序没有任何意义,编译器可以做任何它想做的事情,不,它不需要生成警告或错误。@JesperJuhl:我认为这是UB。但我已经多次运行了这段代码,每次它都成功执行。在我的问题中,我还添加了一个测试代码,在试图访问未初始化的指针时,它会立即给出分段错误。所以我不明白为什么第一个代码没有抛出错误。@shaun022 Undefined Behavior是Undefined。它可能表现为您的代码什么都不做。撞车。做你想做的事或其他任何事。测试它并观察到特定的结果并不意味着什么——它仍然是未定义的,不同的编译器(或不同的编译器版本)、不同的优化级别或不同的平台或对程序其他部分的不相关更改可能会导致观察到的行为改变。
root = 0
Segmentation fault (core dumped)
class node
{
  public:
    string data;
    node *left = nullptr;
    node *right = nullptr;
};