无奖问答:对int * ptr来说,ptr是什么,*ptr是什么?

指针,大家伙都非常熟悉,不论是在C语言还是C++中,它都扮演着十分重要的角色,这里我们来简单回顾一下。
指针是一种存储地址的变量,长度固定,通过&获得常规变量的地址,又通过*解引用出对应地址处存储的值。对于指针而言,地址是指定的量,而值则是被视作派生量。常见声明指针的方式类似于**int * ptr,**在这表达中,ptr是那个真正的指针,而*ptr可以被视为常规变量。
C++环境下,指针的定义并没有多少变化,但是对声明格式及其含义却有着不一样的看法。C语言中我们习惯写成int *ptr ,实际上是在强调*ptr是一个int类型的值这一事实。而C++中,我们也常见到int* ptr的写法,这更多在强调int*是一种特殊的类型------指向某一数据类型的指针。当然,这两种写法都没有问题,编译器都能通过。
不过,以上这些只是指针功能的冰山一角,看着花里胡哨,其实总结来说只是指针为这些已经有名称的内存空间取了别名,让程序员能够更方便地访问这些地址和里面的值,真正的重头戏还在后面。
我在这篇文章之前已经不止一次写过,OOP(面向对象编程)强调在运行阶段进行决策。就比如定义一个定长的数组,那么它的长度在编译阶段就已经决定好了,此为编译阶段决策,通常我们认为自己定义的长度已经足够满足程序的需要,但实际情况是时刻变化的,可能长度远远不够,也可能长度过长,前者导致安全问题,后者导致空间浪费。而OOP将决策推迟,使得程序更加灵活,更能应对实际执行过程中发生的各类情况。
为达到上述的决策情形,C++采用了new申请内存、delete释放内存以及指针跟踪内存位置的方法,这也引出了指针真正的奥义所在------**在运行阶段分配未命名内存,**下面我们来看用法:

要为一个int类型的值分配一段内存,首先就是使用new运算符。具体用法分两点:第一,new需要知道为哪种数据类型分配合适的空间,也就是在new后跟上类型;第二,需要有指针指向这个新开辟的内存空间,不然无法进行访问。
当有指针指向这未命名空间后,就像是为一栋封闭的房屋安上了一扇门,此时就可以通过类似常规变量赋值的方式将想要的值赋给指针,顺着指针这根线,将值存入新开辟的内存空间。
上图代码还只是小试牛刀,new在管理更大型的数据例如数组、结构等时才是真正发挥了最大功效,就以之前提到的数组为例,看如下代码:

可以看到,此时的数组长度是在程序正式运行时由程序员通过cin的输入亲自决定的,这个n想给多少全凭业务里需要多少。确定长度后如果要使用,可以大胆地把指针名当数组名,用类似数组的方式来访问内存中的值。这种创建方式在C++中称为动态联编。
有创建也就有释放,如果在运行过程中不需要这片内存或者空间不足需要释放一些内存时,可以使用delete进行释放,只需要使用类似delete ptr 的语句即可,不过面对动态数组时还需要在delete和指针之间加上[]写成delete [ ] ptr 的形式,告诉delete要释放的是一整个数组**。**
delete还有一些其他的使用注意事项,例如不要用delete释放已经释放过的空间,不能使用delete释放声明普通变量时分配的内存空间,就像下图代码这样:

C语言环境下是否也有类似的内存管理方法呢?有,例如之前文章提到的使用malloc函数等,但是C++提供的new和delete 更为简便。
伴随着指针的进阶,下面我们的另一位老朋友------函数也将迎来独属于它的深化时刻。