字符串常量引起的思考

转载 2013年12月02日 17:48:47


  记得以前看过一道这样的题目:

  以下程序的执行结果是?

复制代码
#include <stdio.h>                                                          
  
int main()
{
       char* p="Hello World"; 
       *(p+1)='a'; 
       printf("%s\n",p);
       return 0; 
} 
复制代码

  应该不难吧,不知道大家的答案是什么。

  以下是我的一些解答:

    对于指针p,他的大小是sizeof(p),一般为4,至于他指向的对象的大小是sizeof(char),那么在哪里存放字符串“Hello World”呢?

  我们知道,程序编译时,编译器将代码翻译成汇编代码,然后汇编器将汇编代码翻译成机器代码(得到目标文件),最后链接器将目标文件链接成可执行文件。而目标文件和可执行文件的格式一般是类似的,由一个个section(段)组成,一般来说有代码段、数据段、bss段等,有些平台还会有.rodata段(只读数据段),用来放置只读变量(const变量)和字符串常量,这样不仅可以在语义上支持C++的const,而且操作系统还可以在加载的时候将.rodata映射为只读,这样对于这个段的修改会作为非法处理,保证了程序的安全。

  (1)在Linux下可以用objdump查看目标文件或可执行文件中的内容:  

objdump -x -s -d testchar

  得到的结果如下:

  

  (左边是十六进制内容,右边是ASCII形式的内容)

  可以看到字符串Hello World就在.rodata段中。

  (2)接下来我们使用readelf来查看.rodata段的属性:

    

  得到:

  

  其中.rodata段的标志(Flg)为A(alloc),表示该段在进程中要分配空间,如果一个段可写的话,应该要有W(write)标志,如数据段(.data):

    

  也就是说,现在字符串“Hello World”在不可写的.rodata中,如果我们用指针直接修改的话,就会引发段错误。

  所以程序的运行结果是:Segmentation fault 应该说在Linux 下用gcc编译后,程序运行结果是:Segmentation fault

  感谢@garbageMan的回复,确实,我说只是在gcc下的情况

@garbageMan:

很难说String literal 放在哪里
C语言并没有具体规定
放在哪里是编译器自己确定的
所以从一个编译结果推广到所有就是错误的

此外,C语言规定,修改String literal是一种UB
任何可能结果都有
不一定引发“段错误”

  (3)数组中的情况

  如果程序是这样呢:

复制代码
#include <stdio.h>                                                          

int main()
{
     char p[]="Hello World";
     *(p+1)='a'; 
     printf("%s\n",p);
     return 0; 
} 
复制代码

  程序是可以正常运行的。

  同样用objdump查看.rodata的内容:

  

  发现字符串已经不在.rodata中了。

  对于数组,我们可以直接分配空间,像上面的数组p就可以直接在栈中分配空间来存放字符串“Hello World”,这样就可以修改字符串了。

 

  以下内容我有点不肯定:

  查看text段(代码段)中的内容,发现字符串在text段中。

  

    所以我的猜想是程序执行时,先将text段中的字符串复制到数组p在栈中的分配的内存里,这样就可以对字符串修改同时又不影响代码段中的内容(因为代码段一般是只读   的)不知我这个猜想对不对,希望各位解答一下……同时这个问题也感谢 @buzzerrookie的提醒。


C风格字符串 C++string对象 字符串常量 字符串直接量

最大的区别就是C风格的字符串是静态的,不可以动态变化,使用极为麻烦。 而C++的std::string类型动态管理,非常方便。 C风格字符串和char数组是不一样的,看下面两种定义: cha...
  • sole_cc
  • sole_cc
  • 2015年06月13日 09:44
  • 1282

Java中的字符串常量池详细介绍

这篇文章主要介绍了Java中的字符串常量池详细介绍,JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池,需要的朋友可以参考下 ...
  • langhong8
  • langhong8
  • 2016年03月20日 19:20
  • 2459

JAVA中关于String类型的创建和字符串常量池的问题

在 JAVA 语言中有8中基本类型和一种比较特殊的类型String。这些类型为了使他们在运行过程中速度更快,更节省内存,都提供了一种常量池的概念。常量池就类似一个JAVA系统级别提供的缓存。  ...
  • tustyao
  • tustyao
  • 2016年05月23日 23:25
  • 2037

字符串常量引起的思考

字符串常量引起的思考   记得以前看过一道这样的题目:   以下程序的执行结果是? #include ...
  • indigogao
  • indigogao
  • 2013年06月07日 18:19
  • 288

函数的返回类型为指针类型时的若干思考(字符串常量问题)

By zieckey (http://blog.chinaunix.net/u/16292/index.html) 问题的引入: 看看下面的程序的输出: #inc...
  • zhongguoren666
  • zhongguoren666
  • 2011年11月22日 13:49
  • 3777

Java中的字符串常量池与Java中的堆和栈的区别

转载自:http://droidyue.com/blog/2014/12/21/string-literal-pool-in-java/ 最近做到一个题目: 问题:String str...
  • pengzhisen123
  • pengzhisen123
  • 2017年11月17日 11:18
  • 45

template学习之零值初始化及字符串常量作(function template argument)函数模版参数问题

本篇只是摘抄自《c++ template》小问题比较少注意,而且也容易忘记 1 零值初始化 对于基本的数据类型int,double,pointer type来说,一般没有default构造式对其初始化...
  • qingtianweichong
  • qingtianweichong
  • 2013年07月26日 20:59
  • 792

String类的内存解析——字符串常量池

package pers.songhongkang.chapter4.day09; //String类的内存解析,存在常量池中 public class TestString { public st...
  • mayanyun2013
  • mayanyun2013
  • 2016年05月30日 17:34
  • 703

字符串常量和字符数组的区分

首先我们来看个程序,这个程序说的是字符串函数strcat()函数的实现:#include #include #include #define MAX 20 char *my_strcat(char *...
  • qq_26768741
  • qq_26768741
  • 2016年04月16日 12:53
  • 645

Java的String类为什么是不可变的以及字符串常量池

JAVA中的String是一个不可变(immutable)类,即创建一个String对象后,是不能直接改变字符串中的某个字符的。 我们打开JDK中String类的源代码来看一下: /** The ...
  • u013303743
  • u013303743
  • 2016年03月02日 19:47
  • 720
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:字符串常量引起的思考
举报原因:
原因补充:

(最多只允许输入30个字)