VC++ 内存机理的个人理解(一)——地址和指针的关系
内存的概念就不赘述了,在此主要叙述一下VC++中指针,地址,堆,栈的个人理解,如果有错请不吝指出。
地址是什么?
地址是一个变量在内存中的“门牌号码”,要得知一个变量的值,只要根据变量的地址就能得到这个地址中到底住的是什么人(这个变量的值到底是什么)。
对于值类型的变量来说,一个地址就能对应一个变量了。但是对于大小超过一个内存块的引用类型,当这个引用类型在一个地址对应的内存块中放不下,这个引用类型的地址就是它的多个内存块的首地址,程序可以通过这个首地址得到一整块内存,也就得到了这个对象。
其中涉及了对象的内存分配原则,关于这个请参见其它内容。在本文中,主要记住,地址就是变量的首地址。
比如我们如下代码:
它们的值都是0,但是它们的地址&a和&b是不一样的,输出结果如下:
Address Of a Is:0012FE58
Address Of b Is:0012FE4C
指针是什么?
指针也是一种变量,我们可以理解为指针就是专门记录地址的值类型。因为我们可以通过首地址得到变量,所以一个变量不管多大,需要多少内存,只需要一个指针就能指向它了。
因为指针也是变量,所以指针是有自己的地址的(没有地址,指针记录的目标的地址存在哪儿呢?对吧),比如我们接着看如下的代码
我们为指针p1赋值是变量a的地址,所以p1的值就是&a。
我们为p2赋的值是在栈内存中开辟的一个新的数字0的地址。为什么不用&0?这是编译器的要求,虽然理解上容易了很多,但是每次这样写岂不是很累人?在大家都知道的情况下,我们就不要用这么麻烦的写法了。
为什么还要给p3也赋上0的地址?这是为了证明这个0不是只有一个,虽然看起来都是0,但是p2指向的0不是p3指向的0。看结果,大家就明白了。
Address Of p1 Is:0012FE40
Address Stores In p1 Is:0012FE58
Address Of p2 Is:0012FE34
Address Of p3 Is:0012FE28
这个结果说明指针是有自己的地址的,同时,指针记录的值就是它所指向的变量的地址,比较一下一开始的代码中变量a的地址“&a”和现在p1的值,都是:0012FE58,说明我们只要通过p1就能找到a,就能找到a变量内存块中的值了。
再深究一下指针如何?
因为指针也是一个变量,所以,我们当然可以做一些很匪夷所思的事情,比如:用一个指针指向一个指针!请看下面的代码。
小凡一开始学C++看到这个代码的时候差点就要骂街了,这是什么东西啊。其实就是一个指针的指针,pp就是Pointer to Pointer的缩写,呵呵。在pp中记录的是p1的地址,同时pp也有自己的内存地址。看看结果是不是像我们想的一样?
Address Of pp Is:0012FE1C
Address Of p1 Is:0012FE40
Address Stores In p1 Is:0012FE58
pp的内存地址是全新的,这是废话,因为pp是一个新的变量,当然需要一个新的内存块来存储它的值。同时pp的值就是p1的地址,上面我们已经用&p1来输出验证了。同时,我们用*pp来获得了p1中的值。
*符号就是解引用符,说白了,就是找到[内存地址=变量中的值]的那个内存块中的值。所以我们的*pp就是:根据pp中存储的p1的地址找到了p1,并且输出了p1内存块中的值,也就是变量a的地址&a。
有点绕人不是吗?其实只要记住简单的一点:地址是自动分配的,不能人为改变;指针是记录地址用的,我们可以用过解引用符*通过指针记录的地址来获取这个首地址记录的变量。就这么简单。