VC++调试过程中的内存堆栈初始值
当时情况是这样的,在品读《数据结构与算法分析-C语言描述》一书。书中第一个例子便是k选择问题。随手在DEVC++下敲了第一版代码。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int k_selection(int a[], int len, int k) 2 { 3 int *tmp = (int*)malloc((k+1)*sizeof(int)); 4 if(NULL == tmp) 5 { 6 return -1; 7 } 8 memset(tmp, 0, sizeof(tmp)); 9 for(int i = 0; i < len; ++i) 10 { 11 for(int j = k-1; a[i] > tmp[j] && j >= 0; --j) 12 { 13 tmp[j+1] = tmp[j]; 14 tmp[j] = a[i]; 15 } 16 } 17 18 int ret = tmp[k-1]; 19 free(tmp); 20 21 return ret; 22 }
毫无意外地发现代码运行结果错误。鉴于DEVCPP简陋的调试环境,祭出大杀器VS2012。
设置断点,打开内存监视窗口。
点击菜单【调试】->【窗口】->【内存】->【内存1】/【内存2】/【内存3】/【内存4】即可打开内存窗口。
默认快捷键:Alt + 6。
输入为存储k个值所申请堆的内存地址,得到该地址值如下图:
tmp数组除前四个数组成功置位0外,其它均为oxcd。
后在网上查阅相关资料http://en.wikipedia.org/wiki/Magic_number_(programming)得知,在内存分配或释放过程中,编译器会对这些内存写入一些Magic debug value,以便于调试发现问题。在VC++中常见的如下:
* 0xcccccccc : Used by Microsoft's C++ debugging runtime library to mark uninitialised stack memory
* 0xcdcdcdcd : Used by Microsoft's C++ debugging runtime library to mark uninitialised heap memory
* 0xfeeefeee : Used by Microsoft's HeapFree() to mark freed heap memory
* 0xabababab : Used by Microsoft's HeapAlloc() to mark "no man's land" guard bytes after allocated heap memory
* 0xabadcafe : A startup to this value to initialize all free memory to catch errant pointers
* 0xbaadf00d : Used by Microsoft's LocalAlloc(LMEM_FIXED) to mark uninitialised allocated heap memory
* 0xbadcab1e : Error Code returned to the Microsoft eVC debugger when connection is severed to the debugger
* 0xbeefcace : Used by Microsoft .NET as a magic number in resource files
如我们经常看到计算机发出"高温预警",即是因为VC 会把未初始化的栈内存上的指针赋值为 0xcccccccc ,中文字符显示 “烫烫烫烫……”;把未初始化的堆内存上的指针赋值为0xcdcdcdcd,即 “屯屯屯屯……”。
如此,发现代码中申请的堆空间只初始化了前四个字符,修改之得到第二版代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int k_selection(int a[], int len, int k) 2 { 3 int msize = (k+1)*sizeof(int); 4 int *tmp = (int*)malloc(msize); 5 if(NULL == tmp) 6 { 7 return -1; 8 } 9 memset(tmp, 0, msize); 10 for(int i = 0; i < len; ++i) 11 { 12 for(int j = k-1; a[i] > tmp[j] && j >= 0; --j) 13 { 14 tmp[j+1] = tmp[j]; 15 tmp[j] = a[i]; 16 } 17 } 18 19 return tmp[k-1]; 20 }
而在vc++中第一版代码也能运行成功,即是因为0xcdcdcdcd小于0,而代码中未考虑输入数列可能存在负数的问题。
tips:sizeof是在编译过程中由编译器根据参数类型计算得到的,在计算机内存中不存在数据类型这个概念。