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.



 

posted on 2012-06-29 16:53  h2内存数据库  阅读(958)  评论(0编辑  收藏  举报

导航