【问题标题】:Why does the value of a Pointer change after a print?为什么指针的值在打印后会发生变化?
【发布时间】:2022-01-24 20:27:52
【问题描述】:
#include <stdlib.h>
#include <stdio.h>
#include "sorted_tree.h"

int insert_value(int value, struct TreeNode *n) {
    if (value < n->value) {
        if (n->left_child == NULL) {
            struct TreeNode t = {0};
            struct TreeNode *tpointer = &t;
            tpointer->value = value;
            tpointer->left_child = NULL;
            tpointer->right_child = NULL;
            n->left_child = tpointer;
            printf("links eingefügt\n");
        } 
        else {
            insert_value(value, n->left_child);
        }

        return 0;
    }
    else if (value > n->value) {
        if (n->right_child == NULL) {
            struct TreeNode t = {0};
            struct TreeNode *tpointer = &t;
            tpointer->value = value;
            tpointer->left_child = NULL;
            tpointer->right_child = NULL;
            n->right_child = tpointer; 
            printf("rechts eingefügt\n");        
        }
        else {
            insert_value(value, n->right_child);
        }

        return 0;
    }
    else {
        return 1;
    }
}

void print_inorder(struct TreeNode *n) {
    if (n == NULL) {
        printf("r");
        return;
    }
    else {
        print_inorder(n->left_child);
        printf("%d ", n->value);
        print_inorder(n->right_child);
    }
}

int main() {
    struct TreeNode t = {0};
    struct TreeNode *tpointer = &t;
    tpointer->value = 5;
    tpointer->left_child = NULL;
    tpointer->right_child = NULL;
    insert_value(6, tpointer);
    printf("%d", tpointer->right_child->value);
    printf("%d", tpointer->right_child->value);
}

main 中的第一个 printf() 输出正确的“6”,但第二个输出一个随机数,好像地址已更改。 6 应该插入到右子节点中,所以我期望 66 作为输出。为什么会发生这种情况,我该如何解决?

【问题讨论】:

  • 寻求调试帮助的问题通常应包括问题的minimal reproducible example
  • n-&gt;right_child=tpointer; 不起作用,因为 struct TreeNode t={0}; 仅在 if 块内具有生命周期。保留对它的引用并在此之外使用它,这会导致未定义的行为。需要使用动态分配来制作这些节点。例如,struct TreeNode *tpointer = malloc(sizeof(*tpointer));
  • @AndreasWenzel:你为什么怀疑它?是 UB,但不是难以置信的 UB。
  • printf() 的调用会覆盖以前用于right_child 的堆栈内存。 @AndreasWenzel
  • @Barmar:啊,是的,你可能是对的。我已删除我的评论。

标签: c recursion struct binary-search-tree function-definition


【解决方案1】:
 struct TreeNode t={0};
 struct TreeNode *tpointer=&t;
 tpointer->value=value;

insert_valueif/else if 内的那些代码块不正确。这是因为struct TreeNode t={0}; 创建了一个自动变量,其生命周期仅在封闭范围内。在这种情况下,生命周期仅在 if/else if 块内。保留对变量的引用并在此之外使用它会导致未定义的行为。

解决方案是创建具有超出函数生命周期的变量。最常见的方法是使用动态分配的内存:

struct TreeNode *tpointer = malloc(sizeof(*tpointer));

当不再需要时,不要忘记free所有动态分配的内存。

【讨论】:

    【解决方案2】:

    当树的第一个节点没有像在你的程序中那样动态分配时的方法

    struct TreeNode t={0};
    struct TreeNode *tpointer=&t;
    tpointer->value=5;
    tpointer->left_child=NULL;
    tpointer->right_child=NULL;
    

    不好。事实上,您不能创建或使用空树。

    树中的所有节点都应在需要时动态分配。

    因此,函数insert_value 中的指针n 通常可以等于空树的NULL。你需要检查一下。否则这样的语句

    if(value<n->value){
    

    可以调用未定义的行为。

    同样在函数中,您正在设置指向 struct TreeNode 类型的本地对象的指针,例如

            struct TreeNode t={0};
            struct TreeNode *tpointer=&t;
    

    退出函数后,本地对象t 将不再存在。所以一个无效的指针会被添加到树中。

    你需要动态分配一个新节点。

    此外,该函数实际上返回任意数字 0 或 1,因为该函数不返回该函数后续递归调用的最终值。

    此外,在添加新节点的情况下返回 1,否则在逻辑上更一致。

    我会通过以下方式声明和定义函数

    int insert_value( struct TreeNode **n, int value )
    {
        if ( *n == NULL )
        {
            *n = malloc( sizeof( struct TreeNode ) );
            ( *n )->value = value;
            ( *n )->left_child  = NULL;
            ( *n )->right_child = NULL;
    
            return 1;
        }
        else if ( value < ( *n )->value )
        {
            return insert_value( &( *n )->left_child, value );
        }
        else if ( ( *n )->value < value )
        {
            return insert_value( &( *n )->right_child, value );
        }
        else
        {
            return 0;
        }
    }
    

    如果在 main 中你有一个指向根节点的指针,声明如下

    struct TreeNode *root = NULL;
    

    然后调用函数就像

    insert_value( &root, value );
    

    【讨论】:

      猜你喜欢
      • 2016-01-06
      • 1970-01-01
      • 2021-06-29
      • 2013-03-14
      • 2015-02-21
      • 2012-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多