参考链接:https://blog.csdn.net/OneMoreTrying/article/details/41893853
https://blog.csdn.net/wuwuku123/article/details/104897719
一、概述
-
0xcccccccc
: Used by Microsoft’s C++ debugging runtime library to mark uninitialised stack memory
由Microsoft的C++调试运行时库用于标记未初始化的栈内存 -
0xcdcdcdcd
: Used by Microsoft’s C++ debugging runtime library to mark uninitialised heap memory
由Microsoft的C++调试运行时库用于标记未初始化的堆内存 -
0xfeeefeee
: Used by Microsoft’s HeapFree() to mark freed heap memory
由Microsoft的HeapFree()用于标记释放的堆内存 -
0xabababab
: Used by Microsoft’s HeapAlloc() to mark “no man’s land” guard bytes after allocated heap memory
被微软的HeapAlloc()用来在分配的堆内存后标记“无人地带”的保护字节 -
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
由Microsoft的LocalAlloc(LMEM_FIXED)用于标记未初始化的已分配堆内存 -
0xbadcab1e
: Error Code returned to the Microsoft eVC debugger when connection is severed to the debugger
断开与调试器的连接时,返回给Microsoft eVC调试器的错误代码 -
0xbeefcace
: Used by Microsoft .NET as a magic number in resource files
由Microsoft.NET在资源文件中用作魔法数字
平时我们只需要了解上面常见的三种就可以了:
0xcccccccc
、0xcdcdcdcd
和0xfeeefeee
,以帮我们迅速地发现问题并分析问题。
对于0xcccccccc和0xcdcdcdcd,在 DEBUG模式下:
- VC 会把未初始化的栈内存上的指针赋值为
0xcccccccc
,当字符串看就是 “烫烫烫烫……”; - 会把未初始化的堆内存上的指针赋值为
0xcdcdcdcd
,当字符串看就是 “屯屯屯屯……”。
那么调试器为什么要这么做呢?
VC的DEBUG模式会把未初始化的指针自动初始化为0xcccccccc或0xcdcdcdcd,而不是取随机值,那是为了方便我们调试程序,如果野指针的初值不确定,那么每次调试同一个程序就可能出现不一样的结果,比如这次程序崩溃,下次却能正常运行,这样显然对我们解BUG是非常不利的,所以
自动初始化的目的是为了让我们一眼就能确定我们使用了未初始化的野指针
。
- 对于
0xfeeefeee
,VC会把与已经释放掉的内存相关的指针赋值为0xfeeefeee
。
注意,如果指针指向的内存被释放了,变量本身的地址如未做改动,则还是之前指向的内存的地址。如果该指针是一个类的指针,并且类中包含有指针变量,则内存被释放后( 对于C++类,通常是执行delete操作 ),类中的指针变量就会被赋值为0xfeeefeee
。如果在调试代码过程中,发现有值为0xfeeefeee的指针,就说明该指针对应的内存被释放掉了。
关于VC中DEBUG和RELEASE模式下的变量初始化问题
大家都知道,DEBUG跟RELEASE在初始化变量时所做的操作是不同的,DEBUG是将每个字节位都赋成0xcc,而RELEASE的赋值近似于随机
( 我想是直接从内存中分配的,没有初始化过 )。这样就明确了,如果你的程序中的某个变量没被初始化就被引用,就很有可能出现异常
:用作控制变量将导致流程导向不一致;用作数组下标将会使程序崩溃;还可能因为其他变量的不准确而引起其他的错误。所以在声明变量后马上对其初始化一个默认的值
是最简单有效的办法,否则项目大了你找都没地方找。
二、代码示例
1
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char dest[] = "Hello A World";
char sour= 'A'; //定义字符变量,并初始化
char ch_temp; //定义字符变量,声明但未初始化
char *TEMP; //定义字符指针,但是其“值”为乱码,也即“野指针”(声明但未初始化)
char *ptemp = NULL; //定义字符指针,并初始化为NULL
char *PTEMP = 0; //定义字符指针,并初始化为0
char *PTemp = (char *)malloc(sizeof(char)); //通过malloc函数在堆上面分配内存,
int in_temp; //定义一个整形变量,但为初始化
int in_TEMP = 1; //定义一个整形变量,并初始化
return 0;
}
分析:
- 定义变量,未初始化:
char ch_temp 、int in_temp 为声明 但未初始化,在Debug模式下,debug是将每个字节位都赋成0xcc,因此 ch_temp为0Xcc、in_temp为0xcccccccc;
- 定义指针变量,未初始化:
char *TEMP 在 Debug 模式下,VC 会把未初始化的栈内存上的指针全部填成 0xcccccccc ,当字符串看就是 “烫烫烫烫……”
因此,在定义变量时,要及时初始化!
定义指针变量时,两种方式对待:
(1)定义指针变量,临时不用指针变量:将指针变量置NULL/0;就是将指针变量置为空指针;在用到的时候,然后用malloc、free函数在堆上面进行内存分配和释放;
(2)定义指针变量,并且用到指针变量:直接用malloc、free函数在堆上面进行内存分配和释放;
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char *TEMP; //定义字符指针,但是其“值”为乱码,也即“野指针”
char *ptemp = NULL; //定义字符指针,并初始化为NULL
char *PTEMP = 0; //定义字符指针,并初始化为0
//先定义,并将指针置空,后面用的时候,在malloc分配内存
char *PTemp = NULL;
PTemp = (char *)malloc(sizeof(char));
//先定义,并将指针置空,后面用的时候,在malloc分配内存
char *PTEmp = 0;
PTEmp = (char *)malloc(sizeof(char));
//直接定义并通过malloc函数在堆上面分配内存,
char *PTEMp = (char *)malloc(sizeof(char));
return 0;
}
2
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* a;
*a = 1;
system("pause");
return 0;
}
解析:整型指针变量a,没有初始化;既指针a存放地值(地址)为随机值,也就是平常说的“野指针”;
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* a = NULL;
*a = 1;
printf("*a=%d\n",*a);
system("pause");
return 0;
}
分析:这是因为NULL指针是一个特殊的指针变量,不指向任何内存,用来表示这个指针目前未指向任何位置。
所以对NULL指针进行解引用操作是非法的。
对指针进行解引用之前,要确定它不是NULL指针!
运行结果:无任何输出结果!
#include<stdio.h>
#include<stdlib.h>
int main()
{
int n = 0;
int* a = NULL;
a = &n;
*a = 1;
printf("*a=%d n=%d\n",*a, n);
system("pause");
return 0;
}
分析:首先对整型指针变量a初始化,指向NULL;然后将其指向整形变量n,因此,整型指针变量a的值为变量n的地址,有效!
运行结果:*a=1 n=1