玩转常量字符串
2015-05-05 11:26
155 查看
1.Reference: http://hi.baidu.com/benzhan/item/8c52be37ca4c9bd76c15e9f9
warning: 原文没有参考文献
2.
先撸段代码来看看
*注:以上bool型的cout我在gcc下编译没通过,不清楚原作者是用什么编译器:(
因此,引用作者的程序结果,是:0 0 1 1
str1,str2,str3,str4是数组变量,它们有各自的内存空间;
而str5,str6,str7,str8是指针,它们指向相同的常量区域。
再来一段代码会更清楚点。
运行结果是
看出点问题了吗?以下我将原作者的思想用我的话以及我的程序结果来表述一下。
(1)因为”pointer”是一个字符串常量,存放在静态数据区,把该字符串常量存放的静态数据区的首地址赋值给了指针temp,所以returnStr_P函数退出时,该字符串常量所在内存不会被回收,故能够通过指针顺利无误的访问。
(2)“array“依然也是一个字符串常量,依然存放在静态数据区,但是把一个字符串常量赋值给了一个局部变量(char型数组temp),该局部变量存放在栈中,这样就有两块内容一样的内存,也就是说“char temp[]=”array”;”这条语句让“array”这个字符串在内存中有两份拷贝,一份在动态分配的栈中,另一份在静态存储区。这是与returnStr_P()最本质的区别。当returnStr_A函数退出时,栈要清空,局部变量的内存也被清空了,所以这时的函数返回的是一个已被释放的内存地址,所以打印出来的是乱码。其实强大的gcc已经给了warning了:
(3)针对前两点总结下,就是虽然returnStr_P()与returnStr_A()返回的都是一个内存地址,但是returnStr_A()中temp是先将”array” copy一份在自己的内存地址上,当函数结束时,栈空间释放,该地址上自然没用内容给str_a了。而由此我做个推断(如果有误还望细心的读者指出),起码静态存储区上的生命周期是整个程序。( PS. 经过小心求证后结果确实是如此:) )
(4)如果非得要返回局部变量的地址,那么该局部变量一定要申明为static类型,强行将temp申明为静态变量,存储于静态存储区。相信从上面的代码可以清楚的体验出来。
3.重点来了
原作者的中心思想看似有理有据,但是在没有参考文献的前提下我还是抱着半信半疑的态度翻阅了其他的一些资料,终于在 欧立奇等. 程序员面试宝典. 电子工业出版社 中找到了一些解释。
内存的分配方式有5种:静态存储区、栈区、堆区、文字常量区、程序代码区。静态存储区,内存在编译时已经分配好空间,并且生命周期为整个程序,例如全局变量、static变量。文字常量区,常量字符串就是存放在此处,生命周期也是整个程序,待程序结束后由系统释放,例如int i = 123; char *p = “hello”; 等,等号右边的这些常量均试存放再文字常量区的。这与该作者的“存放在静态存储区“有些出入。而我本人还是愿意选择更加相信后者。但我觉得通过此次,解释了平日的一些困惑,总之该作者的主思想是正确的,就是对于字符串常量的存放位置可能理解方面有些不同。仁者见仁智者见智。
以上。
warning: 原文没有参考文献
2.
先撸段代码来看看
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;
*注:以上bool型的cout我在gcc下编译没通过,不清楚原作者是用什么编译器:(
因此,引用作者的程序结果,是:0 0 1 1
str1,str2,str3,str4是数组变量,它们有各自的内存空间;
而str5,str6,str7,str8是指针,它们指向相同的常量区域。
再来一段代码会更清楚点。
#include <stdio.h> char *returnStr_P() { char *temp = "pointer"; return temp; } char *returnStr_A() { char temp[] = "array"; return temp; } char *returnStr_A_S() { static char temp[] = "static array"; return temp; } int main() { char *str_p = NULL; char *str_a = NULL; char *str_a_s = NULL; str_p = returnStr_P(); str_a = returnStr_A(); str_a_s = returnStr_A_S(); printf("str_P = %s\n", str_p); printf("str_a = %s\n", str_a); printf("str_a_s = %s\n", str_a_s); return 0; }
运行结果是
str_P = pointer str_a = ����Зc���8�}� str_a_s = static array
看出点问题了吗?以下我将原作者的思想用我的话以及我的程序结果来表述一下。
(1)因为”pointer”是一个字符串常量,存放在静态数据区,把该字符串常量存放的静态数据区的首地址赋值给了指针temp,所以returnStr_P函数退出时,该字符串常量所在内存不会被回收,故能够通过指针顺利无误的访问。
(2)“array“依然也是一个字符串常量,依然存放在静态数据区,但是把一个字符串常量赋值给了一个局部变量(char型数组temp),该局部变量存放在栈中,这样就有两块内容一样的内存,也就是说“char temp[]=”array”;”这条语句让“array”这个字符串在内存中有两份拷贝,一份在动态分配的栈中,另一份在静态存储区。这是与returnStr_P()最本质的区别。当returnStr_A函数退出时,栈要清空,局部变量的内存也被清空了,所以这时的函数返回的是一个已被释放的内存地址,所以打印出来的是乱码。其实强大的gcc已经给了warning了:
test.c: In function ‘returnStr_A’: test.c:12:2: warning: function returns address of local variable [-Wreturn-local-addr] return temp; ^
(3)针对前两点总结下,就是虽然returnStr_P()与returnStr_A()返回的都是一个内存地址,但是returnStr_A()中temp是先将”array” copy一份在自己的内存地址上,当函数结束时,栈空间释放,该地址上自然没用内容给str_a了。而由此我做个推断(如果有误还望细心的读者指出),起码静态存储区上的生命周期是整个程序。( PS. 经过小心求证后结果确实是如此:) )
(4)如果非得要返回局部变量的地址,那么该局部变量一定要申明为static类型,强行将temp申明为静态变量,存储于静态存储区。相信从上面的代码可以清楚的体验出来。
3.重点来了
原作者的中心思想看似有理有据,但是在没有参考文献的前提下我还是抱着半信半疑的态度翻阅了其他的一些资料,终于在 欧立奇等. 程序员面试宝典. 电子工业出版社 中找到了一些解释。
内存的分配方式有5种:静态存储区、栈区、堆区、文字常量区、程序代码区。静态存储区,内存在编译时已经分配好空间,并且生命周期为整个程序,例如全局变量、static变量。文字常量区,常量字符串就是存放在此处,生命周期也是整个程序,待程序结束后由系统释放,例如int i = 123; char *p = “hello”; 等,等号右边的这些常量均试存放再文字常量区的。这与该作者的“存放在静态存储区“有些出入。而我本人还是愿意选择更加相信后者。但我觉得通过此次,解释了平日的一些困惑,总之该作者的主思想是正确的,就是对于字符串常量的存放位置可能理解方面有些不同。仁者见仁智者见智。
以上。
相关文章推荐
- 具有相同值的不同字符串常量在内存中是分开存储的
- 常量,数,字符串,标识符,数据类型
- objc系列译文(9.2):玩转字符串
- JAVA String对象和字符串常量的关系解析
- Go语言学习二:Go基础(变量、常量、数值类型、字符串、错误类型)
- 关于常量字符串的问题
- 玩转字符串
- 常量字符串为什么位于静态存储区?
- 秘籍总结:玩转python里的字符串上篇
- Python入门(二)——IDE选择PyCharm,输入和输出,基础规范,数据类型和变量,常量,字符串和编码,格式化
- String字符串常量相加和new对象
- 字符串常量演示Demo
- 玩转字符串 count letter
- VC编译字符串常量是否合并
- 变量、常量、字符串
- 编译期强制函数参数为字符串常量
- 初学PHP 之常量,字符串
- C/C++ 常量字符串
- 常量数组处理字符串
- iOS开发小技巧--富文本字典集合中的Key都是OC中的常量字符串