在处理C内存分派的时候,我们总会毫不犹豫的犯下各种错误,不信的话,你先看看下面几个例子。
例子一:
void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
请问运行Test 函数会有什么样的结果?
答:程序崩溃。因为GetMemory 并不能传递动态内存,Test 函数中的 str 一直都是 NULL。strcpy(str, "hello world")将使程序崩溃。
例子二:
char *GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
请问运行Test 函数会有什么样的结果?
答:可能是乱码。因为GetMemory 返回的是指向“栈内存”的指针,该指针的地址不是 NULL,但其原现的内容已经被清除,新内容不可知。
例子三:
void GetMemory2(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
请问运行Test 函数会有什么样的结果?
答:(1)能够输出hello(2)内存泄漏,内存没有回收。
例子四:
void Test(void)
{
char *str = (char *) malloc(100);
strcpy(str, “hello”);
free(str);
if(str != NULL)
{
strcpy(str, “world”);
printf(str);
}
}
请问运行Test 函数会有什么样的结果?
答:篡改动态内存区的内容,后果难以预料,非常危险。因为free(str);之后,str 成为野指针,if(str != NULL)语句不起作用。
如果,上面四个例子,你竟然都答对了,那下面的内容,就不是为你准备的了,你还是去别处转转吧!
C/C++程序内存的分配
在C/C++程序中分为这几个存储区:
1.栈区: 存放函数参数,局部变量等,由编译器自动分配释放。
2.堆区: 用于动态分配内存的, 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。
3.全局区(静态区):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,
未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 程序结束时释放。
4.另外还有一个专门放常量的地方,程序结束释放。
例如:
int a = 0; //全局初始化区
char *p1; //全局未初始化区
main()
{
int b; //栈
char s[] = "abc"; //S在栈上,"abc"在常量区
char *p2; //栈
char *p3 = "123456"; //"123456"在常量区,p3在栈上
static int c = 0; //全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);//分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456");//"123456"放在常量区,编译器可能会将p1与p3所指向的"123456"优化成一块。
}
一些常见的内存错误及其应对策略
1、内存分配为成功便使用。常用解决办法是,在使用内存之前检查指针是否为 NULL。
2、尚未初始化就引用。犯这种错误主要有两个起因:一是没有初始化的观念;二是误以为内存的缺省初值全为零,
导致引用初值错误(例如数组) 。所以无论用何种方式创建数组,都别忘了赋初值。
3、操作越过了内存的边界。
4、忘了释放内存,造成内存泄漏。动态内存的申请与释放必须配对,程序中 malloc 与 free 的使用次数一定要相同,
否则肯定有错误(new/delete 同理) 。
5、释放了的内存,还继续使用。主要有两种情况:
(1)函数的 return 语句写错了,注意不要返回指向“栈内存”的“指针”或者“引用” ,因为该内存在函数体结束时被自动销毁。
(2)使用 free 或 delete 释放了内存后,没有将指针设置为 NULL。导致产生“野指针” 。
因此,建议你:
1、用 malloc 或 new 申请内存之后,应该立即检查指针值是否为 NULL。防止使用指针值为 NULL 的内存。
2、不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。
3、避免数组或指针的下标越界,特别要当心发生“多 1”或者“少 1”操作。
4、动态内存的申请与释放必须配对,防止内存泄漏。
5、用 free 或 delete 释放了内存之后,立即将指针设置为 NULL,防止产生“野指针” 。
浙公网安备 33010602011771号