【问题标题】:Recursive function passes NULL pointer when the argument is not NULL当参数不为 NULL 时,递归函数传递 NULL 指针
【发布时间】:2011-12-23 00:25:30
【问题描述】:

以下程序旨在使用 strcmp 函数在二叉搜索树中按字母顺序存储单词。这个问题,在程序下详细说明,是在函数的最后部分的函数的递归调用中没有传递指针。

typedef struct NodT{
   char word[30];
   struct NodT *left, *right;
} NOD;

void reset_field(NOD *nod){
    int i;
    for(i=0; i<30; i++){
        nod->word[i]='\0';
    }
}

void enter_recursively(NOD *nod, char *word){
    if(nod==NULL){
        nod= (NOD *) malloc(sizeof(NOD));
       nod->left=NULL;
       nod->right=NULL;
       reset_field(nod);
       strcpy(nod->word, word);
       return;
   }

   if(nod->word[0]=='\0'){
       strcpy(nod->word, word);
       return;
   }

   if(strcmp(nod->word, word)==0) return;

   if(strcmp(nod->word, word)<0){
       enter_recursively(nod->right, word);//the problem seems to be here
       printf("right\n");
   }
   else{
       enter_recursively(nod->left, word);//...and here
       printf("left\n");
   }
   //the NULL pointer is being sent over, which is peculiar
}

问题是,当我在 if-else 条件下将指针(左、右)从结构传递给递归函数时,它在另一侧取一个 NULL 值,这是不应该的,因为它们根据strcmp,分配第一个词在root中,第二个词在右边或左边后不为NULL,使用malloc为词创建新存储空间时的alocation。

更新:使用双指针的新脚本:

typedef struct NodT{
    int key;
    char word[30];
    struct NodT *left, *right;
} NOD;

void enter_recursively(NOD **nod, char *word){
        printf("N: %p\n", nod);
    printf("NL: %p\n", (**nod).left);
    printf("NR: %p\n", (**nod).right);
        if(nod==NULL){
            nod=malloc(sizeof(NOD));        
            (**nod).left=NULL;
            (**nod).right=NULL;
            strcpy((**nod).word, word);
            return;
        }
        if((**nod).word[0]=='\0'){
            strcpy((**nod).word, word);
            return;
        }

    if(strcmp((**nod).word, word)==0) return;

        if(strcmp((**nod).word, word)<0){
            enter_recursively((**nod).right, word);
        }
        else{
            enter_recursively((**nod).left, word);
        }

我遇到分段错误,我不知道为什么。

【问题讨论】:

  • 在您尝试访问其内容之前,请勾选nod == NULL(或只是nod :)。您可能只是在使用这些访问权限转储您的堆栈。
  • 请在你的编译器上启用警告,你在一个没有意义的非空函数中使用return;。此外,您的拳头 NULL 检查将永远不会匹配,如果 nod 在函数入口处为空,您将在此之前出现段错误。
  • 抱歉,我重新编辑了。退货;现在有意义
  • 这与您的问题没有直接关系,但for (i = 0; i &lt; 30; i++) { nod-&gt;word[0] = '\0'; } 没有意义。
  • @pmg,这只是我用来清除所有字符串以写入文件的函数。我已经添加了它,以防你们中的一些人发现它影响了其他功能。哦......我的糟糕我直到现在才注意到那个功能。那里应该是 word[i]。

标签: c pointers recursion reference binary-tree


【解决方案1】:

您的 enter_recursively() 函数分配了一个节点,甚至可能分配给它,但无法将其传递回调用者。想办法将有用的东西返回给调用者。

更新: 为了完整性:这是other将信息从子级传回其父级的方式:(通过返回值)

NOD * enter_recursively(NOD *ptr, char *word){
    int rc;

    if (ptr==NULL){
       ptr = malloc(sizeof *ptr);
       ptr->left = NULL;
       ptr->right = NULL;
       strcpy(ptr->word, word);
       return ptr;
   }

   rc = strcmp(ptr->word, word);
   if (rc==0) return ptr;

   if (rc < 0){
       ptr->right = enter_recursively(ptr->right, word);
       fprintf(stderr, "right\n");
   }
   else {
       ptr->left = enter_recursively(ptr->left, word);
       fprintf(stderr, "left\n");
   }
   return ptr; /* not reached */
}

【讨论】:

  • 我已经重新编辑,从函数中删除了指针 *right 和 *left 并添加了 nod->left 和 nod->right 到递归调用,我在第一个原始程序中使用过,那也没有用。我将尝试 Tio Pepe 在另一个答案中建议的双指针。
  • 基本上,有两种方法可以将信息从函数传回给它的调用者。显而易见的方法是使用返回值。另一种方法是使用指针参数(在这种情况下是指向指针的指针,因为您要传达的东西是指针) 第三种方法,使用全局变量是可能的,但不建议使用。
  • 如果改为使用指向指针的指针,您会将指针存储的地址复制到另一个指针,并使用地址所在的全新指针引用指向的值抄袭? (我试过了)
  • 如果你想理解它,首先假设结果不是指针而是整数。在这种情况下,您可以使用“int func(...) { return 42; }”或“void func(int *p, ...) { *p = 42; }”。现在,将 int 替换为 *NOD,就差不多了。
【解决方案2】:

问题是*nod被修改但没有返回:更改

void enter_recursively(NOD *nod, char *word)

void enter_recursively(NOD **nod, char *word)

为了返回合法的指针。在函数内部,使用 *nod 代替 nod,这是正确的方法。

当您只将 NOD * 传递给函数时,分配的内存不会正确存储。就像当你想在函数中修改一个 int 值时,你传递的是它的地址,而不是值。

此外,在使用它们之前始终验证空指针。你可以获得一个核心。

最终的代码接缝如下:

void enter_recursively(NOD **nod, char *word){
    if (*nod==NULL){
        *nod=malloc(sizeof(NOD));        
        (*nod)->left=NULL;
        (*nod)->right=NULL;
        strcpy((*nod)->word, word);
        return;
    }
    if((*nod)->word[0]=='\0'){
        strcpy((*nod)->word, word);
        return;
    }

    if(strcmp((*nod)->word, word)==0) return;

    if(strcmp((*nod)->word, word)<0){
        enter_recursively(&(*nod)->right, word);
    }
    else{
        enter_recursively(&(*nod)->left, word);
    }

【讨论】:

  • 我在一个链表问题中使用了 NOD *nod,并且很好地返回了指针。有什么不同?你能解释一下为什么双指针会更好吗?
  • 哦,伙计……如果这是为 BST 创建节点的最简单形式……那就相当复杂了。有谁知道制作简单 BSTree 的更简单方法?
猜你喜欢
  • 1970-01-01
  • 2017-10-13
  • 2015-06-16
  • 1970-01-01
  • 2012-02-22
  • 1970-01-01
  • 1970-01-01
  • 2022-06-11
  • 1970-01-01
相关资源
最近更新 更多