首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【答疑解惑】常量字符串引发的“血案”

【答疑解惑】常量字符串引发的“血案”

作者头像
程序员互动联盟
发布2018-03-14 15:05:04
6990
发布2018-03-14 15:05:04
举报
有朋友在《程序员互动联盟》QQ群里问了如下一个问题,见下的QQ截图图:

上图与下面这个图中,请注意main函数中s1和s2这两个变量。一个定义为指针,一个定义为数组。他的问题是:为什么下图中用数组定义的能正常运行,但是上图中用指针定义的取运行出错!

看起来差不多的程序,但是第一个能正常运行,第二个却不能运行,为什么呢?

要正确理解这个问题,需要了解C语言中变量及常量的存储位置,这个其实在咱们程序员互动联盟里面以前的文章中应该也讲到过,一直阅读和关心的朋友应该看到过。

这里我再简单重复一下,C语言变量分为BSS段,数据段和栈区;而常量数据则会被编译器放到文本段,这个段实际上跟代码段在一起。你分析执行程序时常常会看到一个.text或者.code。这个段默认是只读的,也就是你不能去改写它。

上面两部分程序的关键在main函数中定义的

char *s1 = “china”, *s2 = “ch”;

char s1[] = “china”, s2[] = “ch”;

按第一种方式,s1和s2本身是一个栈中的变量,但它们指向的字符串都放在代码段中,是一个只读的内存块,所以这种情况下,要用第二个字符串去逐个替换时,操作系统会检查到目标内存是一个只读属性的存储单元,会给程序返回一个异常,于是我们就看到下面这个出错的对话框了。

对于第二中方式,在编译的时候,同样会把两个字符串放到某个只读区。但是关键点来了,s1和s2是数组,他们的内存空间也是分配在栈中的,由于这两个变量在分配时同时需要用常量初始化的,所以在变量空间在栈中分配好后,编译器会做额外的工作,它会自动把那个只读的字符串拷贝过来初始化这个栈中的变量,于是这个变量就有了我们看到的初始值,实际上这个时候在进程的内存映像中有两份。既然是栈中的空间,默认就是可读写的,所以这种情况就可以对s1进行写了。由于只是对s1进行写操作,对s2只有读的要求,所以s2用第一种还是第二种都可以。

如果要对以上做更深入的理解,你需要知道进程的虚拟内存以及物理存储映射相关的知识。对于初学者,只要知道C语言中字符常量编译在只读区,不能写即可。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2015-09-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员互动联盟 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档