EasyC++16,指针初探之二

开发 后端
指针由于能够操作内存,所以如果使用的时候不够仔细,很容易引发一些意想不到的错误。

[[431850]]

大家好,我是梁唐。

想要追求更好阅读体验的同学,可以点击文末的「阅读原文」,访问github仓库。

危险的case

指针由于能够操作内存,所以如果使用的时候不够仔细,很容易引发一些意想不到的错误。

C++ Primer当中给了这样一个例子:

  1. int *ptr; 
  2. *ptr = 2333; 

在这段代码当中我们声明了一个int型的指针,并且将它指向了2333。然而,这里有一个问题,我们在声明指针的时候并没有进行初始化。没有初始化的指针并不为空,而是指向一个未知的地方。如果说它指向的是一个常量1200的地址,我们让它等于2333,那么之后当我们使用1200这个常量的时候,得到的结果都是2333。

更可怕的是,整个过程非常地隐蔽,很难察觉。debug的时候会令人抓狂。

所以千万不要修改一个没有初始化的指针指向的值。

指针和数字

C++ Primer当中还给了另外一个例子,当我们输出指针的时候,得到的是一串十六进制的数。那我们能不能反过来将一个十六进制的数赋值给指针呢?

  1. int *p; 
  2. p = 0xB8000000; 

答案是不行,因为类型不一致。虽然我们打印指针的时候看起来得到是十六进制数,但它的类型其实是指针类型,而不是整数类型。所以我们将一个整数赋值给一个指针是不行的,如果非要赋值,必须要进行类型转换。

  1. int *p; 
  2. p = (int*) 0xB8000000; 

但是这一转换之后显然又出现了一个问题,我们知道0xB8000000这个地址指向哪里么?显然不知道,自然也就说不清改了这里的值之后会引发什么结果。

所以虽然这么做可行,但也强烈不建议这样干。

new操作

前文说过使用指针有一个非常大的好处就是可以在程序运行的时候,动态分配内存。其实在C语言当中也有类似的功能,可以使用malloc来分配内存。不过在C++当中有了更好用的运算符——new。

比如我们要动态创建一个int类型的变量,可以这样写:

  1. int *ptr = new int

new运算符根据之后的类型确定需要的内存大小,找到这样的内存之后,返回地址。刚好指针接收的值就是内存地址,因此刚好可以完成这样的赋值操作。

上面的代码也可以写成这样:

  1. int a; 
  2. int *ptr = &a; 

这两者有什么区别呢?表面上看没有区别,都是创建了一个int类型的变量。只不过第二种写法除了可以使用指针ptr之外,还可以使用变量名a来访问这个int。

但实际上这两者的内部实现完全不同,我们直接通过变量名创建的变量它的值会被存储在栈内存当中,而通过new创建的对象则被存储在堆内存当中。栈内存是由系统自动分配,而堆内存则是由程序员进行申请使用。这两者的内存模型是完全不同的,我们会在之后的文章详细地讨论这点。目前简单来理解的话,就是堆内存更加灵活,它的空间也更大,可以存储下更大的数据。

delete操作

有了动态创建,自然也就有动态删除,所以C++当中有一个delete操作和new相对应。

delete运算符可以在变量使用结束之后,将内存归还给内存池。因为很多时候程序当中的变量都是一次性使用或者是有生命周期的,当生命周期结束,使命完成就没有必要继续占用着资源了。毕竟系统内的内存资源是有限的,尤其是在一些大型项目或者嵌入式系统当中,内存资源非常紧张。

delete运算符之后跟一个指针,它会释放改指针指向的内存。

  1. int *ptr = new int
  2. delete ptr; 

这里面有很多坑,千万要当心。首先是使用了new创建了内存之后,一定要记得delete,否则这块内存将会永远被占用无法得到释放,这种情况被称为内存泄漏(memory leak)。另外,我们不能delete一个已经delete过的指针,这也会引发严重错误。C++ Primer对此的描述是:什么情况都可能发生。当然也不能再使用一个已经被delete的指针,这会引发空指针错误。

指针对于C++来说是一把双刃剑,像是Java、Python、Go等其他语言,内存回收的工作都是由系统自动执行的。例如Java的JVM虚拟机设计了严密的GC(垃圾回收)机制,程序员无须关心内存的回收问题,全部交给程序自动完成。

 

而在C++当中,这一过程是由程序员手动执行的,某种程度上来说,这当然非常好,程序员拥有了很高的权限以及灵活度。但同样也是一个坑,尤其是在复杂系统当中,很难准确判断delete执行的时间。这会引发严重的问题,例如内存泄漏严重,野指针到处飞等……

 

责任编辑:武晓燕 来源: Coder梁
相关推荐

2021-10-27 16:27:20

C++指针操控

2021-10-29 09:44:50

C++指针变量

2021-12-12 18:13:54

C++This指针

2021-10-26 00:19:51

C++结构体存储

2021-11-09 10:38:16

C++Const指针

2021-11-10 10:48:36

C++函数指针

2021-12-29 20:31:40

C++多态指针

2021-12-09 10:56:50

函数C++原型

2021-11-26 00:03:20

C++编译常量

2021-12-20 21:01:52

鸿蒙HarmonyOS应用

2021-12-08 10:43:09

C++实现

2021-12-30 14:58:58

C++函数动态

2021-12-10 10:45:36

C++函数Stock

2021-11-27 11:50:09

C++静态持续

2021-12-11 19:02:03

函数C++对象

2021-12-15 10:25:57

C++运算符重载

2022-01-04 16:35:42

C++Protected关键字

2021-12-05 18:20:42

C++空间特性

2021-10-26 15:36:17

C++枚举值类型

2022-03-04 15:43:36

文件管理模块Harmony鸿蒙
点赞
收藏

51CTO技术栈公众号