zoukankan      html  css  js  c++  java
  • 【转】函数返回局部变量

    (看到C++ Primer(P.225)“return reference to local object”时有点懵,然后找到了这篇博文。)

    一般的来说,函数是可以返回局部变量的。 局部变量的作用域只在函数内部,在函数返回后,局部变量的内存已经释放了。因此,如果函数返回的是局部变量的值,不涉及地址,程序不会出错。但是如果返回的是局部变量的地址(指针)的话,程序运行后会出错。因为函数只是把指针复制后返回了,但是指针指向的内容已经被释放了,这样指针指向的内容就是不可预料的内容,调用就会出错。准确的来说,函数不能通过返回指向栈内存的指针(注意这里指的是栈,返回指向堆内存的指针是可以的)。
    1. 返回局部变量的值

    可以有两种情况:返回局部自动变量和局部静态变量,比如,

    int func()
    {
        int temp = 0;   // 返回局部自动变量的值
        return temp;
    }

    局部变量temp存储在栈中,函数返回时会自动复制一份temp的copy给调用者,没有问题。

    int func()
    {
        static int a = 1;   // 返回局部静态变量的值
        return a;
    }

    局部变量a存储在静态(全局)存储区中,从初始化后一直有效直到程序结束,仅分配一次内存,并且函数返回后,变量不会销毁,没有问题。

    vector func()
    {
        vector v;
        v.push_back(0);
        return v;
    }

    返回的是v的值拷贝,没有问题。

    Person func()
    {
        Person p1;
        p1.name = "test";
        return p1;
    }

    返回的也是值拷贝,会调用Person类的拷贝构造函数,没有问题。

    2. 返回局部变量的指针

    int* func()
    {
        int temp = 0;   // 返回局部变量的地址
        return &temp;
    }

    前面讨论过,局部变量temp存储在栈中,函数返回时将已销毁变量的地址返回给调用者,结果将是不可预知的。

    int* func()
    {
        static int temp = 1;
        return &temp;
    }

    局部变量temp存储在静态存储区,返回指向静态存储区变量的指针是可行的。

    char* func()
    {
        char *p = "test";
        return p;   // 返回指向常量字符串的指针
    }

    对于字符串的特殊情况,由于字符串test存储在常量存储区(不是静态存储区),因此函数返回一个指向常量的字符串指针是可行的。

    char* func()
    {
        char str[] = "test";
        return str; // 返回局部字符串的指针
    }

    这种情况下,str被初始化为字符串局部变量,因此函数返回一个已销毁的局部变量是不可行的。解决办法就是将字符串str声明为static。

    char* func()
    {
        char *str = (char *)malloc(sizeof(char) * BUFFER_SIZE);
        strcpy(str, "test");
        return str;
    }

    这种情况下,函数返回一个指向堆内存的指针,由于堆存储区由程序员手动管理,因此这种做法是可行的,但是要防止出现内存泄露,函数调用完后需要手动释放内存。这里的sizeof作用于指针返回的是指针类型的长度1byte,而如果作用于数组返回的则是数组的长度。

    char *temp = NULL;
    temp = func();
    // some operation...
    free(temp);

    3. 返回局部变量的引用

    int& func()
    {
        int temp = 0;   // 返回局部变量的引用
        return temp;
    }

    由引用的概念可知,函数返回的是temp本身,而temp在函数返回后已销毁,结果将是不可预知的。

    补充:静态全局变量和全局变量的区别

    静态全局变量只在当前文件中可用,全局变量在其他文件中也可用,需要用extern声明。

    全局变量和静态变量如果没有手动初始化,则默认由编译器初始化为0。

    1>

    #include    
    char *returnStr()   
    {   
        char *p="hello world!";   
        return p;   
    }   
    int main()   
    {   
        char *str;   
        str=returnStr();   
        printf("%s
    ", str);   
        return 0;   
    } 
    这个没有任何问题,因为"hello world!"是一个字符串常量,存放在只读数据段,把该字符串常量存放的只读数据段的首地址赋值给了指针,所以returnStr函数退出时,该该字符串常量所在内存不会被回收,故能够通过指针顺利无误的访问。

    2>

    #include <stdio.h>   
    char *returnStr()   
    {   
        char p[]="hello world!";   
        return p;   
    }   
    int main()   
    {   
        char *str;   
        str=returnStr();   
        printf("%s
    ", str);   
        return 0;   
    }   
    "hello world!"是局部变量存放在栈中。当returnStr函数退出时,栈要清空,局部变量的内存也被清空了,所以这时的函数返回的是一个已被释放的内存地址,所以有可能打印出来的是乱码。 

    3>

    int func()  
    {  
          int a;  
          ....  
          return a;    //允许  
    }                     
      
    int * func()  
    {  
          int a;  
          ....  
          return &a;    //无意义,不应该这样做  
    }   

    局部变量也分局部自动变量和局部静态变量,由于a返回的是值,因此返回一个局部变量是可以的,无论自动还是静态,

    因为这时候返回的是这个局部变量的值,但不应该返回指向局部自动变量的指针,因为函数调用结束后该局部自动变量

    被抛弃,这个指针指向一个不再存在的对象,是无意义的。但可以返回指向局部静态变量的指针,因为静态变量的生存

    期从定义起到程序结束。

     
    4>如果函数的返回值非要是一个局部变量的地址,那么该局部变量一定要申明为static类型。如下:
    #include <stdio.h>   
    char *returnStr()   
    {   
        static char p[]="hello world!";   
        return p;   
    }   
    int main()   
    {   
        char *str;   
         str=returnStr();   
        printf("%s
    ", str);   
      
        return 0;   
    }   
     
    5>数组是不能作为函数的返回值的,原因是编译器把数组名认为是局部变量(数组)的地址。返回一个数组一般用返回指向这个数组的指针代替,而且这个指针不能指向一个自动数组,因为函数结束后自动数组被抛弃,但可以返回一个指向静态局部数组的指针,因为静态存储期是从对象定义到程序结束的。如下:
    int* func( void )  
    {  
        static int a[10];  
        ........  
        return a;  
    }   

    6>返回指向堆内存的指针是可以的

    char *GetMemory3(int num)  
    {  
    char *p = (char *)malloc(sizeof(char) * num);  
    return p;  
    }  
    void Test3(void)  
    {  
    char *str = NULL;  
    str = GetMemory3(100);  
    strcpy(str, "hello");  
    cout<< str << endl;  
    free(str);  
    }  
    程序在运行的时候用 malloc 申请任意多少的内存,程序员自己负责在何时用 free释放内存。动态内存的生存期由程序员自己决定,使用非常灵活。
     
  • 相关阅读:
    DPDK安装方法 17.12.13
    numa.h:No such file or directory 解决方法
    17秋 软件工程 第六次作业 Beta冲刺 Scrum3
    17秋 软件工程 第六次作业 Beta冲刺 总结博客
    17秋 软件工程 第六次作业 Beta冲刺 Scrum2
    Paper Reviews and Presentations
    17秋 软件工程 第六次作业 Beta冲刺 Scrum1
    17秋 软件工程 第六次作业 Beta冲刺
    error: could not create '/System/Library/Frameworks/Python.framework/Versions/2.7/share': Operation not permitted
    17秋 软件工程 个人作业 软件产品案例分析
  • 原文地址:https://www.cnblogs.com/liez/p/5503805.html
Copyright © 2011-2022 走看看