VC++调试过程中的内存堆栈初始值

  当时情况是这样的,在品读《数据结构与算法分析-C语言描述》一书。书中第一个例子便是k选择问题。随手在DEVC++下敲了第一版代码。

 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 }
View Code

  毫无意外地发现代码运行结果错误。鉴于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,即 “屯屯屯屯……”。

  如此,发现代码中申请的堆空间只初始化了前四个字符,修改之得到第二版代码如下:

 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 }
View Code

  而在vc++中第一版代码也能运行成功,即是因为0xcdcdcdcd小于0,而代码中未考虑输入数列可能存在负数的问题。

  tips:sizeof是在编译过程中由编译器根据参数类型计算得到的,在计算机内存中不存在数据类型这个概念。

posted @ 2015-05-17 14:32  eagleliwx  阅读(709)  评论(0编辑  收藏  举报