《编写高质量代码:改善Objective-C程序的61个建议》——建议9:高度警惕空指针和野指针的袭击

简介:

本节书摘来自华章出版社《编写高质量代码:改善Objective-C程序的61个建议》一 书中的第2章,作者:刘一道,更多章节内容可以访问云栖社区“华章计算机”公众号查看。

建议9:高度警惕空指针和野指针的袭击

在Objective-C中,利用指针写代码,特别对于指针掌握不熟练的人,经常会遭遇到空指针和野指针的困扰,造成应用出现一些莫名其妙的崩溃。因此,有必要在写Objective-C代码时,高度警惕空指针和野指针的袭击。
兵法上讲究“知己知彼,百战不殆”,那么就从什么是空指针和野指针来入手,认识这两个经常搞袭击的常客。

  1. 认识空指针和野指针
    没有存储任何内存地址的指针就称为空指针(NULL指针)。空指针就是被赋值为0的指针,在没有被具体初始化之前,其值为0。也就是说,一个指针变量分配一个NULL值的情况下,没有确切的地址被分配。

下面两个都是空指针:

Student *s1 = NULL;
Student *s2 = nil;

NULL指针是一个常数与几个标准库中定义的一个零值。考虑下面的程序:

#import <Foundation/Foundation.h>

int main ()
{
   int  *ptr = NULL;

   NSLog(@"The value of ptr is : %x\n", ptr  );
 
   return 0;
}

上面的代码编译和执行时,它会产生以下结果:

2013-09-13 03:21:19.447 demo[28027] The value of ptr is : 0

大部分的作业系统程序不允许被保留,因为该内存由操作系统来访问内存地址0处。然而,存储器地址0具有特殊的意义,它的信号指针不指向一个可访问的存储器位置。但是,按照惯例,如果一个指针包含空值(零),它被假定为指向什么。
要检查空指针,可以使用一个if语句,具体如下:

if(ptr)     /* succeeds if p is not null */
if(!ptr)    /* succeeds if p is null */

野指针不是NULL指针,而是指向“垃圾”内存(不可用内存)的指针。野指针是非常危险的。

  1. 空指针和野指针的区别及防御策略
    接下来用一个简单的例子对比一下野指针和空指针的区别,同时,介绍如何防止空指针和野指针的产生。

(1)首先,打开Xcode的内存管理调试开关,它能帮助用户检测垃圾内存,如图2-1和图2-2所示。

adf598d5e49e5af14a9c9599c21c5a7430192911

(2)自定义Student类,在main函数中添加下列代码:

Student *stu = [[Student alloc] init];
[stu setAge:10];
[stu release];
[stu setAge:10];

运行程序,你会发现第7行报错了,是一个野指针错误,如图2-3所示。

9ee18e30d962b1c44aaff94172873ba6e6a94936

(3)接下来分析一下报错原因。
① 执行完第1行代码后,内存中有个指针变量stu,指向了Student对象。

Student *stu = [[Student alloc] init];

假设Student对象的地址为0xff43,指针变量stu的地址为0xee45,stu中存储的是Student对象的地址0xff43,即指针变量stu指向了这个Student对象,如图2-4所示。

9f5f529685e04ac30c59cf8d628e0b310b32d1bb

②接下来是第3行代码:

[stu setAge:10];

这行代码的意思是:给stu所指向的Student对象发送一条setAge:消息,即调用这个Student对象的setAge:方法。目前来说,这个Student对象仍存在于内存中,所以这句代码没有任何问题。
③接下来是第5行代码:

[stu release];

这行代码的意思是:给stu指向的Student对象发送一条release消息。在这里,Student对象接收到release消息后,会马上被销毁,所占用的内存会被回收。
Student对象被销毁了,地址为0xff43的内存就变成了“垃圾内存”,然而,指针变量stu仍然指向这一块内存,如图2-5所示,这时stu就成为野指针。

7cf1821f14b26c5c3747890f48682958d6b33a74

④最后执行了第7行代码:

[stu setAge:10];

这句代码的意思仍然是:给stu所指向的Student对象发送一条setAge:消息。但是在执行完第5行代码后,Student对象已经被销毁了,它所占用的内存已经是垃圾内存,如果你还去访问这一块内存,那就会报野指针错误。这块内存已经不可用了,也不属于你了,你还去访问它,肯定是不合法的。所以,这行代码报错了!
(4)如果改动一下代码,就不会报错了,如下所示:

Student *stu = [[Student alloc] init];
[stu setAge:10];
 [stu release];

stu = nil;
 [stu setAge:10];

注意第7行代码,stu变成了空指针,stu就不再指向任何内存了,如图2-6所示。因为stu是个空指针,没有指向任何对象,因此第9行的setAge:消息是发不出去的,不会造成任何影响。当然,肯定也不会报错。

866006067c8016d232986f6d948367d9004c65af

 要点
(1)空指针(NULL指针),是指没有存储任何内存地址的指针。野指针,是指向“垃圾内存”(不可用内存)的指针。
(2)利用野指针发消息是很危险的,会报错。也就是说,如果一个对象已经被回收了,就不要再去操作它,不要再尝试给它发消息。
(3)利用空指针发消息是没有任何问题的,也就是说代码是没有错误的。

相关文章
|
7月前
|
C++
野指针与空指针:深入解析与防范策略
野指针与空指针:深入解析与防范策略
|
7月前
空指针和野指针的区别和定义
空指针和野指针的区别和定义
141 0
|
7月前
|
安全 算法 程序员
【C++智能指针 空指针判断】深入探索C++智能指针:nullptr与empty的微妙差异
【C++智能指针 空指针判断】深入探索C++智能指针:nullptr与empty的微妙差异
183 1
|
7月前
|
C++
C++野指针 空指针 危险指针
C++野指针 空指针 危险指针
105 3
|
Java Go Windows
Go-指针类型详解(空指针、指针的指针、函数形参指针等)
Go-指针类型详解(空指针、指针的指针、函数形参指针等)
140 0
Go-指针类型详解(空指针、指针的指针、函数形参指针等)
|
编译器 C语言 C++
C语言 野指针和空指针
C语言 野指针和空指针
333 1
C语言 野指针和空指针
指针(三)- 二级指针、野指针、空指针
指针(三)- 二级指针、野指针、空指针
216 0
|
C++
C++中野指针和空指针和无类型指针
一. 野指针 所谓的野指针指的是一个指针变量指向了不可使用的内存空间。 产生野指针三个原因: (1)指针变量创建时候没有被初始化:任何指针变量在创建的时候,不会自动成为NULL指针,它的默认值是随机的,因此该指针就会成为一个野指针,可能指向一块不可使用的内存空间。
1306 0
|
前端开发 Java
被同事的空指针硬生生的折磨了好久,终于学会了如何处理空指针
阿粉入职这么久了,无论如何也不会想到会被自己同事写的一个接口返回的空指针异常折磨致死,折磨的死去活来,却完全不知道是什么原因,你有没有过这种经历呢?
被同事的空指针硬生生的折磨了好久,终于学会了如何处理空指针