C++内存管理(一)
1、 内存分配方式
(1)从静态存储区域分配。例如使用static、全局变量。静态存储区的数据在程序编译的时候就已经分配好了,在程序运行期间一直存在,只有在程序推出之后才会释放。
(2)在栈上分配。函数内部的局部变量都是在栈上分配的,在函数阶数时存储空间便被释放;
(3)在堆上分配。程序员根据自己的需要申请和释放内存(new/delete malloc/free)
2、在内存的分配过程中经常会出现一些错误。
(1)内存未分配成功却使用了他。例如内存中没有足够大的剩余空间此时内存分配(new/malloc)失败之后会返回NULL,可以用assert(p!=NULL)或者if语句进行检查。
(2)内存分配成功却没有初始化就引用它。 int *p=newint(10);//忘记初始化
(3)内存分配成功,但是越界操作。在使用数组下标时容易出现“多1”、“少1”
(4)忘记释放内存,造成内存泄露。
(5)内存被释放(delete)之后却继续使用它
3、指针与数组
(1)修改内容
char a[]=”hello”;
a[0]=’X’;
cout<<a<<endl;
char *p=”world”; //这里定义p指向常量字符串
p[0]=’X’; //错误,常量字符串的值不能被改变
cout<<endl;
(2)当使用数组作为函数的参数进行传递时,该数组自动退化为同类型的指针
void printLen(char a[100])
{
Cout<<sizeof(a)<<endl;//这里会输出4 而不是100
}
(3)指针参数传递内存
如果一个函数的参数是一个指针,不要使用该指针去申请动态内存。例如:
void getMem(char *p, int len)
{
p=(char*)malloc(sizeof(char) * len);
}
void test(void)
{
char*str=NULL;
getMem(str,1100);//执行之后str仍是NULL
strcopy(str,“hello”);//由于str=NULL 所以导致运行错误
}
上面运行错误是因为,在函数中重视要为每个参数制作一个临时的副本,在getMem中,指针参数p的副本就是_p,在编译器中会使_p=p。从而在函数体中修改了_p所指向的内容也就修改了p所指向的内容,这也就是指针可以作为输出参数的根本原因。但是在getMem函数中,临时的副本_p申请了一个新的内存空间,从而把_p所指向的空间改变了,从此再改变_p所指向的内容时,原来p所指向的内容被没有变化。而且这里没有使用free函数释放内存,从而在每次执行getMem的时候还会泄露一块内存。
解决办法:通过指向指针的指针 或者 返回指针
(1)指向指针的指针
void getMem1(char **p, int num)
{
*p=(char*)malloc(sizeof(char) * num);
}
void test1(void)
{
char*str = NULL;
getMem1(&str,100); //注意这里是&str
strcpy(str,“hello”);
cout<<str<<endl;
free(str); //不要忘了释放内存
}
(2)使用return返回指针
使用函数的返回值来动态传递内存的这种做法虽然比较好,但是有时候程序员常常会把return语句返回的结果弄错掉。主要是强调不要使用return语句返回指向栈内存的指针,因为该内存在函数结束的时候将会被释放,下次再访问该内存空间时存储的很可能不是原来的数据。例如:
#include "stdafx.h"
#include <iostream>
using namespace std;
char *getStr(void)
{
char str1[] = "hello world";//这个数据存储在栈上,在这个函数阶数之后这个空间将会被释放。
//由于返回的str指向的是这个地址,在以后再次用到这个地址时
//由于str这个空间已经被分配给其他变量,所以之后对str的操作
//会出错。
cout<<"str1[]的地址"<<&str1<<endl;
returnstr1; //这里编译器会提出警告,VC6.0中返回的地址为0x0012FE90
}
void test()
{
char*str2=NULL;
str2= getStr(); //这里str2=0x0012FEF0
cout<<"str2的地址"<<&str2<<endl;
cout<<str2<<endl;//打印出来的并不是 hello world 而是一串比较乱的字符,因为并不知道str2里面存的是什么
}
void main(void)
{
test();
}
注释:其实这里可以把下面这个函数中的变量定义做些修改:
char *getStr(void)
{
char str1[] = "hello world";
}
这个函数里的变量定义到静态存储区中就可以实现输出“hello world”
例如 static char str1[] = “hello world”; 或者 char *p = “hello world”;//这里需要注意一下第二种方法定义的是一种字符常量
主要参考《高质量C/C++编程指南》
Motto:the world makes way for the man who knows where he is going.