一个字符串常量实验引发的思考
2015-08-29 16:48
239 查看
一、实验回顾
有这么一段程序(编译环境 vs 2013),如下:#include "stdafx.h" int _tmain(int argc, _TCHAR* argv[]) { char a[] = "abc"; char b[] = "abc"; char* pstr1 = "abc"; char* pstr2 = "abc"; if (a==b) { printf("true\n"); } else { printf("false\n"); } if (pstr1==pstr2) { printf("true\n"); } else { printf("false\n"); } return 0; }
这段程序意图很明显,将字符串常量分别赋值给数组和指针,然后试图通过==判断是否相等(这里当然是判断地址是否相等,你不会想到判断值相等去了吧 - -!)。对于a==b,我分析对了,它们确实不相等。但是pstr1==pstr2,它们居然相等!
我将a,b ,pstr1,pstr2的地址打印了出来,如下图所示:
很遗憾的是,它们确实相等,地址都是2119768。但是这是为什么呢?搜了一下,发现了答案,因为字符串常量分配在了静态存储区!下面是关于内存基本构成的一段解释:
可编程内存在基本上分为这样的几大部分:静态存储区、堆区和栈区。
静态存储区:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。它主要存放静态数据、全局数据和常量。
栈区:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
堆区:亦称动态内存分配。程序在运行的时候用malloc或new申请任意大小的内存,程序员自己负责在适当的时候用free或delete释放内存。动态内存的生存期可以由我们决定,如果我们不释放内存,程序将在最后才释放掉动态内存。 但是,良好的编程习惯是:如果某动态内存不再使用,需要将其释放掉,否则,我们认为发生了内存泄漏现象。
好,现在再回到我们的程序中来。我们将字符串常量"abc"赋值给了数组a和b,其实是将"abc"拷贝到了a,b所在内存中,很显然这里的内存是栈区。因为a,b所占内存不同,所以a==b的结果是false。当我们将字符串常量"abc"赋值给了指针pstr1和pstr2后,其实是将指针指向了"abc"所在存储位置---静态存储区(因为指针pstr1和pstr2并没有通过new/malloc分配内存)。由于赋值给pstr1和pstr2的"abc"都是同一个常量,所以尽管它们赋值给了两个不同的指针,其实都是同一个"abc"。既然pstr1和pstr2指向的都是同一个"abc",那么pstr1==pstr2为true就很好理解了!
当我们把赋值给pstr2的字串改成"abcd"时,由于"abc"和"abcd"显然是两个不同的常量,所以存储位置肯定不同,那么pstr1肯定就不等于pstr2了,如下所示:
#include "stdafx.h" int _tmain(int argc, _TCHAR* argv[]) { char* pstr1 = "abc"; char* pstr2 = "abcd"; if (pstr1==pstr2) { printf("true\n"); } else { printf("false\n"); } printf("%d\n", pstr1); printf("%d\n", pstr2); return 0; }运行结果:
此外,由于指针指向的是字符串常量,所以一般用const修饰一下比较好:
const char* pstr1 = "abc";之所以这么做,是因为凡是指向"abc"的指针,都指向的同一块存储位置。你把"abc"赋值给数组,没关系,反正是要拷贝到各自数组中去的,所以你即使写下如下的语句也没关系(即把字串值改变):
a[0] = 'e';但是你通过指针改变字符串常量的值,那就很危险了,例如:
#include "stdafx.h" int _tmain(int argc, _TCHAR* argv[]) { char* pstr1 = "abc"; char* pstr2 = "abc"; pstr1[0] = 'e'; printf("%s\n",*pstr1); printf("%s\n", *pstr2); return 0; }这个程序运行时会报错,如图所示:
原因是"abc"是字符串常量,存放在静态存储区,不能修改。我们从逻辑上也好理解,很多指针都指向了"abc",你某个指针如果可以改动它的话,那别的指针岂不是要完蛋?
为了使程序更加健壮,所以我们给pstr1和pstr2加上const关键字:
const char* pstr1 = "abc"; const char* pstr2 = "abc";这样如果出现修改指针内容的语句,编译将不会通过,报错如下:
这样我们就可以及时发现bug并修正它。
参考文章:
1、静态存储区、堆和栈的区别2、常量字符串内存分配问题
3、C语音const关键字详解
相关文章推荐
- 无线安全的一些东西
- 理解ThreadLocal
- shader基础
- Catalan数
- 改变 Flash Recovery Area (FRA)到一个新路径的方法
- [LeetCode] 23 - Merge k Sorted Lists
- 我关注的一周技术动态 2015.08.30
- localhost与127.0.0.1的区别
- 使用Jedis源码生成Jedis.jar
- C++中map、hash_map、unordered_map、unordered_set通俗辨析
- 在Mac上制作树莓派SD镜像
- Intellij IDEA 修改字体
- Android 如何在Eclipse中查看Android API源码以及support包源码
- linux内核之字符驱动
- 【LeetCode】67. Add Binary
- ios的属性和成员变量在.h文件和.m文件的不同
- Python爬虫框架Scrapy教程(1)—入门
- 1063 -- 发奖学金咯^_^
- Genealogical tree(拓扑排序)
- UDP客户端实现在不同端口上发送和接收数据