递归是怎么美好的引发堆内存非法访问的(二叉树)

前言:

计算机其实很笨,但它却总能欺骗自以为很聪明的人类;如果它的愚笨被聪明的人利用,你能想象会发生什么吗?

1.递归实现二叉树正常情况:

二叉树数据结构及算法声明 

//
//  T-Tree.hpp
//  T-Tree
//
//  Created by 韩立国 on 2021/10/29.
//

#ifndef T_Tree_hpp
#define T_Tree_hpp

#include <stdio.h>

struct T_struct
{
    float Date;
    T_struct *Left_T;
    T_struct *Right_T;
    int n;   
};

extern void Create_T_Tree(T_struct * &T_struct_Root,unsigned int m);
extern void Front_Search(T_struct *T_struct_Root);
extern void Back_Search(T_struct *T_struct_Root);
extern void Midll_Search(T_struct *T_struct_Root);
//extern bool Insert(int *Root_Node,int Who,int Where);
//extern bool Delete(int *Root_Node,int Who,int Where);
#endif /* T_Tree_hpp */

二叉树算法实现

//
//  T-Tree.cpp
//  T-Tree
//
//  Created by 韩立国 on 2021/10/29.
//

#include "T-Tree.hpp"
#include <stdlib.h>
#include <iostream>
//#include <malloc.h>
using namespace std;

//T_struct *T_struct_Root;
//T_struct *Root_Node=&T_struct_Root;

/*
 建立二叉树
 */
unsigned int m;
void Create_T_Tree(T_struct* &T_struct_Root,unsigned int m)
{
    std::cout<<"I WILL CREATE A TREE,ARE U READY?\n";
    std::cout<<"please put in a VALue   :"<<m<<"LEVEL\n";

    if(m<3)
    {
        //while(m>0)
        //{
        m++;
        //T_struct_Root=(T_struct*)malloc(sizeof(T_struct));
        T_struct_Root=new T_struct;
        cin>>T_struct_Root->Date;
        T_struct_Root->Left_T=NULL;
        T_struct_Root->Right_T=NULL;
        T_struct_Root->n=m;
        Create_T_Tree(T_struct_Root->Left_T,m);
        Create_T_Tree(T_struct_Root->Right_T,m);
        //}
        m--;
    }
    else
    {
        cout<<"OK!\n";
        //T_struct_Root=NULL;
        //return; //T_struct_Root->Date;
    }
}
/*
 中序遍历搜索
 */
void Front_Search(T_struct * T_struct_Root)
{
    if(T_struct_Root==NULL/*||T_struct_Root->Left_T==NULL||T_struct_Root->Right_T==NULL*/)
    {
        cout<<"BOttom is\n";
        //return;
    }else
    {
    
    Front_Search(T_struct_Root->Left_T);
    cout<<"Date is   :"<<T_struct_Root->Date<<"    I aM Level :   "<<T_struct_Root->n<<"\n";
    Front_Search(T_struct_Root->Right_T);


    }
}

测试用例 

//
//  main.cpp
//  T-Tree
//
//  Created by 韩立国 on 2021/10/29.
//

#include <iostream>
#include "T-Tree.hpp"
//#include <stdlib.h>
//#include <malloc.h>
using namespace std;
T_struct *T_struct_Root={0};

int main(int argc, const char * argv[]) {

    Create_T_Tree(T_struct_Root,0);
    std::cout << "T_struct_Root is    :"<<T_struct_Root<<"\n";
    Front_Search(T_struct_Root);
    //std::cout << "Hello, World!\n";
    return 0;
}

测试结果:

I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :0LEVEL
1
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :1LEVEL
2
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :2LEVEL
3
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :3LEVEL
OK!
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :3LEVEL
OK!
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :2LEVEL
4
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :3LEVEL
OK!
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :3LEVEL
OK!
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :1LEVEL
5
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :2LEVEL
6
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :3LEVEL
OK!
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :3LEVEL
OK!
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :2LEVEL
7
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :3LEVEL
OK!
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :3LEVEL
OK!
T_struct_Root is    :0x1007063d0
BOttom is
Date is   :3    I aM Level :   3
BOttom is
Date is   :2    I aM Level :   2
BOttom is
Date is   :4    I aM Level :   3
BOttom is
Date is   :1    I aM Level :   1
BOttom is
Date is   :6    I aM Level :   3
BOttom is
Date is   :5    I aM Level :   2
BOttom is
Date is   :7    I aM Level :   3
BOttom is
Program ended with exit code: 0

2.对二叉树内部变量不初始化,引发访问异常

32    T_struct_Root=new T_struct;
33    cin>>T_struct_Root->Date;
34    //T_struct_Root->Left_T=NULL;    //指针无初始化
35    //T_struct_Root->Right_T=NULL;   //指针无初始化

测试结果

T_struct_Root is    :0x10071fd20
BOttom is
Date is   :3    I aM Level :   3
(lldb) 

在访问第3层,Date 3之后发生异常退出。

