字符串常量引起的思考

转载 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的提醒。


相关文章推荐

字符串常量引起的思考

字符串常量引起的思考   记得以前看过一道这样的题目:   以下程序的执行结果是? #include ...

字符串常量引起的思考

http://www.cnblogs.com/-Lei/archive/2013/01/12/2858027.html 记得以前看过一道这样的题目:   以下程序的执行结果是? #inc...

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

By zieckey (http://blog.chinaunix.net/u/16292/index.html) 问题的引入: 看看下面的程序的输出: #inc...

字符串常量放在内存中的静态存储区

一、在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。 栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函...
  • glx2012
  • glx2012
  • 2013年04月08日 13:39
  • 957

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

首先我们来看个程序,这个程序说的是字符串函数strcat()函数的实现:#include #include #include #define MAX 20 char *my_strcat(char *...

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

package pers.songhongkang.chapter4.day09; //String类的内存解析,存在常量池中 public class TestString { public st...

对字符串常量 的理解

常量存储总结 局部变量、静态局部变量、全局变量、全局静态变量、字符串常量以及动态申请的内存区1、局部变量存储在栈中2、全局变量、静态变量(全局和局部静态变量)存储在静态存储区3、new申请的内存是在堆...
  • a199228
  • a199228
  • 2011年07月29日 11:17
  • 5877

字符串常量和变量

写代码的时候,发现对字符串常量改变的问题。网上找了一下资料,明白了 出处:http://blog.csdn.net/andylyc/archive/2008/01/16/2046225.aspx...

C++的字符串常量

浅析c++的字符串常量。

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

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

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