常见的内存错误及其对策

1.常见的内存错误及其对策

  *内存未分配成功却使用了它:

   在使用内存之前检查指针是否为NULL。如果指针p是函数的参数,那么在函数的入口处用assert(p!=NULL)进行检查 ;如果使用malloc或者new来申请内存,应该用if(p==NULL)或if(p!=NULL)进防错处理。

     *无论用何种方式创建数组,都别忘了赋初值,即便是赋零值也不可省略,不要嫌麻烦。

     *内存分配成并且已经初始化,但操作越过了内存的边界。

     *内存泄露。动态内存的申请与释放必须配对,申请与释放的次数一定要想同。

     *释放了内存却继续使用它(三种情况):

   (1)对象调用关系过于复杂。应重新设计数据结构,解决对象管理混乱局面

   (2)函数注意不要返回指向“栈内存”的“指针”或者“引用”,该内存在函数体结束时会被销毁

   (3)使用free或delete释放了内存后,没有将指针设置为NULL。导致产生“野指针”。  

2. 指针与数组的对比

     *数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。数组名对应着(而不是指向)一块内存,其地址与容量在声明周期内保持不变,只有数组的内容可以改变。

2.1修改内容

      企图修改常量字符串的内容导致运行错误。

2.2内容复制与比较

      对数组进行复制:strcpy();

     对数组进行比较:strcmp();

     //指针

      intlen=strlen(a);

     char*p=(char *)malloc(sizeof(char)*(len+1));

    strcpy(p,a);              //不要用p=a,

    if(strcmp(p,a)==0)  //不要用if(p==a),那是比较地址

2.3.计算内存容量

      chara[]="hello world";     //sizeof(a)的值为12(别忘了'\0')。

      voidFunc(char a[100])

      {

           cout<<sizeof(a)<<endl;//4字节而不是100字节,当数组作为函数的参数进行传递时,该数组自动退化

                                                     //为同类型的指针。

      }

2.4指针参数是如何传递内存的?

      如果函数的参数是一个指针,不要指望用该指针去申请动态内存。

      voidGetMemory(char *p,int num)

      {

          p=(char *)malloc(sizeof(char)*num);

      }

      voidTest(void)

     {

          char*str=NULL;

           GetMemory(str,100);//str仍然为NULL

          strcpy(str,"hello");    //运行错误

        }

    Test函数的语句GetMemory(str,200)并没有使str获得期望的内存,str依旧是NULL。

    毛病出在GetMemory()中。编译器总是要为函数的每个参数制作临时副本,指针参数p的副本是_p,编译器使_p=p。如果函数体内的程序修改了_p的内容,就导致参数p的内容作相应的修改。这就是指针可以用作输出参数的原因。在上面代码中,_p申请了新的内存,只是把_p所指的内存地址改变了,但是p丝毫未变。所以函数GetMemory()并不能输出任何东西。事实上,每执行一次GetMemory()就会泄露一块内存,因为没有用free释放内存。

     如果非要用指针参数去申请内存,那么应该改用"指向针针的指针"

        voidGetMemory2(char **p,int num)

        {

             *p=(char *)malloc(sizeof(char)*num);

        }

        voidTest2(void)

        {

            char*str=NULL;

           GetMemory(&str,100);//注意参数是&str

           strcpy(str,"hello");

           cout<<str<<endl;

           free(str);

       }

       还可以用函数返回值来传递动态内存,这种方法更简单。

       char *GetMemory3(int num)

       {

            char *p=(char*)malloc(sizeof(char)*num);

           return p;

       }

       voidTest3(void)

       {

            char*str=NULL;

           str=GetMemory3(100);

            strcpy(str,"hello");

           cout<<str<<endl;

           free(str);

       }

     用函数返回值传递动态内存这种方法虽然好用,但是要注意不要用return语句返回指向“栈内存"的指针,因为该内存在函数结束时自动消亡。

       char*GetString(void)

       {

            charp[]="hello world";

            returnp; //编译器将提出警告

       }

      voidTest4(void)

       {

            char*str=NULL;

      str=GetString();//str的内容是垃圾,GetString()中的p指向的内存已经被释放

           cout<<str<<endl;

       }

       改为下面的代码:

       char*GetString2(void)

       {

            char*p="hello world";

           return p;

       }

       voidTest5(void)

       {

            char*str=NULL;

           str=GetString2();

           cout<<str<<endl;

        }

3. 常见的使用规则

[规则1]用malloc或new申请内存之后,因该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。

    [规则2]不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。

    [规则3]避免数字或指针的下标越界,特别要当心发生“多1”或者“少1”操作

    [规则4]动态内存的申请与释放必须配对,防止内存泄漏

    [规则5]用free或delete释放了内存之后,立即将指针设置为NULL,防止“野指针”

4.  内存分配方式有三种:
  (1) 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static 变量。
  (2) 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
  (3) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少的内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值