看下栈数据:

T_struct_Root	T_struct *	0x10071fd20	0x000000010071fd20
Date	float	1
Left_T	T_struct *	0x10113cde0	0x000000010113cde0
Date	float	2
Left_T	T_struct *	0x10071fd40	0x000000010071fd40
Date	float	3
Left_T	T_struct *	NULL	0x0000000000000000
Right_T	T_struct *	0x7ff8058b0012	0x00007ff8058b0012  //异常地址
n	int	3
Right_T	T_struct *	0x10113ce00	0x000000010113ce00
n	int	2
Right_T	T_struct *	0x101006420	0x0000000101006420
Date	float	5
Left_T	T_struct *	0x101008190	0x0000000101008190
Right_T	T_struct *	0x101236210	0x0000000101236210
Date	float	7
Left_T	T_struct *	NULL	0x0000000000000000
Right_T	T_struct *	0x10	0x0000000000000010
n	int	3
n	int	2
n	int	1

此时T_struct_Root->Right_T指向了违法地址,引发异常,所以Front_Search( )退出了。

Right_T	T_struct *	0x7ff8058b0012	0x00007ff8058b0012
Date	float	2.59967951E+28
Left_T	T_struct *	0x6e9c0017a00fffee
Right_T	T_struct *	0xa022ffee27890023
n	int	1854930967
n	int	3

那么这块数据是怎么来的呢?

为了更好的跟踪Create_T_Tree(T_struct_Root,0)函数的执行,对源代码稍作调整

unsigned int m;
void Create_T_Tree(T_struct* &T_struct_Root,unsigned int m)
{
    std::cout<<"I WILL CREATE A TREE,ARE U READY?\n";
    std::cout<<"please put in a VALue   :"<<m<<"LEVEL\n";

    if(m<3)
    {
        //while(m>0)
        //{
        m++;
        T_struct_Root=(T_struct*)malloc(sizeof(T_struct));
        //T_struct_Root=new T_struct;
        cin>>T_struct_Root->Date;
        //T_struct_Root->Left_T=NULL;    //指针无初始化
        //T_struct_Root->Right_T=NULL;   //指针无初始化
        cout<<"T_struct_Root->Left_T   is:"<<T_struct_Root->Left_T<<"\n";
        cout<<"T_struct_Root->Right_T   is:"<<T_struct_Root->Right_T<<"\n";
        T_struct_Root->n=m;
        Create_T_Tree(T_struct_Root->Left_T,m);
        Create_T_Tree(T_struct_Root->Right_T,m);
        //}
        m--;
    }
    else
    {
        cout<<"OK!\n";
        //T_struct_Root=NULL;
        //return; //T_struct_Root->Date;
    }
}

让每一次Create_T_Tree(T_struct* &T_struct_Root,unsigned int m)都输出内存块被放Date后T_struct_Root->Left_T、T_struct_Root->Right_T究竟有什么,执行后会看到,奇妙的事情被发现了:

I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :0LEVEL
1
T_struct_Root->Left_T   is:0x10
T_struct_Root->Right_T   is:0x0
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :1LEVEL
2
T_struct_Root->Left_T   is:0xa000000010070002
T_struct_Root->Right_T   is:0x4000000010070536
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :2LEVEL
3
T_struct_Root->Left_T   is:0x0
T_struct_Root->Right_T   is:0x7ff8058b162d
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :3LEVEL
OK!
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :3LEVEL
OK!
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :2LEVEL
4
T_struct_Root->Left_T   is:0x7ff90671000a
T_struct_Root->Right_T   is:0x0
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :3LEVEL
OK!
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :3LEVEL
OK!
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :1LEVEL
5
T_struct_Root->Left_T   is:0x7ff906710008
T_struct_Root->Right_T   is:0x0
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :2LEVEL
6
T_struct_Root->Left_T   is:0xe
T_struct_Root->Right_T   is:0x0
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :3LEVEL
OK!
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :3LEVEL
OK!
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :2LEVEL
7
T_struct_Root->Left_T   is:0x0
T_struct_Root->Right_T   is:0x0
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :3LEVEL
OK!
I WILL CREATE A TREE,ARE U READY?
please put in a VALue   :3LEVEL
OK!
T_struct_Root is    :0x10112f940
BOttom is
Date is   :3    I aM Level :   3

在Date=2被放置后,T_struct_Root->Left_T   is:0xa000000010070002、T_struct_Root->Right_T   is:0x4000000010070536,可见这个指针数据是原先堆内存被使用后残留的数据,而又没有初始化对其归零,所以导致残留数据被用作指针,原本没有数据的指针指向了未知区域;而这个指针是在下一步递归中使用到的,被用作参数压栈,并被用作变量被写入下一次申请内存的地址,从而导致程序失控。这会导致严重的堆内存写入错误,如果存在函数对其读数据,则会造成非法地址访问Front_Search(T_struct * T_struct_Root)抛出异常就是这样导致的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值