主题:关于vc中用new申请动态内存的问题,谢谢
waver001 [专家分:0] 发布于 2008-01-05 21:58:00
哪位朋友能先解释一下动态内存分配和静态内存分配的相关基础,他们各是在何时分配内存的。
我在程序中是这样做的:先在函数PixelCol* BmpToStructImage(HDIB hDIB)中用new分配了一段内存,最后返回指向该内存的指针lp(在该函数中并没有 delete lp)。然后在另一函数void CSIIDlg::OnColorCluster() 中用一个指针指向刚才申请的空间PixelCol * ImageData=BmpToStructImage(m_hDIB);,不知这样是否妥当,是否造成内存泄露。
void CSIIDlg::OnColorCluster()
{
#define A 7
CDlgCluster dlg;
if(dlg.DoModal()!=IDOK)
{
return ;
}
int i,j,l;
int Count=0;//当前的聚类数
Set* lpSet=new Set[dlg.m_P];
[color=FF0000] PixelCol * ImageData=BmpToStructImage(m_hDIB);[/color]
LPSTR lpDIB; // 指向DIB的指针
lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) m_hDIB); // 锁定DIB
DWORD dwWidth = DIBWidth(lpDIB);
DWORD dwHeight =DIBHeight(lpDIB);
PixelCol y;
BYTE err=0;
int cluster;//将要加入的聚类
for (i=0;i<dlg.m_P;i++)
{
lpSet[i].CreateMemory(dwHeight,dwWidth);
}
for( j=0;j<dwHeight-100;j++)
for( i=0;i<dwWidth-100;i++)
{
y=ImageData[j*dwWidth+i];
if(0==Count)
{ lpSet[0].lpCurrent=lpSet[0].lpCpoint;
lpSet[0].lpCurrent->x=(LONG)i;
lpSet[0].lpCurrent->y=(LONG)j;
lpSet[0].lpCurrent++;
lpSet[0].MeanValue=y;
lpSet[0].Total++;
Count++;
continue;
}
cluster=FindMinError(y,err,Count,lpSet);
if(err<dlg.m_R) AddPixToSet(i,j,lpSet+cluster,y);
else
{ l=Count;
Count++;
//检测目前聚类数Count是否大于期望聚类数m_P,若是则更新聚类半径m_R
if(Count>dlg.m_P)
{dlg.m_R=dlg.m_R+(Count-dlg.m_P)*A*dlg.m_R/dlg.m_P;
Count=0, i=-1, j=0;
for(int k=0;k<dlg.m_P;k++)
{ lpSet[k].Total=0;
}
continue;
}
lpSet[l].lpCurrent=lpSet[l].lpCpoint;
lpSet[l].lpCurrent->x=i;
lpSet[l].lpCurrent->y=j;
lpSet[l].lpCurrent++;
lpSet[l].MeanValue=y;
lpSet[l].Total++;
}
}
}
PixelCol* BmpToStructImage(HDIB hDIB)
{ LPSTR lpDib;
LPSTR lpDIBBits;
PixelCol * lp;
LPBITMAPINFOHEADER lpBi;
//锁定输入内存
lpDib = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
lpBi = (LPBITMAPINFOHEADER)lpDib;
//如果不是24位图,返回NULL
if(lpBi->biBitCount != 24)
{
return NULL;
}
lpBi = (LPBITMAPINFOHEADER)lpDib;
DWORD dwWidth = lpBi->biWidth;
DWORD dwHeight = lpBi->biHeight;
DWORD dwLineBytes = (DWORD)WIDTHBYTES(dwWidth * 24);
//申请BufSize大小的内存空间
DWORD BufSize=dwWidth*dwHeight;
[color=FF00FF] lp= new PixelCol[BufSize];[/color]
if (lp==0)
{
AfxMessageBox("申请空间错误");
}
lpDIBBits=::FindDIBBits(lpDib);//找到DIB图像像素起始位置
int i,j;
for(j=0;j<dwHeight;j++)
for(i=0;i<dwWidth;i++)
{
lp[j*dwWidth+i].b=lpDIBBits[j*dwLineBytes+i*3+0];
lp[j*dwWidth+i].g=lpDIBBits[j*dwLineBytes+i*3+1];
lp[j*dwWidth+i].r=lpDIBBits[j*dwLineBytes+i*3+2];
}
[color=FF0000]return lp;[/color]}
回复列表 (共9个回复)
沙发
vbcs [专家分:3910] 发布于 2008-01-07 00:16:00
看了一下你的程序太长,就写了一个类似的小测试程序:
#include "stdio.h"
#include "windows.h"
char *GetMyChar(char *name);
void main()
{
char *name="zhongguohebei";
char *p=GetMyChar(name);
printf("%s\n",p);
delete p;
p=NULL;
}
char* GetMyChar(char *name)
{
int num;
num=strlen(name);
char *temp=new char[num];
memcpy(temp,name,num);
return temp;
}
你看一下是不是我的这个意思,如果是的话,
那也就是没有:
delete p;
p=NULL;
这两句,如果是这样的话肯定是会内存泄露得。因为你new出来得东西是在堆上的,
是不会自己回收得。要手动。
我用BoundsChecker检测了一下结果也是这样的。
板凳
华山论剑 [专家分:5310] 发布于 2008-01-07 08:57:00
静态声明就是普通的声明,比如:int x;
静态声明的变量在编译时刻就会决定其内存的分配(在程序的运行栈上),其释放也不用程序员干预,根据声明的变量类型(局部、全局、静态static等),是自动进行的。
动态声明的变量就是用new声明的变量,它是在堆上(系统空闲存储区)分配内存的,其生命周期由声明时刻开始,到程序员显示式地用delete或者delete[]释放时结束。
所以如果你不用delete,是会有内存泄漏的。你可以在这个变量不需要时显式释放,或者学习用C++的auto_ptr,它会自动管理声明的动态内存变量。
相对来说,静态声明的变量运行效率更高,因为编译期就已经分配了内存。但对于不能预知大小的变量,比如一个网络聊天室,参加聊天的人可能从一个到几百个,这时要声明变量保存聊天者的资料,用动态声明就更好,不然为了保险起见,可能要声明一个一两千个元素的数组变量,但很多时候只用几个。
上面的程序好像是图片处理方面的,由于不知道详细的流程目的,也不好确定用什么方式。
3 楼
waver001 [专家分:0] 发布于 2008-01-07 15:38:00
谢谢大家的帮助。
vbcs朋友,我就是你这个意思,在主调函数main()中 delete p;p=NULL;以后就不会造成内存泄漏了吧。
另外还有点疑虑:先在一个函数A(被调函数)中new一段内存空间,指针p=new,用指针作函数返回值。然后在主调函数B中定义了另一个指针p1,两个指针都指向那一段空间,最后仅在B中 delete p1。 这样的编程习惯怎么样呀,会不会造成野指针啊(不同函数中的指针指向同一内存空间)。
A()
{...
char* p=new;
完成某种处理,结果在p中保存...
return p;
}
B()
{
char* p1=A();
......
delete p1;
}
我最近正在编写一个c均值聚类的图像处理算法,但是程序一运行,资源管理器就显示无响应,不知是何原因,很是郁闷啊
4 楼
华山论剑 [专家分:5310] 发布于 2008-01-07 16:58:00
可以像上面那样调用!
还有个办法可能更好,就是在主调函数中声明一个指针变量,然后以参数形势传递给被调函数,再在被调函数内new一片内存出来后返回(不用返回值),这样就不会有两个指针指向同一地址了。
5 楼
vbcs [专家分:3910] 发布于 2008-01-07 18:55:00
[quote]可以像上面那样调用!
还有个办法可能更好,就是在主调函数中声明一个指针变量,然后以参数形势传递给被调函数,再在被调函数内new一片内存出来后返回(不用返回值),这样就不会有两个指针指向同一地址了。[/quote]
同意!!!
6 楼
waver001 [专家分:0] 发布于 2008-01-08 14:24:00
谢谢两位朋友,本人才疏学浅,还得还好好向大家学习啊。
听同学介绍,最好在一个函数中new一段内存就在该函数中delete 掉这段空间。但我的思路恰恰相反,想在主调函数中保留被调函数中new的空间,因为那里存有我处理的结果,不知大家如何看待这个问题。
再次感谢!
7 楼
waver001 [专家分:0] 发布于 2008-01-08 15:18:00
在问个小问题:由于没有delete造成的内存泄露,在关闭应用程序后,操作系统是否会释放掉呢?还是要等到下次开机呢?
8 楼
华山论剑 [专家分:5310] 发布于 2008-01-08 16:43:00
如果你的被调函数仅仅是分配内存,在被调函数内delete掉这个函数就没有存在价值了。
“最好在一个函数中new一段内存就在该函数中delete 掉这段空间”,这句话也不错,像上面例子,如果只是一个简单的new,没有必要写一个函数来分配,直接在主程序中写和最后delete就行了。
如果造成泄漏,关闭程序后,操作系统会释放。如果这个程序是个服务器程序(比如网络聊天服务器),很久不关闭的,假设每多一个聊天客户登录,就多一次泄漏,这个服务程序一定时间后就可能崩溃。而对于一般的小型程序,泄漏一点对于现代的硬件来说,未必有明显的影响。
9 楼
vbcs [专家分:3910] 发布于 2008-01-08 20:44:00
delete 之后,还没有完成,
还要把指针给值成NULL
我来回复