C:当指针实际上是指向某个对象的指针时,函数会一直接收调零指针

C:当指针实际上是指向某个对象的指针时,函数会一直接收调零指针,c,segmentation-fault,C,Segmentation Fault,我为这个令人困惑的标题道歉,我希望我的解释将有助于澄清目前在你脑海中最有可能发生的困惑之雾。所以今天我决定尝试创建一个能够插入和搜索特定数字的二叉树程序。现在,当我完成我的搜索功能并决定测试它时,我得到了一个分段错误。然后我使用当前的IDE运行GDB来查找问题的根源。GDB随后返回以下消息: Program received signal SIGSEGV, Segmentation fault.

我为这个令人困惑的标题道歉,我希望我的解释将有助于澄清目前在你脑海中最有可能发生的困惑之雾。所以今天我决定尝试创建一个能够插入和搜索特定数字的二叉树程序。现在,当我完成我的搜索功能并决定测试它时,我得到了一个
分段错误
。然后我使用当前的IDE运行GDB来查找问题的根源。GDB随后返回以下消息:

  Program received signal SIGSEGV, Segmentation fault.                                                             
    0x0000000000400634 in search (num=503, dt=0x0) at main.c:39                                                      
    39          if(num < dt->data) {       
程序接收信号SIGSEGV,分段故障。
在main.c:39处搜索0x0000000000400634(num=503,dt=0x0)
39如果(numdata){
我似乎注意到,出于某种奇怪的原因,我的dt(函数用来导航二叉树的结构)指针变量已归零,即使我输入函数的变量指向分配的缓冲区。这让我困惑了很长一段时间,希望有人能帮助我找出问题的根源

我的代码:

#包括
#包括
#定义根节点500
类型定义结构_DNode{
int数据;
结构_DNode*右侧;
结构_DNode*左;
}节点;
Node*InitNode();
无效插入(int num,节点*dt);
int搜索(int num,节点*dt);
无效插入(整数,节点*dt){
if(num数据){
如果(dt->left==NULL){
dt->left=InitNode(num);
}否则{
插入(num,dt->left);
}
}否则{
如果(dt->right==NULL){
dt->right=InitNode(num);
}否则{
插入(num,dt->right);
}
}
}
整数搜索(整数,节点*dt){
if(numdata){
如果(dt->left==NULL){
返回-1;
}否则{
返回搜索(num,dt->left);
}
}否则{
如果(num>dt->data){
如果(dt->right==NULL){
返回-1;
}否则{
返回搜索(num,dt->left);
}
}
如果(num==dt->data){
返回0;
}
}
}
Node*InitNode(int num){
Node*TNode=(struct_DNode*)malloc(sizeof(Node));
TNode->right=NULL;
TNode->left=NULL;
TNode->data=num;
返回(TNode);
}
int main()
{
Node*root=InitNode(root\u节点);
根->数据=根节点;
插入(507,根部);
插入(503,根);
printf(“%i”,搜索(503,根));
}
在:

你的意思可能是:

           ...
                return search(num,dt->right);
           ...
在:

你的意思可能是:

           ...
                return search(num,dt->right);
           ...
缺陷 代码中的问题是调用的是传递树中的错误节点。因此

return search(num,dt->left);
在这个地方

if(dt->right == NULL) {
    return -1;
} else {
    return search(num,dt->left);
                      ^^^^^^
}
替代实施 在代码中,您没有利用递归代码。您对左子树和右子树重复了相同的不必要的代码,这不应该是这种情况

正确的代码可以如此简单

    int search(int num,Node *dt) {
        if(dt == NULL)  
             return -1;
        else if(dt->data == num) 
             return 0;
        else if(dt->data >= num) 
             return search(num,dt->left);
        else 
             return search(num,dt->right);
    }
此外,在代码中插入还有一点。在设置中,您永远不会将节点插入空树。只有当
不是
NULL
时,树插入才会正常工作。因此,插入代码应为空

Node * insert(Node *p, int num){
   if(p == NULL)
      return initNode(num);
   else if(num <= p->data)
      return p->left = insert(p->left,num);
   else
      return p->right = insert(p->right,num); 
}
缺陷 代码中的问题是调用的是传递树中的错误节点。因此

return search(num,dt->left);
在这个地方

if(dt->right == NULL) {
    return -1;
} else {
    return search(num,dt->left);
                      ^^^^^^
}
替代实施 在代码中,您没有利用递归代码。您对左子树和右子树重复了相同的不必要的代码,这不应该是这种情况

正确的代码可以如此简单

    int search(int num,Node *dt) {
        if(dt == NULL)  
             return -1;
        else if(dt->data == num) 
             return 0;
        else if(dt->data >= num) 
             return search(num,dt->left);
        else 
             return search(num,dt->right);
    }
此外,在代码中插入还有一点。在设置中,您永远不会将节点插入空树。只有当
不是
NULL
时,树插入才会正常工作。因此,插入代码应为空

Node * insert(Node *p, int num){
   if(p == NULL)
      return initNode(num);
   else if(num <= p->data)
      return p->left = insert(p->left,num);
   else
      return p->right = insert(p->right,num); 
}

尝试“模拟”手工编写代码,仔细浏览,这将帮助您找到出错的地方。这是理解此类问题的最佳方法,如果我面试您是为了一份编程工作,我会要求您这样做。复制并粘贴问题。选中
dt->right
后,
搜索(数值,dt->左)调用
时根本不检查
dt->left
。如果
dt->left
NULL
,则递归调用具有未定义的行为,因为它做的第一件事是访问其
数据
成员。可能最好对函数进行编码,以便它们检查
dt
是否为
NULL
,这样更安全使用任何指针调用
insert()
search()
。您的搜索函数并不总是返回值,AFAICS(GCC 7.2.0也同意我的看法)。如果您在编译时没有出现大量编译器警告,您应该这样做。如果您尝试使用
search()未返回的值,则会出现未定义的行为
@JonathanLeffler-我也看了一下。这不明显,但所有条件都会进入
if
else
子句之一,所以函数不会从末尾掉下来。我同意,可以对其进行编码以使其更明显。@Peter:Hmmm…是的,它看起来是“OK”,但我不接受编译器混淆的代码t因为如果编译器对此感到困惑,那么阅读代码的人也会感到困惑。如果代码测试了大于和小于的情况,则不需要测试是否相等;剩下的就是这些。尝试“模拟”手工编写代码,仔细浏览,这将帮助您找到出错的地方。这是理解此类问题的最佳方法,如果我面试您是为了一份编程工作,我会要求您这样做。复制并粘贴问题。选中
dt->right
后,
搜索(数值,dt->l