• 一道关于返回指针和返回数组名的面试题


    先看一个例子:

    #include<iostream>

    usingnamespace std;

     

    char *fun(void)
    {
    char *p="hello the world";
    char buffer[] = "hello the world";
    return p; //这里为什么可以返回局部定义的指针?
    // return buffer; //这里为什么不可以返回局部定义的数组名?

    }

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

    这里返回的是指针的话程序可以正常输出,但返回数组名则不可以。

    因为字符串常量"hello the world"存放在文字常量区,可以理解为一个没有名字的静态变量(因为字符串常量很少需要修改,放在静态内存区会提高效率)。

    指针p指向了存放"hello the world"的文字常量区,所以可以正常返回。

    而这里buffer是在函数栈里面开辟了内存空间,里面的内容是用文字常量区的字符串的拷贝,buffer指向栈内存,

    fun函数调用结束后buffer指向的空间被操作系统收回,所以不能正常返回。

    我们在fun函数中添加两句:

    cout<<(void *)p<<endl;
    cout<<(void *)buffer<<endl;

    来测试p和buffer所指向的地址空间是否相同:

    输出为:

    0x402080
    0x22ac1c

    可以看出,这两个指针所值空间是不同的,p指向文字常量区,buffer指向栈区。

    下面引用一篇文章来作进一步说明:

    #include
      using namespace std;
      
      char *fun(void)
      {
       char *p = "hello the world";//字符串常量"hello the world"存放在文字常量区,
       char buffer[] = "hello the world";//这里buffer是在函数栈里面开辟了内存空间,里面的内容是用文字常量区的字符串的拷贝
       return p; //p指向存放"hello the world"的文字常量区
      // return buffer; //buffer指向栈内存,fun函数调用结束后buffer指向的空间被操作系统收回
       
      }
      
      int main(void)
      {
       char *s;
       s=fun();
       printf("%s\n",s);
       return 0;
      }
      
      -------------------------------------------------------------------------------
      char *c="chenxi";
      书上说: "chenxi"这个字符串被当作常量而且被放置在此程序的内存静态区。
      那一般的int i=1;
      1也是常量,为什么1就不被放置在此程序的内存静态区了呢?
      请高手指点!
      
      所有的字符窜常量都被放在静态内存区
      因为字符串常量很少需要修改,放在静态内存区会提高效率
      
      例:
      
      char str1[] = "abc";
      char str2[] = "abc";
      
      const char str3[] = "abc";
      const char str4[] = "abc";
      
      const char *str5 = "abc";
      const char *str6 = "abc";
      
      char *str7 = "abc";
      char *str8 = "abc";
      
      
      cout << ( str1 == str2 ) << endl;
      cout << ( str3 == str4 ) << endl;
      cout << ( str5 == str6 ) << endl;
      cout << ( str7 == str8 ) << endl;
      
      结果是:0 0 1 1
      str1,str2,str3,str4是数组变量,它们有各自的内存空间;
      而str5,str6,str7,str8是指针,它们指向相同的常量区域。
      
       
      
       
      
      问题的引入:
      看看下面的程序的输出:
      
      #include <stdio.h>
      char *returnStr()
      {
       char *p="hello world!";
       return p;
      }
      int main()
      {
       char *str=NULL;//一定要初始化,好习惯
       str=returnStr();
       printf("%s\n", str);
       
       return 0;
      }
      
      这个没有任何问题,因为"hello world!"是一个字符串常量,存放在静态数据区,
      把该字符串常量存放的静态数据区的首地址赋值给了指针,
      所以returnStr函数退出时,该该字符串常量所在内存不会被回收,故能够通过指针顺利无误的访问。
      
      但是,下面的就有问题:
      
      #include <stdio.h>
      char *returnStr()
      {
       char p[]="hello world!";
       return p;
      }
      int main()
      {
       char *str=NULL;//一定要初始化,好习惯
       str=returnStr();
       printf("%s\n", str);
       
       return 0;
      }
      "hello world!"是一个字符串常量,存放在静态数据区,没错,
      但是把一个字符串常量赋值给了一个局部变量(char []型数组),该局部变量存放在栈中,
      这样就有两块内容一样的内存,也就是说“char p[]="hello world!";”这条语句让“hello world!”这个字符串在内存中有两份拷贝,一份在动态分配的栈中,另一份在静态存储区。这是与前者最本质的区别,
      当returnStr函数退出时,栈要清空,局部变量的内存也被清空了,
      所以这时的函数返回的是一个已被释放的内存地址,所以打印出来的是乱码。
      
      如果函数的返回值非要是一个局部变量的地址,那么该局部变量一定要申明为static类型。如下:
      
      #include <stdio.h>
      char *returnStr()
      {
       static char p[]="hello world!";
       return p;
      }
      int main()
      {
       char *str=NULL;
       str=returnStr();
       printf("%s\n", str);
       
       return 0;
      }
      
      这个问题可以通过下面的一个例子来更好的说明:
      
      #include <stdio.h>
      //返回的是局部变量的地址,该地址位于动态数据区,栈里
      
      char *s1()
      {
       char* p1 = "qqq";//为了测试‘char p[]="Hello world!"’中的字符串在静态存储区是否也有一份拷贝
       char p[]="Hello world!";
       char* p2 = "w";//为了测试‘char p[]="Hello world!"’中的字符串在静态存储区是否也有一份拷贝
       printf("in s1 p=%p\n", p);
       printf("in s1 p1=%p\n", p1);
       printf("in s1: string's address: %p\n", &("Hello world!"));
       printf("in s1 p2=%p\n", p2);
       return p;
      }
      
      //返回的是字符串常量的地址,该地址位于静态数据区
      
      char *s2()
      {
       char *q="Hello world!";
       printf("in s2 q=%p\n", q);
       printf("in s2: string's address: %p\n", &("Hello world!"));
       return q;
      }
      
      //返回的是静态局部变量的地址,该地址位于静态数据区
      
      char *s3()
      {
       static char r[]="Hello world!";
       printf("in s3 r=%p\n", r);
       printf("in s3: string's address: %p\n", &("Hello world!"));
       return r;
      }
      
      int main()
      {
       char *t1, *t2, *t3;
       t1=s1();
       t2=s2();
       t3=s3();
       
       printf("in main:");
       printf("p=%p, q=%p, r=%p\n", t1, t2, t3);
      
       printf("%s\n", t1);
       printf("%s\n", t2);
       printf("%s\n", t3);
       
       return 0;
      }
      运行输出结果:
      
      in s1 p=0013FF0C
      in s1 p1=00431084
      in s1: string's address: 00431074
      in s1 p2=00431070
      in s2 q=00431074
      in s2: string's address: 00431074
      in s3 r=00434DC0
      in s3: string's address: 00431074
      in main:p=0013FF0C, q=00431074, r=00434DC0
      $
      Hello world!
      Hello world!
      
      这个结果正好应证了上面解释,同时,还可是得出一个结论:
      字符串常量,之所以称之为常量,因为它可一看作是一个没有命名的字符串且为常量,存放在静态数据区。
      这里说的静态数据区,是相对于堆、栈等动态数据区而言的。
      静态数据区存放的是全局变量和静态变量,从这一点上来说,字符串常量又可以称之为一个无名的静态变量,
      因为"Hello world!"这个字符串在函数 s1和s2 中都引用了,但在内存中却只有一份拷贝,这与静态变量性质相当神似。

  • 相关阅读:
    Redis源码分析(二十一)--- anet网络通信的封装
    leetcode 总结part1
    leetcode String to Integer (atoi)
    leetcode 165. Compare Version Numbers
    leetcode 189. Rotate Array
    leetcode 168. Excel Sheet Column Title
    leetcode 155. Min Stack
    leetcode 228. Summary Ranges
    leetcode 204. Count Primes
    leetcode 6. ZigZag Conversion
  • 原文地址:https://www.cnblogs.com/CBDoctor/p/2685926.html
Copyright © 2020-2023  润新知