内存出错,内存泄露,数组越界,悬空指针,错误分配

来源:互联网 发布:福建广电网络官方网站 编辑:程序博客网 时间:2024/05/02 07:27
 


2010-06-01 10:43 968人阅读 评论(3) 收藏 举报

内存出错

. 数组越界;

. 内存泄露;

. 悬空指针(野指针);

. 错误分配。

 

1.     数组越界:

程序反应:

 跳出“内存不足。”提示框。

调试的时候无法定位到准确的出错点,也就是程序崩溃的地方不确定。

但是大致出错会在数组所在的函数里面或调用了数组的函数里,如果总弹出以上对话框,就检查出错代码附近是否有用到数组,特别是边界处要仔细检查。

应用vector的时候也要注意越界问题。

2. 内存泄露

new后一定要delete,malloc之后一定要free。

程序反应:

一是可能像上面一样弹出对话框提示。//一般不会出现。

二是可能在Debug版下编译运行均不会崩溃,但是Release版下会导致程序崩溃,这一般是内存泄露的问题。

2.1:1. delete的时候为什么会报错?2.在哪里delete比较合适?

BOOL  Test(char*& ptStr)

{

 

       CString  temp;

       temp = m_pListCtrl->GetItemText(iRow, iCol);

 

       ilen = temp.GetLength()+1;   //必须加1

       ptStr = new char[ilen];

       strcpy(ptStr,temp);  

  

       // delete ptStr;

       return TRUE;

}

void CallTest()

{

       char* cstemp = NULL;

for( i=0;i<Count;i++)

       {

              Test(cstemp);

delete cstemp;

       }    

}

2.2:构造函数和析构函数对指针的操作

class CFM3Dlg

{

public:

       CFM3Dlg();

       ~CFM3Dlg(); 

Cs2 * cs2;

}

CFM3Dlg::CFM3Dlg()

{

       cs2 = NULL;

}

CFM3Dlg::~CFM3Dlg()

{

       if (cs2)

       {

              delete cs2;

              cs2 = NULL;        

       }

}

// 用cs2指针之前最好先判断cs2指针是否为空。

2.3:来自资源错误管理的潜在堆内存丢失

int getkey(char *filename)

{

FILE *fp;

int key;

fp = fopen(filename, "r");

fscanf(fp, "%d", &key);

return key;

}

“资源”不一定仅仅指“内存”,如FILE句柄可能与内存块不同,但是必须对它们给予同等关注。

fopen的语义需要补充性的 fclose。在没有 fclose()的情况下,C 标准不能指定发生的情况时,很可能是内存泄漏。其他资源(如信号量、网络句柄、数据库连接等)同样值得考虑,像excel中的一些应用,用完后也都要release。

 

2.4:new时用了[],delete时也要用[]。new时没有用[],delete时也不要用[]。

string *stringarray = new string[100];
...
delete stringarray;
 

stringarray指向的100个string对象中的99个不会被正确地摧毁,因为他们的析构函数永远不会被调用。

 

string *stringptr1 = new string;
string *stringptr2 = new string[100];
...
delete stringptr1;// 删除一个对象
delete [] stringptr2;// 删除对象数组

 

2.5:内存耗尽怎么办?

如果在申请动态内存时找不到足够大的内存块,malloc和new将返回NULL指针,宣告内存申请失败。通常有三种方式处理“内存耗尽”问题。

(1)判断指针是否为NULL,如果是则马上用return语句终止本函数。例如:

void Func(void)
{
    A *a = new A;//int 
    if(a == NULL)//对于内存有限的小机最好作此判断
    {
        return;
    }
    
}

(2)判断指针是否为NULL,如果是则马上用exit(1)终止整个程序的运行。例如:

void Func(void)
{
    A *a = new A;
    if(a == NULL)
    {
        std::cout << “Memory Exhausted” << std::endl;
        exit(1);
    }
    
}

(3)为new和malloc设置异常处理函数。例如Visual C++可以用set_new_hander函数为new设置用户自己定义的异常处理函数。

在<new>文件中有:

typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();

用户自定义:

void nomorememory()

{

       std::cerr << "unable to satisfy request for memory/n";

       abort();

}

void OnCancel()

{

       set_new_handler(nomorememory);     //报错

//set_new_handler(NULL);           //调用std::bad_alloc异常, bad_alloc是operator new不能满足内存分配请求时抛出的异常类型。

       int *pbigdataarray = new int[1000000000];

}

3.   悬空指针(野指针)

“调试”难以识别悬空指针。“野指针”不是NULL指针,是指向“垃圾”内存的指针。人们一般不会错用NULL指针,因为用if语句很容易判断。但是“野指针”是很危险的,if语句对它不起作用。 “野指针”的原因主要有如下几种:

(1)指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。例如

char *ip = NULL;

char *ip = new char;

(2)指针ip被free或者delete之后,没有置为NULL,让人误以为ip是个合法的指针。

     Delete后ip所指的对象清空,但指针仍然还有值。

若内存在释放后立即被覆盖,并且新指向的值不同于预期值,但是却很难识别出新值是错误值。

(3)指针操作超越了变量的作用范围。这种情况让人防不胜防,示例程序如下:

class A
{
    public:
    void Func(void){ std::cout << “Func of class A” << std::endl; }
};
void Test(void)
{
    A *p;
    {
        A a;
        p = &a; // 注意 a 的生命期 
    }
    p->Func(); // p是“野指针”
}

函数Test在执行语句p->Func()时,对象a已经消失,而p是指向a的,所以p就成了“野指针”。但奇怪的是有些编译器运行这个程序时居然没有出错,这可能与编译器有关。

4.   错误分配

错误分配的管理不是很困难, 此类错误都会被快速地检测到。

4.1两个错误的内存释放

/* Allocate once, free twice. */

void f3()

{

    char *p;

    p = malloc(10);

     ...

    free(p);

     ...

    free(p);

 }

/* Allocate zero times, free once. */

void f4()

{

    char *p;

/* Note that p remains uninitialized here. */

    free(p);

}

4.2未初始化的指针

void f2(int datum)

{

int *p2;

/* Uh-oh!  No one has initialized p2. */

*p2 =datum;

...

}

原创粉丝点击