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

有朋友在《程序员互动联盟》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语言中字符常量编译在只读区,不能写即可。

原文发布于微信公众号 - 程序员互动联盟(coder_online)

原文发表时间:2015-09-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏小白的技术客栈

Python函数基础知多少

函数基础 简单地说,一个函数就是一组Python语句的组合,它们可以在程序中运行一次或多次运行。Python中的函数在其他语言中也叫做过程或子例程,那么这些被...

33011
来自专栏微信公众号:Java团长

Java异常处理和设计

在程序设计中,进行异常处理是非常关键和重要的一部分。一个程序的异常处理框架的好坏直接影响到整个项目的代码质量以及后期维护成本和难度。试想一下,如果一个项目从头到...

1013
来自专栏Linyb极客之路

深入理解和探究Java类加载机制

java.lang.ClassLoader类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个Java 类,即 ...

673
来自专栏游戏开发那些事

【小白学C#】浅谈.NET中的IL代码

  前几天群里有位水友提问:”C#中,当一个方法所传入的参数是一个静态字段的时候,程序是直接到静态字段拿数据还是从复制的函数栈中拿数据“。其实很明显,这和方法参...

762
来自专栏GreenLeaves

Jquery dom搜索之siblings()方法

      如果给定一个dom的元素集合的算则其对象,siblings()方法允许我们在dom树中搜索这个元素集合的同胞元素,并匹配这些元素构造一个新的对象,J...

1947
来自专栏猿人谷

PHP常用库函数介绍+常见疑难问题解答

      最近在苦学PHP,虽然PHP在整体功能上不如Java强大,但相比PHP而言Java算是较重量级的,所以在小中型系统的开发上,使用PHP的趋势不可挡,...

1848
来自专栏思考的代码世界

Python编程从入门到实践之函数2|第9天

向函数传递列表很有用,这种列表包含的可能是名字、数字或更复杂的对象(如字典)。将列表传递给函数后,函数就能直接访问其内容。

3567
来自专栏非著名程序员

常见面试题六之java系列

做Android开发最重要的是要有一个很好的java基础。所以在我们的面试过程中也会被经常问到有关java的问题,其实在小编看来,如果java基础不好,那开发起...

1756
来自专栏数据存储

MySQL中用快速为select结果加序号

set @a=0;select @a:=@a+1,user,host from mysql.user;

1895
来自专栏云霄雨霁

发布与逸出

983

扫码关注云+社区