内存分区
- 堆:由程序员手动分配(malloc和new)和释放(free和delete),若不手动释放,会造成内存泄漏。当程序结束时会由系统释放申请的内存。
- 栈:由编译器自动分配和释放的,用于存放函数的参数,函数内的局部变量等,函数执行结束时这些存储单元自动释放。
- 静待存储区:由编译器在编译的时候分配,用于存放全局变量和静态变量(全局和局部),包括DATA段(全局初始化区)与BSS段(全局未初始化区)。BSS段的特点是在程序执行之前BSS段会自动清零。这块内存在程序的整个运行期间都存在。
- 文字常量区:用于存放常量字符串,程序结束后由系统释放。
- 程序代码区:存放函数的二进制代码。
内存管理
-
指针没有指向一块合法的内存
定义了指针变量,但是没有为此指针分配内存。
例如:结构体里面定义的指针变量
struct employe
{
char *name;
int id;
}emp;int main(void)
{
strcpy(emp.name,“daniao”;
emp.id=12331;
return 0;
}
name指针没有指向一个合法的地址,其内部存的只是一些乱码,执行strcpy函数时,会将字符串往乱码所指内存上拷贝,而这块内存name指针无权访问。解决的办法是为name指针malloc一块内存。 -
为指针分配的内存太小
char *src=“abcde”;
char *dest=(char *)malloc(sizeof(char)*strlen(src));
strcpy(dest,src);
src为字符串常量,长度为字符个数加"\0"的长度,上述字符串拷贝函数没能将字符串结束标志"\0"拷贝到dest中。 -
内存分配成功,但尚未初始化就引用它
指针变量如果未初始化,会导致if语句或assert宏检验失效。 -
内存访问越界
内存分配成功并且已初始化,但操作越过了内存的边界,主要是由于操作数组或指针时出现了多1或少1的情况。
int a[5]={1,2,3,4,5};
for(int i=0;i<=5;++i)
{
sum+=a[i];
}
for循环变量一般采取半开半闭的区间。 -
忘记释放内存,造成内存泄漏
malloc函数原型:void * malloc(int size);
例如:int *p=(int *)malloc(sizeof(int)*10);
使用malloc函数注意的几点:内存分配给谁(分给p)、内存分配多大(sizeof(int)*10)、是否有足够的内存分配(if语句验证)、内存用来存那种类型的数据(int)、分配好的内存在哪里(堆上)。既然malloc函数申请内存可能不成功,所以在使用指向这块内存的指针时,必须用if(NULL!= p)来验证内存分配成功与否。
使用free函数注意的几点:free必须与malloc配套、free之后必须把指针置空,否则if语句不起作用,因为free函数只是把内存与指针之间的关系斩断,而指针变量本身保存的地址并没有改变,只是对这个地址处的内存没有了所用权。 -
释放了内存却继续使用
1.函数返回指向栈内存的指针或引用
2.free之后,没能将指针置空,产生野指针
3.对象调用关系过于复杂,难以搞清某个对象释放