回 帖 发 新 帖 刷新版面

主题:关于vc中用new申请动态内存的问题,谢谢

哪位朋友能先解释一下动态内存分配和静态内存分配的相关基础,他们各是在何时分配内存的。

   我在程序中是这样做的:先在函数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个回复)

沙发

看了一下你的程序太长,就写了一个类似的小测试程序:
#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检测了一下结果也是这样的。

板凳

静态声明就是普通的声明,比如:int x;

静态声明的变量在编译时刻就会决定其内存的分配(在程序的运行栈上),其释放也不用程序员干预,根据声明的变量类型(局部、全局、静态static等),是自动进行的。

动态声明的变量就是用new声明的变量,它是在堆上(系统空闲存储区)分配内存的,其生命周期由声明时刻开始,到程序员显示式地用delete或者delete[]释放时结束。

所以如果你不用delete,是会有内存泄漏的。你可以在这个变量不需要时显式释放,或者学习用C++的auto_ptr,它会自动管理声明的动态内存变量。

相对来说,静态声明的变量运行效率更高,因为编译期就已经分配了内存。但对于不能预知大小的变量,比如一个网络聊天室,参加聊天的人可能从一个到几百个,这时要声明变量保存聊天者的资料,用动态声明就更好,不然为了保险起见,可能要声明一个一两千个元素的数组变量,但很多时候只用几个。

上面的程序好像是图片处理方面的,由于不知道详细的流程目的,也不好确定用什么方式。

3 楼


谢谢大家的帮助。

 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 楼

可以像上面那样调用!

还有个办法可能更好,就是在主调函数中声明一个指针变量,然后以参数形势传递给被调函数,再在被调函数内new一片内存出来后返回(不用返回值),这样就不会有两个指针指向同一地址了。

5 楼

[quote]可以像上面那样调用!

还有个办法可能更好,就是在主调函数中声明一个指针变量,然后以参数形势传递给被调函数,再在被调函数内new一片内存出来后返回(不用返回值),这样就不会有两个指针指向同一地址了。[/quote]

同意!!!

6 楼


谢谢两位朋友,本人才疏学浅,还得还好好向大家学习啊。

  听同学介绍,最好在一个函数中new一段内存就在该函数中delete 掉这段空间。但我的思路恰恰相反,想在主调函数中保留被调函数中new的空间,因为那里存有我处理的结果,不知大家如何看待这个问题。 

   再次感谢!

7 楼

在问个小问题:由于没有delete造成的内存泄露,在关闭应用程序后,操作系统是否会释放掉呢?还是要等到下次开机呢?

8 楼

如果你的被调函数仅仅是分配内存,在被调函数内delete掉这个函数就没有存在价值了。

“最好在一个函数中new一段内存就在该函数中delete 掉这段空间”,这句话也不错,像上面例子,如果只是一个简单的new,没有必要写一个函数来分配,直接在主程序中写和最后delete就行了。

如果造成泄漏,关闭程序后,操作系统会释放。如果这个程序是个服务器程序(比如网络聊天服务器),很久不关闭的,假设每多一个聊天客户登录,就多一次泄漏,这个服务程序一定时间后就可能崩溃。而对于一般的小型程序,泄漏一点对于现代的硬件来说,未必有明显的影响。

9 楼

delete 之后,还没有完成,
还要把指针给值成NULL

我来回复

您尚未登录,请登录后再回复。点此登录或注册