野指针

28:什么是野指针?
野指针是什么?有什么作用?
野指针不是NULL指针,是指向“垃圾”内存的指针。人们一般不会错用NULL指针,但是野指针是很难判断出,是很危险的,而且if语句对它不起作用。野指针的成员主要有两种:
1:指针变量没初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的默认值是随机的,所以指针变量在创建的同时应当初始化,要么将指针设置为NULL,要么指向合法的内存。
2:指针p被free或delete后,没有置为NULL。

 

29:代码分析查错

下面的程序有什么bug?

 1 #include "stdafx.h"
 2 using namespace std;
 3 
 4 int main()
 5 {
 6     short*bufptr;
 7     short bufarray[20];
 8     short var = 0x20;
 9     *bufptr = var;
10     bufarray[0] = var;
11     
12     return 0;
13     getchar();
14 }

第6行正确,声明了一个short*类型的指针,但没有对它进行初始化。

第7行正确,声明一个含有20个元素的数组。每个元素都是short类型。

第8行正确,声明short类型的变量var,并把它初始化为0x20。

第9行错误。因为bufptr没有被初始化,是个野指针,因此将bufptr指针指向的内容赋值为var变量的值就变得十分危险,会导致程序崩溃。为了杜绝这种错误,可以对bufptr进行初始化。将第6行修改为:

short*bufptr=(short *)malloc(sizeof(short));

代码10正确。把变量var值赋值给bufarray的第一个元素。

 

30:有了malloc和free,为什么还要new和delete

malloc与free和new与delete的区别

malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可以用于申请动态内存和释放内存。

对于非内部数据类型的对象而言,仅用malloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,因此不能把执行构造函数和析构函数的任务强加于malloc/free函数。

 

C++语言需要能完成动态内存分配和初始化工作的运算符,即new运算符,以及能完成清理和释放内存工作的运算符,即delete运算符。注意new/delete不是库函数。

 1 #include "stdafx.h"
 2 #include <iostream>
 3 using namespace std;
 4 
 5 class Obj
 6 {
 7 public:
 8     Obj(void)
 9     {
10         cout << "Initialization" << endl;
11     }
12     ~Obj(void)
13     {
14         cout << "Destroy" << endl;
15     }
16 };
17 
18 void UseMallocFree(void)
19 {
20     cout << "in UseMallocFree()..." << endl;
21     Obj*a = (Obj*)malloc(sizeof(Obj));
22     free(a);
23 }
24 
25 void UseNewDelete(void)
26 {
27     cout << "in UseNewDelete()..." << endl;
28     Obj*a = new Obj;
29     delete a;
30 }
31 
32 
33 int main()
34 {
35     UseMallocFree();
36     UseNewDelete();
37     getchar();
38     return 0;
39 }

对于非内部数据类型的对象而言,对象在消亡之前要自动执行析构函数。由于malloc/free函数是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加在malloc/free函数之上,因此只能使用new/delete运算符

 

31:程序改错--指针的初始化

 野指针必须初始化为NULL

 1 #include "stdafx.h"
 2 #include <stdio.h>
 3 #include <malloc.h>
 4 
 5 
 6 struct Tag_Node
 7 {
 8     struct Tag_Node* left;
 9     struct Tag_Node* right;
10     int value;
11 };
12 
13 typedef struct Tag_Node TNode;
14 
15 TNode* root = NULL;
16 
17 void append(int N);
18 
19 
20 int main()
21 {
22     append(63);
23     append(45);
24     append(32);
25     append(77);
26     append(96);
27     append(21);
28     append(17);
29     
30     return 0;
31 }
32 
33 void append(int N)
34 {
35     TNode* NewNode = (TNode*)malloc(sizeof(TNode));
36     NewNode->value = N;
37     
38     if (root==NULL)
39     {
40         root = NewNode;
41         return;
42     }
43     else
44     {
45         TNode* temp;
46         temp = root;
47         while ((N>=temp->value&&temp->left!=NULL)||
48             (N<temp->value&&temp->right!=NULL))
49         {
50             while (N>=temp->value&&temp->left!=NULL)
51                 temp = temp->left;
52                 while (N < temp->value&&temp->right!=NULL)
53                     temp = temp->right;
54 
55         }
56         if (N>=temp->value)
57         {
58             temp->left = NewNode;
59         }
60         else
61 
62             temp->right = NewNode;
63             return;
64     }
65 }

