1free()函数
问:下面的程序会在用户输入'freeze'的时候出问题,而'zebra'则不会,为什么?
答:这里的问题在于,代码会(通过增加“ptr”)修改while循环里“ptr”存储的地址。当输入“zebra”时,while循环会在执行前被终止,因此传给free()的变量就是传给malloc()的地址,即最初分配给str的地址。但在“freeze”时,“ptr”存储的地址会在while循环里被修改,因此导致传给free()的地址出错,申请的内存前面一部分就没有释放,因为str++,让释放地址时不是从最初申请的那个地址开始释放的,也就导致了seg-fault或者崩溃。
2.问:修改代码片段(或者只读代码)
问:下面的代码段有错,你能指出来吗?
答:这是因为,通过*ptr = ‘T’,会改变内存中代码段(只读代码)“Linux”的第一个字母。这个操作是无效的,因此会造成seg-fault或者崩溃。
试了一下,确实会出错,但是还是不是很理解,为什么像 *str++=*ptr++这种又是正确的了?
3、输出是什么结果,还有(int&)a 与 (int)&a 有什么区别
#include <iostream>
using namespace std;
void main()
{
float a = 1.0f;
cout < < &a < < endl;
cout < < (int)&a < < endl;
cout < < (int&)a < < endl;
cout < < boolalpha < < ( (int)a == (int&)a ) < < endl; // 输出什么?
float b = 0.0f;
cout < < (int)b < < endl;
cout < < (int&)b < < endl;
cout < < boolalpha < < ( (int)b == (int&)b ) < < endl; // 输出什么?
}
解答:cout < < boolalpha < < ( (int)a == (int&)a ) < < endl; // 输出0;
/*(int&)a:将a的引用强制转换为整型,意思是a所在的内存,本来定义的时候为float类型,并初始为1.0f,但现在我要按int类型解释这段内存。1.0f 在内存中的存储为 0 011 1111 1 000 0000 0000 0000 0000 0000.把他按整型数解释为2^29+2^28+2^27+2^26+2^25+2^24+2^23=1065353216 */
cout < < boolalpha < < ( (int)b == (int&)b ) < < endl; // 输出1;
0.0 在内存中的的存储形式
0000 0000 0000 0000 0000 0000 0000 0000
(int&)a 把a强制转换成整形引用类型 ,
(int)&a 把a的地址强制转换成整型 。
那为什么(int)a=1呢,因为这个强制转化不是转化float在内存的存储方式,而是转化的a的值。
还要注意的是
用 #include <iostream>
要加 using namespace std;
用iostream.h下面 ,就不用加 using namespace std;
国际标准化
推荐的是:
#include <iostream>
using namespace std;
不加.h的是现在C++中规定的标准,目的在于使C++代码用于移植和混合嵌入时不受扩展名.h的限制,避免因为.h而造成的额外的处理和修改
而加.h的是c语言的用法,但是在c++中也支持这种用法,主要是为了向下兼容c 的内容,我们平时尽量不用这种方法 iostream是现在C++中规定的标准,目的在于使C++代码用于移植和混合嵌入时不受扩展名.h的限制,避免因为.h而造成的额外的处理和修改。iostream包含的基本功能和对应的旧头文件相同,但头文件的内容在名字空间std中。(在标准化的过程中,库中有些部分的细节被修改了,所以旧头文件和新头文件中的实体不一定完全对应。) 一般情况下应该用这个头文件,而iostream.h则是老式的,以后有可能被淘汰。
5、
下列代码的运行结果是什么?
int *ptr;
ptr=(int *)0x8000;
*ptr=3;
解答:指针问题,首先将指针ptr指向一个指定的地址,即对一个未作声明的地址直接进行访问,所以访问出错。这块地址可能已经被用,或者被其他程序占用等,因此会导致错误。
int *ptr;
*ptr=3;
这样也会导致错误,因为ptr没有分配一个合法的地址,在定义的时候,系统随机分配了一个地址给ptr,而这个地址可能是不合法的,已经被占用了的,所以会导致出错,如果 int a;ptr=&a;加这两句就不会出错。
6、
有了malloc/free为什么还要new/delete ?
malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。
对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。
因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。
我们先看一看malloc/free和new/delete如何实现对象的动态内存管理,见示例7-8。
class Obj { public : Obj(void){ cout << “Initialization” << endl; } ~Obj(void){ cout << “Destroy” << endl; } void Initialize(void){ cout << “Initialization” << endl; } void Destroy(void){ cout << “Destroy” << endl; } }; |
void UseMallocFree(void) { Obj *a = (obj *)malloc(sizeof(obj)); // 申请动态内存 a->Initialize(); // 初始化 //… a->Destroy(); // 清除工作 free(a); // 释放内存 } |
void UseNewDelete(void) { Obj *a = new Obj; // 申请动态内存并且初始化 //… delete a; // 清除并且释放内存 } |
示例7-8 用malloc/free和new/delete如何实现对象的动态内存管理
类Obj的函数Initialize模拟了构造函数的功能,函数Destroy模拟了析构函数的功能。函数UseMallocFree中,由于malloc/free不能执行构造函数与析构函数,必须调用成员函数Initialize和Destroy来完成初始化与清除工作。函数UseNewDelete则简单得多。
所以我们不要企图用malloc/free来完成动态对象的内存管理,应该用new/delete。由于内部数据类型的“对象”没有构造与析构的过程,对它们而言malloc/free和new/delete是等价的。
既然new/delete的功能完全覆盖了malloc/free,为什么C++不把malloc/free淘汰出局呢?这是因为C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存。
如果用free释放“new创建的动态对象”,那么该对象因无法执行析构函数而可能导致程序出错。如果用delete释放“malloc申请的动态内存”,理论上讲程序不会出错,但是该程序的可读性很差。所以new/delete必须配对使用,malloc/free也一样。