zoukankan      html  css  js  c++  java
  • 野指针及c++指针使用注意点

    避免野指针的产生

    “野指针”的成因主要有:

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

    char *p; //此时p为野指针

     

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

    char *p=new char[10];  //指向堆中分配的内存首地址,p存储在栈区
    cin>> p;
    delete []p; //p重新变为野指针

     

    3)指针操作超越了变量的作用范围。          

    char *p=new char[10]; //指向堆中分配的内存首地址
    cin>> p;
    cout<<*(p+10); //可能输出未知数据

    指针的注意点:

    a.指针指向常量存储区对象

    char *p="abc";

    此时p指向的是一个字符串常量,不能对*p的内容进行写操作,如srtcpy(p,s)是错误的,因为p的内容为“abc”字符串常量,该数据存储在常量存储区,但可以对指针p进行操作,让其指向其他的内存空间。

     

    b.资源泄漏

    问题:

    1 #include<iostream>
    2 using namespace std;
    3 void main()
    4 {
    5     char *p=new char[3];  //分配三个字符空间,p指向该内存空间
    6     p="ab";             //此时p指向常量“ab”,而不再是new char分配的内存空间了,从而造成了资源泄漏
    7     delete []p;         //释放时报错
    8 }

    结果:卡死

    改进:

    1 #include<iostream>
    2 using namespace std;
    3 void main()
    4 {
    5     char *p=new char[3];  //分配三个字符空间,p指向该内存空间
    6     strcpy(p,"ab");      //将"ab"存储到p指向的内存空间
    7     delete []p;         //ok
    8 }

    结果:正确

     

    c.内存越界

    1 char *p=new char[3];  //分配三个字符空间,p指向该内存空间
    2 strcpy(p,"abcd");    //将abcd存处在分配的内存空间中,由于strlen("abcd")=4>3,越界
    3 delete []p;         //ok

     

    d.返回值是指针

    问题:数组p[]中的内容为“hello world”,存储在栈区,函数结束时内容被清除,p变为野指针,可能导致乱码

     1 #include<iostream>
     2 using namespace std;
     3 char *f()
     4 {
     5     char p[]="abc";
     6     return p;
     7 }
     8 void main()
     9 {
    10     cout<<f()<<endl;
    11 }

    结果:

     改进:

    1.加static限定,延长数组生存期

     1 #include<iostream>
     2 using namespace std;
     3 char *f()
     4 {
     5     static char p[]="abc";  //此时数组为静态数组,存储在全局/静态区,生存期到程序结束,因此函数结束时不会销毁p
     6     return p;
     7 }
     8 void main()
     9 {
    10     cout<<f()<<endl;
    11 }

    结果:

    2.定义成指针型数组

     1 #include<iostream>
     2 using namespace std;
     3 char *f()
     4 {
     5     char *p="abc";    //"abc"存储在文字常量区,p是指向常量的指针,生存期到程序结束
     6     return p;
     7 }
     8 void main()
     9 {
    10     cout<<f()<<endl;
    11 }

    结果:

    3.动态分配存储空间,存储在堆区

     1 #include<iostream>
     2 using namespace std;
     3 char *f()
     4 {
     5     char *p=new char[5];  //动态分配存储空间,p指向堆区
     6     strcpy(p,"abc");   // 这里不能用p="abc",前面已经说明
     7     return p;
     8 }
     9 void main()
    10 {
    11     cout<<f()<<endl;
    12 }

    结果:

     e.指针做形参

    即所谓的地址传递,我们都知道地址传递的方式,形参的改变会导致实参的改变,但要注意的是,这里的改变是指指针所指内容的改变,而不是指针值的改变。因此,当形参改变会导致实参改变时,指针所指的内容是非const类型的,否则会出错。

    1.改变指针内容:

    1 void swap(int *a,int *b)   //交换的是*a,*b,即指针的内容,而不是指针a,b
    2 {
    3    int t;
    4    t=*a;
    5    *a=*b;
    6    *b=t;
    7 }

    2.改变指针值:

     1 #include<iostream>
     2 using namespace std;
     3 void fun(char *p)
     4 {
     5     p="cba";    //“cba”存放在文字常量区,让p指向常量"abc",这里改变的是指针值,实参并不会改变
     6 }
     7 void main()
     8 {
     9     char *p="abc";  //“abc”存放在文字常量区,p指向常量"abc"
    10     fun(p);
    11     cout<<p<<endl;   //输出"abc",而不是"bca"
    12 }

    结果:

    继续看下面的情况,修改指针的内容:

     1 #include<iostream>
     2 using namespace std;
     3 void fun(char *p)
     4 {
     5     p[0]='c';    //改变p的内容,即修改p[0]
     6 }
     7 void main()
     8 {
     9     char *p="abc";  //p指向常量"abc"
    10     fun(p);
    11     cout<<p<<endl;   //error,p所指内容为常量,不能修改
    12 }

    结果:

    注:p="ab"和strcpy(p,"ab"),含义不一样,前者指针p指向常量“ab”存储区域的首地址,改变了p最开始指向的new申请的内存空间;而后者是将“ab”分配到new申请的内存空间中;

  • 相关阅读:
    分布式事务的四种解决方案
    uber-go/guide 的中文翻译
    域名解析-CNAME
    Nginx节点存活状态检查
    Laravel核心解读--中间件(Middleware)
    Mac dyld: Library not loaded: /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib
    前缀树算法实现路由匹配原理解析
    原创-实用salt部署文档(持续更新)
    线上案例-调参-设置滑动窗口提高视频云播放性能
    NGINX日志割切
  • 原文地址:https://www.cnblogs.com/mrlsx/p/5419030.html
Copyright © 2011-2022 走看看