指针和自由存储空间
1.声明和初始化指针
(1)指针只是一个变量,其存储的是值的地址,当指针加上解引用运算符()后才表示该地址上存储的值。指针所存储的值在一定程度上与取地址符&(如&home)所引用的变量地址是一样的。也就是说int *ptr ;ptr = home;那么ptr 存储的值就是变量home的地址,也就是&home。
(2)面向对象编程与传统的过程性编程的区别在于,OOP强调的是在运行阶段(不是编译阶段)进行决策。运行阶段指的是程序正在运行时,编译阶段指的是编译器将程序组合起来时。运行阶段提供了灵活性,可以根据当时的情况进行调整。例如,考虑为数组分配内存的情况,传统方法是声明一个数组。要在c++中声明数组,必须指定数组长度。因此数组长度在程序编译时就设定好了,这就是编译阶段决策。您可能认为,在80%的情况下,一个包含20个元素的数组足够了,但程序有时需要处理200个元素。为了安全起见,使用了一个包含200个元素的数组。这样,程序在大多数情况下都浪费了内存。OOP通过将这样的决策推迟到运行阶段进行,使程序更加灵活。在程序运行后,可以这次告诉它只需要20个元素,而还可以下次告诉它需要205个元素。而在c++中,使用关键字new请求正确数量的内存以及使用指针来跟踪新分配的内存位置。
2.指针的危险
警告!!!:一定要在对指针应用解除引用运算符(*)之前,将指针初始化为一个确定的,适当的地址。这是关于使用指针的金科玉律。如下就是错误示范:
```
long *fellow;
*fellow = 22333;
```·
fellow确实是一个指针,但它指向哪呢?上述代码并没有将地址赋给fellow。那么22333将被放在哪里呢?我们不知道。由于fellow没有初始化,它可能有任何值。不管值是什么,程序都将它解释为存储22333的地址。换句话说,你不给指针变量具体的值,那么编译器就会给它赋给任意值,即指针fellow可能指向任意一端内存空间。有可能时已经存了数据的内存空间,那么,你再用felloe指针给这段内存空间赋值,可能就会修改一些程序的关键数据。这就是它的危险性所在。
3.指针和数字
指针不是整形,虽然计算机通常把地址当作整数来处理。从概念上看,指针与整数是截然不同的类型。整数可以执行加减乘除等运算,而指针描述的是地址位置,将两个地址相乘没有任何意义。从可以对整数和指针执行的操作上看,它们也是彼此不同的。因此,不能简单地将整数赋给指针。
4.使用new来分配内存
对指针的工作方式有一定了解后,来看看它如何实现在程序运行时分配内存。前面我们我们将指针初始化变量的地址;变量是在编译时分配的有名称的内存,而指针只是为可以通过名称来直接访问的内存的一个别名。指针真正的用武之地在于,在运行阶段分配未命名的内存以存储值。在这种情况下只能通过指针来访问内存。在c语言中,可以用库函数malloc()来分配内存:在c++中仍然可以这样做,但c++还有更好的办法---new运算符。
总结的来讲,运算符new与malloc的区别在于
(1)从本质上来讲:malloc时c中的库函数,需要声明特定的头文件。而new是c++中的关键字(操作运算符),它本身不是函数,所以不依赖于头文件,c++编译器就可以把new编译成目标代码(还会根据参数类型插入相应的构造函数)
(2)从使用上来讲,如下几点不同:
#1.new和delete都是操作符,可以重载,只能在c++中使用。而malloc,free是函数,由于c++向下兼容c,因此malloc和free在c和c++中都可以使用。
#2.相对于malloc,new更加智能一些,new可以自动计算所需的字节大小。而malloc必须人为的计算所需的字节数
#3.内存分配成功的话,new会返回指定类型的指针,而malloc只能返回一个void指针,因此在返回后必须强行进行指针类型的转换。对于c++,如果写成:P = malloc(sizeof(int));程序会报错:“不能将void赋值给int 类型变量”。所以必须将void进行int的强行转换。而对于c,没有这个要求,但是为了使c程序更加方便的移植到c++中来,建议养成强制转换的习惯。
#4.分配内存失败的话,new会thow一个异常std::bad_alloc.而malloc会返回空指针。
#5.new可以调用对象的构造函数,对应的delete调用相应的析构函数。而malloc仅仅分配内存,free仅仅回收内存,并不执行构造函数,和析构函数。也就是说,用new进行动态内存分配,由于会调用构造函数,因此会对申请对象进行初始化。而malloc只管分配内存,并不能对所得内存进行初始化,所以得到的一片新内存中,其值将是随机的。
*(3)从效率上来讲(new/delete和malloc/free的效率比较)**
#1.new和delete的实现其实是调用了malloc/free库函数的
#2.不要企图用malloc/free来完成动态对象的内存管理,应该用new/delete,因为new/delete会自动调用构造析构函数。由于内部数据类型的对象没有析构于构造的过程,对他们而言,malloc/free和new/delete是等价的。
#3.既然new/delete的功能完全覆盖了malloc/free,为什么c++不将malloc/free管理动态内存淘汰出局呢?这是因为c++程序经常要调用c函数,而c程序只能用malloc/free管理动态内存。如果用free释放“new创建的动态对象”,那么该对象因无法执行析构函数而可能导致程序出错。如果用delete释放“malloc申请的动态内存”,理论上讲程序不会出错,但是该程序的可读性很差。所以,new/delete必须配对使用,malloc/free也一样。
5.使用delete释放内存
当需要内存时,可以使用new来请求,这只是c++内存管理数据包中有魅力的一个方面。另一个方面是delete运算符,它使得在使用完内存块后,会将内存块归还给内存池。使用delete时,后面要加上指向内存块的指针。这将释放指针指向的内存,而不会删除指针本身。一定要配对使用new和delete,否则将发生内存泄漏(memory leak),也就是说,被分配的内存再也无法使用了。这将导致程序不断寻找更多内存而终止。
6.使用new来创建动态数组
在c++中,创建动态数组很容易:只要将数组的元素类型和元素数目告诉new即可。必须在类型名后加上方括号,其中包含元素数目。例如,要创建一个包含10个int元素的数组,可以这样做:
int *psome = new int [10];
对于new创建的数组,应使用另一种格式的delete来释放
delete [] psome;
总之,使用new和delete时,应遵守一下规则:
#1.不要使用delete来释放不是new分配的内存。
#2.不要使用delete释放同一个内存块两次。
#3.如果使用new[]为数组分配内存,则应使用delete[]来释放。
#4.如果使用new[]为一个实体分配内存,则应使用delete(没有方括号)来释放。
#5.对空指针应用delete是安全的。