内存管理
内存的分配方式
答:分配方式有三种,
1、 静态存储区,是在程序编译时就已经分配好的,在整个运行期间都存在,如全局变量、常量。
2、 栈上分配,函数内的局部变量就是从这分配的,但分配的内存容易有限。
3、 堆上分配,也称动态分配,如我们用new,malloc分配内存,用delete,free来释放的内存
new/delete 与 malloc()/free() 的区别?
malloc() 与 free() 是C语言的标准库函数, new/delete 是C++的运算符, 他们都可以用来申请和释放内存, malloc()和free()不在编译器控制权限之内, 不能把构造函数和析构函数的任务强加给他们
内存分配的注意事项
用new或malloc分配内存时,必须要对此指针赋初值。
用delete 或free释放内存后,必须要将指针指向NULL
关于malloc/free 和new /delete
malloc/free 是C/C+的内存分配符,new /delete是C++的内存分配符。
注意:malloc/free是库函数,new/delete是运算符
malloc/free不能执行构造函数与析构函数,而new/delete可以
new/delete不能在C上运行,所以malloc/free不能被淘汰
两者都必须要成对使用
C++中可以使用_set_new_hander函数来定义内存分配异常的处理
delete与 delete []区别
delete只会调用一次析构函数,而delete[]会调用每一个成员的析构函数。在More Effective C++中有更为详细的解释:“当delete操作符用于数组时,它为每个数组元素调用析构函数,然后调用operator delete来释放内存。”delete与new配套,delete []与new []配套
MemTest *mTest1=new MemTest[10];
MemTest *mTest2=new MemTest;
Int *pInt1=new int [10];
Int *pInt2=new int;
delete[]pInt1; //-1-
delete[]pInt2; //-2-
delete[]mTest1;//-3-
delete[]mTest2;//-4-
在-4-处报错。
这就说明:对于内建简单数据类型,delete和delete[]功能是相同的。对于自定义的复杂数据类型,delete和delete[]不能互用。delete[]删除一个数组,delete删除一个指针。简单来说,用new分配的内存用delete删除;用new[]分配的内存用delete[]删除。delete[]会调用数组元素的析构函数。内部数据类型没有析构函数,所以问题不大。如果你在用delete时没用括号,delete就会认为指向的是单个对象,否则,它就会认为指向的是一个数组。
new,delete和malloc,free的用法
MemTest *mTest1=new MemTest[10];
MemTest *mTest2=new MemTest;
Int *pInt1=new int [10];
Int *pInt2=new int;
delete[]pInt1;
delete[]pInt2;
malloc和free
char *p = (char *) malloc( 100 ) //分配内存
if ( *p == NULL ) //查看内存是否分配成功
{
//进行申请内存失败处理
}
free( p ) // 释放内存
p = NULL //将内存置为空,防止也指针的出现
以下是几个对于可能出现内存泄露的问题
1.
void test1()
{
char string[10];
char* str1 = "0123456789";
strcpy( string, str1 );
} //字符串str1需要11个字节才能存放下(包括末尾的’\0’),而string只有10个字节的空间,strcpy会导致数组越界
2.
void test2()
{
char string[10],str1[10];
int i;
for(i=0; i<10; i++)
{
str1 = 'a';
}
strcpy( string, str1 );
} //如果面试者指出字符数组str1不能在数组内结束可以给3分;如果面试者指出strcpy(string,str1)调用使得从str1内存起复制到string内存起所复制的字节数具有不确定性可以给7分,在此基础上指出库函数strcpy工作方式的给10分
3.
void test3(char* str1)
{
char string[10];
if( strlen( str1 ) <= 10 )
{
strcpy( string, str1 );
}
} //if(strlen(str1)<= 10)应改为if(strlen(str1) < 10),因为strlen的结果未统计’\0’所占用的1个字节
4.
void GetMemory( char *p )
{
p = (char *) malloc( 100 );
}
void Test( void )
{
char *str = NULL;
GetMemory( str );
strcpy( str, "hello world" );
printf( str );
} //传入中GetMemory(char *p )函数的形参为字符串指针,在函数内部修改形参并不能真正的改变传入形参的值,执行完char *str = NULL;
//GetMemory( str );
//后的str仍然为NULL
5.
char *GetMemory( void )
{
char p[] = "hello world";
return p;
}
void Test( void )
{
char *str = NULL;
str = GetMemory();
printf( str );
} //char p[] = "hello world";
//return p; 的p[]数组为函数内的局部自动变量,在函数返回后,内存已经被释放。这是许多程序员常犯的错误,其根源在于不理解变量的生存期
6.
void GetMemory( char **p, int num )
{
*p = (char *) malloc( num );
}
void Test( void )
{
char *str = NULL;
GetMemory( &str, 100 );
strcpy( str, "hello" );
printf( str );
} //GetMemory避免了试题4的问题,传入GetMemory的参数为字符串指针的指针,但是在GetMemory中执行申请内存及赋值语句
//*p = (char *) malloc( num );后未判断内存是否申请成功,应加上:
//if ( *p == NULL )
//{
// ...//进行申请内存失败处理
//}
7.
void Test( void )
{
char *str = (char *) malloc( 100 );
strcpy( str, "hello" );
free( str );
... //省略的其它语句
} //char *str = (char *) malloc(100);后未进行内存是否申请成功的判断;另外,在free(str)后未置str为空,导致可能变成一个“野”指针,应加上:
//str = NULL
8.
swap( int* p1,int* p2 )
{
int *p;
*p = *p1;
*p1 = *p2;
*p2 = *p;
}
//p是一个“野”指针,有可能指向系统区,导致程序运行的崩溃
总结:
1.字符串是以“\0”结尾的,在拷贝数据的时候,不要忘了数组
2.strcpy(s1,s2);strcpy函数的意思是:把字符串s2中的内容copy到s1中,连字符串结束标志也一起copy,当遇到”\0”作为结束符
3 strlen是计算字符串的字节数,不算’\0’所占用的1个字节
4 函数内部修改形参并不能真正的改变传入形参的值
5 函数中的局部自动变量,在函数返回后,内存已经被释放
6 申请了内存应该判断是否申请成功
7 对于释放内存之后,应该把他置为NULL,防止也指针的出现