我们都知道指针C/C++的一大特色,但其实指针并不是C/C++独有的,像C#和java等其实也是有指针的,只不过都被语言本身用其他的方式替代和封装了一般程序员接触不到,C/C++就不一样,它是直接将指针暴露给开发者,因为大部分牵涉到指针的都与内存有关,而计算机内存很重要,万一出什么问题可能系统都会崩溃,下面我们就简单来看一下程序在运行时指针与内存之间到底是个什么样的关系:
先看一段代码:
#include #include #include #include using namespace std;class people{public:people();~people();string Name ;int age ;bool sex ;char info[1024] ;void run(){}void eat(){}private:};people::people(){}people::~people(){}int main(){people* p1 = new people();cout<
直接运行看结果:
分析
接下来来一一进行分析:
首先people* p1 = new people();这一句是类的一个实例化,系统会给people实例化一个对象*p并且给它在堆上开辟空间,注意是在堆上,开辟的空间用来存储对象的数据。数据包括哪些?就是对象的属性和虚函数指针,但是函数并不存储在各对象中。因此run()和eat()方法是不存在对象*p指向的内存处的。
cout<
cout<
cout<
cout<
通过这两个我们就更清晰的认识到了,p1本身只占用4个字节的空间,而他所指向的对象的地址所占的空间就很大,等于类中所有数据类型所占空间之和。
接下来我们在main函数里写一点逻辑:
图解
我们来看一下程序运行时间,指针和内存是怎么工作的。我画一个图给大家:
程序在运行时,数据主要是存储在栈、堆、代码区、全局区。代码区主要就是存代码中出现的一些字符常量、方法等,比如这里代码中给对象的Name属性赋的值“xiaoli”之类的都是存在此处,然后我们通过new出来的对象,都是由堆通过计算好类中各属性所需空间然后开辟出来的。这里p3不是通过new开辟出来的,所以他是存在栈上的并且地址是固定的,是不能更改的,而p1和p2是能更改的。
改变地址
如此,我们三个对象互相赋值后会发生什么呢?
对比代码和输出结果我们发现了什么?赋值后p1和p2本身的地址并无改变,但是他所指向的内存都编程p3所在的内存了。下面用图解给大家看一下:
注意,此处原来的p1和p2指向的内存由于是new出来的我们需要手动释放它。所以我们在重新赋值之前要将这两块内存删除掉delete p2 ;delete p1;
改变地址的值
如果我将代码中的 p2 = &p3;换成*p2=p3呢?我们看下输出结果:
造成这种情况的原因,其实这就牵涉到指针的两种赋值问题:一种是改变指向的地址,一种是改变本身指向地址的值p2 = &p3是改变指向地址,*p2=p3是改变指向地址的值。
完整测试代码
下面给大家贴上完整的代码吧:
#include #include #include #include using namespace std;class people{public:people();~people();string Name ;int age ;bool sex ;char info[1024] ; void run(){}void eat(){}private:};people::people(){}people::~people(){}int main(){people* p1 = new people();people* p2 = new people();cout<Name = "xiaoli" ;p1->run();p2->Name = "xiaohua";p2->run();people p3 ;p3.Name = "xiaoming"; p3.run();cout<Name<Name<