zoukankan      html  css  js  c++  java
  • 一道 C++ 关于野指针和作用域的问题

    前言:

    前些天问了问了一道题:

    http://home.cnblogs.com/q/27511/ 

    结果网上的评价 都还是理解有点不对,这里记录下我试验的结果以及解决方案

    1.原题如下:问题是当p离开作用域时,不是应该p变成野指针么,为什么test函数输出依然正确?

    #include <iostream>
    using namespace std;
    class A{
        public:
        virtual void func(){ cout << "A func()" << endl;}
    };
    void test(){
        A* p;
        {
            A a;
            p = &a;
        }
        p->func();
    }
    int main()
    {
        test();
        return 0;
    }
    

    结果输出 A func()  

    如下回答:

    1. A的这个方法是关键。。

    因为这个方法内没有访问A的任务东东。也就是没有访问this指针。因此调用有效。

    如果方法中有访问A的字段就不行了。。

    这是不对的,下面的代码访问到了this指针,结果依然是输出a_i值

    #include <iostream>
    using namespace std;
    class A
    {
        private:
        int a_i;
        public:
        void func(){ cout << "A:a_i " << this->a_i << endl;}
        A(int i){this->a_i = i;}
    };
    void test(){
        A* p;
        {
            A a(5);
            p = &a;
        }
        p->func();
    }
    int main()
    {
        test();
        return 0;
    }
    

    输出为A a_i 5  

    将结果换成指针的生成方式换成new,也不行,没有什么本质区别

    class A
    {
        private:
        int a_i;
        public:
        void func(){ cout << "A:a_i " << this->a_i << endl;}
        A(int i){this->a_i = i;}
    };
    void test(){
        A* p;
        {
            p = new A(3);
        }
        p->func();
    }
    int main()
    {
        test();
        return 0;
    }
    

      输出为A a_i 5 

     关于作用域:

    作用域:a.func();已经出了作用域
    #include <iostream>
    using namespace std;
    class A{
        private:
        int a_i;
        public:
        void func(){ cout << "A:a_i " << this->a_i << endl;}
        A(int i){this->a_i = i;}
    };
    void test(){
        A* p;
        {
            A a(5);
            p = &a;
        }
        a.func();
        p->func();
    }
    int main()
    {
        test();
        return 0;
    }
    

      结果:编译不过去

    是不是野指针的问题,答案肯定是,看下面的

    class A
    {
        private:
        int a_i;
        public:
        void func(){ cout << "A:a_i " << this->a_i << endl;}
        A(int i = 0){this->a_i = i;}
    };
    int main()
    {
        A* p;//野指针
        p->func();
        return 0;
    }
    

      A 没有初始化,但是结果是: 

         A:a_i 0 

      这几天也在复习C++,想了想,其实,在C++ 对象模型 中 有这么一段话:

      类的非虚方法并不会存在于对象的内存布局中,实际上C++编译器将方法转化为全局函数,上面的会转化为: A_func_xxx (),而对象的指针是作为第一个参数被隐式的传递给了该函数,所以上面的p->func(); 调用的是全局函数A_func_xxx (),p作为this指针隐式的传递给了func()函数,所以结果是正确的

    下面有一个这样的回复:

    #include <iostream>
    using namespace::std;
    class A
    {
    private:
    int a_i;
    public:
    void func(){ cout << "A:a_i " << this->a_i << endl;}
    A(
    int i){this->a_i = i;}
    };
    void test(){
    A
    * p;
    {
    p
    = new A(3);
    delete p;
    }
    A
    * b=new A(23);
    cout
    << "==!!" << endl;
    p
    ->func();
    }
    int main()
    {
    test();
    return 0;
    }

       A* b=new A(23); 重新使用了先前分配的内存

    下面的回复有一个关于堆栈的问题,一直以为自己懂了:

    #include <iostream>

    using namespace std;

    //指针的地址是在栈中(首地址除外),但是指针指向的内容却在堆中,
    //所以并没有被清除

    char* get_str()
    {
    char* str = {"abcd"};
    return str;
    }
    //栈里面的变量都是临时的。当前函数执行完成时,
    //相关的临时变量和参数都被清除了,所以返回的指针指向的已经是随机的了
    //但是str[]首地址被当成指针来处理,存放在堆中。
    char* get_str2()
    {
    char str[] = {"abcd"};
    return str;
    }
    int main(int argc, char* argv[])
    {
    char* p = get_str();
    cout
    << *p << endl;
    cout
    << *(p+1) << endl;
    cout
    << p << endl;
    cout
    << "========================" << endl;

    char *p2 = get_str2();
    //第1次执行 *p2的时候,由于p2指针的首地址被返回了,还是可以取到*p2的内容的
    /*
    可以试试取*(p2+1),也是可以取到的
    */
    cout
    << *p2 << endl;

    //第一次调用*p2的时候还是有数据的,但是第2次就没有了,
    //说明cout之后指针已经被破坏了
    cout << *p2 << endl;
    cout
    << *(p2+1) <<endl;
    cout
    << *p2 << endl;
    cout
    << p2 << endl;
    return 0;
    }

      但是这个:答案是可以正确的运行,因为是常量字符串,存储在静态内存区中,返回没事,所以说,还得看清题啊 

    #include <iostream>
    #include
    <stdio.h>
    using namespace std;

    char *fun(void)
    {
    char *p="hello";
    return p;
    }
    int main(void)
    {
    char *s;
    s
    =fun();
    printf(
    "%s\n",s);
    }

      

  • 相关阅读:
    检测用户名和密码
    文本框赋值-数组的使用
    表单元素属性应用
    innerText和textContent区别以及兼容处理
    1.1自动化测试
    coockie & session
    springMVC 实现上传文件和下载文件
    el 表达式 显示错误 总结
    杭电oj_2063——过山车(java实现)
    关于java静态存储类的一个知识点
  • 原文地址:https://www.cnblogs.com/hitwtx/p/2143673.html
Copyright © 2011-2022 走看看