// Listing 8.9 - Demonstrates a stray pointer typedef unsigned short int USHORT; #include <iostream> int main() { USHORT * pInt = new USHORT; // 声明第一个指针,分配了一块内存块(指针自身占用另一块内存块) *pInt = 10; // 使用指针并赋值,正确。short类型会把内存的值改成0A00,是2个字节,而不是4个字节。 std::cout << "*pInt: " << *pInt << std::endl; delete pInt; // 删除指针,正确。告诉编译器将使用该内存区域保存其它东西。 // 让编译器释放内存,但指针本身存在。它现在就是一个失控指针(野指针)。应该把它改成空指针 pInt=NULL; // 如果删除一个指针之后,又对它删除了一次,那么程序就是不确定的。任何情况都有可能发生。只有幸运的话,程序也许会崩溃。 // 如果删除一个空指针,什么事情也不会发生,这样非常安全。 long * pLong = new long; // 声明第二个指针,分配了一块内存块(指针自身占用另一块内存块) // 但是第一个指针的内存块被清除以后,第二个指针就可以使用那块内存块了(事实也是如此) *pLong = 90000; // 使用指针并赋值,正确。90000 = 00 01 5F 90,实际存储为 90 5F 01 00 (小端存储,按Byte的倒序排列) std::cout << "*pLong: " << *pLong << std::endl; *pInt = 20; // 使用指针并赋值,错误。因为这个指针已经被删除。20 = 00 14,内存里存储为14 00 // 如果对空指针赋值,程序将崩溃,这是与失控指针相比,空指针的另一个优点 std::cout << "*pInt: " << *pInt << std::endl; // 使用指针,错误,尽管打印了第一个指针期望的正确值,但其实错误,因为它已经被删除了 std::cout << "*pLong: " << *pLong << std::endl; // 使用指针,错误,打印结果不是第二个指针期望的值,尽管它存在内存里,但内容已被改写 delete pLong; // 删除指针,正确。 return 0; }
输出结果:
*pInt: 10 // 简单
*pLong: 90000 // 简单
*pInt: 20 // 输出结果正确,但其实鸠占鹊巢使用内存,以后不保证正确,而且影响了应该正确输出的另一个变量。
*pLong: 65556 // 输出结果错误,不是期望的值,原因是失控指针pInt与正常指针pLong使用同一块内存,于是其内存的一部分数据被改写,即90 5F 00 01的低端部分被改写,改成:14 00 01 00,再变回人类正常数字的顺序,即00 01 00 14 = 65556
疑问1:《21天学通C++》中文版书上p157说 90000(00 01 5F 90)实际存储为5F 90 00 01 ,即按照Word长度反序排列,这应该是错误。整个过程使用VC++观察内存值,特别清楚
--------------------------------------
继续1,如果把第一个指针的声明语句改成:
long * pInt = new long;
那么打印结果是:
*pInt: 10
*pLong: 90000
*pInt: 20
*pLong: 20 (第二个指针指向的内容与第一个指针指向的内容长度完全一致)
--------------------------------------
继续2,如果把第一个指针的声明语句改成:
char * pInt = new char;
那么
*pInt = 10; // 只把一个字节改成 0A
使用失控指针的时候:
*pInt = 20; // 只把一个字节改成 14
最终第二个指针的值变成 00 01 5F 14 = 89876
--------------------------------------
继续3:有空可以看看这个程序的反汇编,研究一下。
参考,关于大端小端的图,很形象:
http://www.cppblog.com/tx7do/archive/2009/01/06/71276.html