TNode是结构体类型,它有left和right两个成员指针,分别代表链接左右两个元素,value成员表示元素节点的数据。在append函数中,数据从左到右按降序排列。因此在代码第47,48,50行中使用while循坏来查找合适的位置。在这4行都采用temp的指针left或指针right与NULL进行判断,然而对堆中分配的内存只做成员value的初始化(代码36行),没有把left和right初始化为NULL,因此指针left和指针right与NULL进行判断不起作用。从而程序会对野指针指向的地址进行赋值,从而导致程序崩溃。

改进后的代码:

 1 #include <stdio.h>
 2 #include <malloc.h>
 3 
 4 
 5 struct Tag_Node
 6 {
 7     struct Tag_Node* left;
 8     struct Tag_Node* right;
 9     int value;
10 };
11 
12 typedef struct Tag_Node TNode;
13 
14 TNode* root = NULL;
15 
16 void append(int N);
17 void print();
18 
19 
20 int main()
21 {
22     append(63);
23     append(45);
24     append(32);
25     append(77);
26     append(96);
27     append(21);
28     append(17);
29     printf("head:%d\n", root->value);
30     print(); //打印链表所有元素
31 
32 }
33 
34 void append(int N)
35 {
36     TNode* NewNode = (TNode*)malloc(sizeof(TNode));
37     NewNode->value = N;
38     NewNode->left = NULL;   //初始化left
39     NewNode->right = NULL;   //初始化right
40 
41     
42     if (root==NULL)
43     {
44         root = NewNode;
45         return;
46     }
47     else
48     {
49         TNode* temp;
50         temp = root;
51         while ((N>=temp->value&&temp->left!=NULL)||
52             (N<temp->value&&temp->right!=NULL))
53         {
54             while (N>=temp->value&&temp->left!=NULL)
55                 temp = temp->left;
56                 while (N < temp->value&&temp->right!=NULL)
57                     temp = temp->right;
58 
59         }
60         if (N>=temp->value)
61         {
62             temp->left = NewNode;
63             NewNode->right = temp;  //形成双向链表
64         }
65         else
66         {
67             temp->right = NewNode;
68             NewNode->left = temp;   //形成双向链表
69         }
70             
71             return;
72     }
73 }
74 
75 void print()
76 {
77     TNode* leftside = NULL;
78 
79     if (root=NULL)
80     {
81         printf("There is not any element");
82         return;
83     }
84     leftside = root->left;
85 
86     while (1)
87     {
88         if (leftside->left == NULL)
89         {
90             break;
91         }
92         leftside = leftside->left;
93     }
94     while (leftside!=NULL)
95     {
96         printf("%d", leftside->value);
97         leftside = leftside->right;
98     }
99 }

在代码38和39中添加了成员指针left和right的初始化。这样就杜绝了野指针的产生。在代码63和代码68的目的是为了使链表尾双向链表。这样在遍历链表时就比较方便。print函数从左到右打印链表中所有元素的value成员。执行结果:

head:63

96 77 63 45 32 21 17

可以看出,root节点是第一个插入到链接的节点,其数据值为63.链表按照从左到右降序排列

没有对新增加的节点成员指针left和right作初始化,它们都是野指针,在随后与NULL比较时不起判断的作用。最终由于对野指针指向的内存块赋值导致程序崩溃。

 

 

posted on 2016-03-09 17:20  h3iß3n  阅读(255)  评论(0)    收藏  举报

导航