zoukankan      html  css  js  c++  java
  • 文字常量区与栈区分析

    文字常量区与栈区分析

    首先看下下面这段:

     int main()
    
    {
        char *name = "fengkewei";
        char name1[] = "fengkewei";
        char *name2 = "fengkewei";
        char *name3 = "woaifengkewei";
        int i = 10;
        int j = 10;
        int k = 11;
    
        return 0;
    
    }

    若您觉得它们应该都保存在内存中的一块地方,那请往下看(事实上是保存在不同的地方)......

    下面是编译器为各个变量分配的内存地址,由于分配在栈上 所以地址是递减的

    ---------------------栈区------------------------------------
    +   &name 0x0013ff5c unsigned char * *
    +   &name1 0x0013ff48 unsigned char [10]*
    +   &name2 0x0013ff3c unsigned char * *
    +   &name3 0x0013ff30 unsigned char * *
    +   &i 0x0013ff24 int *
    +   &j 0x0013ff18 int *
    +   &k 0x0013ff0c int *
    ---------------------------------------------------------------


    &name 和&name1[] 相差20个字节 但"fengkewei"只有10个字节(带空字符)

    &name1[]和&name2 相差12个字节

    后面都正常了 都差12

    为什么是12?
    ————————————————————————————————————————————

    下面是各字符串的首地址,它们都在文字常量区里,相同的字符串地址也就相同了,不同则是递增分配的( 文字常量区也是递增分配的)

    ---------------------------文字常量区-------------------------------------------------
    +   name 0x004156b8 "fengkewei" unsigned char *
    +   name2 0x004156b8 "fengkewei" unsigned char *
    +   name3 0x00416010 "woaifengkewei" unsigned char *
    
    +   name1 0x0013ff48 "fengkewei" unsigned char [10]

    可见name1[]是在一个不同的地方的 也就是说它就是在栈上(name1[]字符串地址和name、name2地址不同

    现在我们设置一个整型指针

    int *p;

    p = &i;

    那p的地址应该是指向i的地址,指向栈区

    果然:

    +   &i 0x0013ff24 int *
    +   p 0x0013ff24 int *

    --------------------------------------------------------------------
    那当我设置一个字符型指针呢?

    char *p;
    
    p = name;
    
    +   &name 0x0013ff5c unsigned char * *
    +   name 0x004156b8 "fengkewei" unsigned char *
    +   p 0x004156b8 "fengkewei" unsigned char *

    p则指向的是字符串的地址,也就是指向文字常量区

    ------------------------------------------------------------------------------------------
    为什么&name与name的地址不同呢? 因为name是个字符型变量,该变量的空间分配在栈区,name指向的字符串在文字常量区,
    而name又是个字符型指针变量,它里面所保存的值即为字符串在文字常量区的地址,这也就是为什么指针指向的内容和指针自身
    的地址不同
    的原因了。

    可见 字符串常量是放在文字常量区的, 当你初始化赋值的时候 ,这些常量就先在文字常量区开辟一段空间,保存此常量。

    以后相同的常量就都在这里了。


    还有 char name1[] = "fengkewei";

    +   name1 0x0013ff48 "fengkewei" unsigned char [10]
    
    -   &name1 0x0013ff48 unsigned char [10]*
       [0] 102 'f' unsigned char
       [1] 101 'e' unsigned char
       [2] 110 'n' unsigned char
       [3] 103 'g' unsigned char
       [4] 107 'k' unsigned char
       [5] 101 'e' unsigned char
       [6] 119 'w' unsigned char
       [7] 101 'e' unsigned char
       [8] 105 'i' unsigned char
       [9] 0 unsigned char

    可以看出 name1始终是指向一个地址的 这个地址 就是栈区的地址 这就可以理解为什么书上说name1就是表示数组的首地址了。

    但后面的101,102,103,...代表什么呢?是ASCII码。

    看看文字常量区:

    +   name 0x004156b8 "fengkewei" unsigned char *
       name[0] 102 'f' unsigned char
       name[1] 101 'e' unsigned char
       name[2] 110 'n' unsigned char

    也就是说不管在栈区还是在文字常量区,都是这样保存的。

    但如果是这样呢:

    char name4[20];
    
    strcpy(name4, "fengkewei");
    
    +   &name4 0x0013fee4 unsigned char [20]*
    +   &name4[0] 0x0013fee4 "fengkewei" unsigned char *
    +   &name4[1] 0x0013fee5 "engkewei" unsigned char *
    +   &name4[2] 0x0013fee6 "ngkewei" unsigned char *
       name4[0] 102 'f' unsigned char
       name4[1] 101 'e' unsigned char

    可见 每个数组元素的地址都在栈区 而它们的值保存的都是相应的字符。也就是说 这个strcpy()并没有调用文字常量区的"fengkewei",
    而是直接把内容放在栈区name4[20]了.

    同样

    char name5[20] = "fengkewei";
    
    +   name4 0x0013fee4 "fengkewei" unsigned char [20]
    +   name5 0x0013fec8 "fengkewei" unsigned char [20]

    可见 这两种方式是将"fengkewei"保存在栈区的.

    最后总结下文字常量区的保存方式:

    char *name = "fengkewei";
    
    +   name 0x004156b8 "fengkewei" unsigned char *    //name的值是保存在文字常量区"fengkewei"的地址
    +   &name 0x0013ff5c unsigned char * *    //name自身的地址则被编译器分配在栈区
       name[0] 102 'f' unsigned char      //name的第一个字符值为'f'
    +   &name[0] 0x004156b8 "fengkewei" unsigned char *   //它保存在文字常量区
       name[1] 101 'e' unsigned char      //第二个字符为'e'
    +   &name[1] 0x004156b9 "engkewei" unsigned char *   //它也保存在文字常量区

    由此可见, 字符串常量, 按保存区域的不同分为以下几种:

    一种是保存在栈区, char name5[20] = "fengkewei";
       或 char name1[] = "fengkewei";

    一种保存在文字常量区, 即 char *name = "fengkewei";

    一种保存在全局区(静态区)(下次有机会再说。。。)

    最后一种保存在堆区,即用malloc, alloc, realloc 分配内存分配的区域,可由程序员自身分配和释放

    还有其他区:程序代码区 存放函数体的二进制代码。

    文章出处:http://hi.baidu.com/summy00/blog/item/501a16dae1fe96deb7fd487d.html

     常量解析:

      常量之所以称为“文字常量”,其中“文字”是指我们只能以它的值的形式指代它,“常量”是指它的值是不可变的。同时注意一点:文字常量是不可寻址的(即我们的程序中不可能出现获取所谓常量20的存储地址&20这样的表达式)虽然常量也是存储在内存的某个地方,但是我们没有办法访问常量的地址的。


    常量是有类型的:
    1、 字符型char:一个字节表示,通常表示单个字符或小整数,字符型常量用一对单引号‘ ’夹着一个字符表示。
    (1)可打印字符常量表示:
    ‘a’    ‘2’ ‘,’    ‘ ’
    字符常量在内存中的存储格式依赖于ASCП码表的。
    (2)不可打印字符常量,通过斜杠“/”表示:
    ‘/n’   换行符     ‘//’ 反斜杠 ‘/t’   水平制表符 ‘/0’ 空(NULL)字符


    2、 整型int:一个机器字长度的整数值。
    短整型short:半个机器字长度的整数值。
    长整型long:一个或两个机器字长度的整数值。
    在32位机器中,int和long通常相同。
    (1)上面提到的char字符型,也可看作长度为一个字节的字符型整数。
    通过下面这个小例子,可以看到char型数据,不同初始化方法,内存格式也是不同的。
    char a=’1’;
    cout<<a+1<<endl; //输出结果为50,参照ASC表,字符常量’1’在内存中是十进制数49
    char b=1;
     cout<<b+1<<endl;//输出结果为2


    实际上,字符常量还可以初始化int、long等类型数据,例如:
    int c=’1’;
    cout<<c+1<<endl;//输出结果也是50
    而:
    char a=’1’;
    cout<<a<<endl;//输出结果为1
    int a=’1’;
    cout<<a<<endl;//输出结果为49
    这些区别需要引起我们的注意。
    (2)整数常量可以使用十进制、八进制、十六进制表示,例如
           20(十进制)024(八进制)0x24(十六进制,也可写做0X24,“x”大小写无所谓)
    (3)整型常量可以有符号,也可以无符号,例如:
           一个8位有符号char:-128~127
           一个8位无符号char:0~255
    说明:缺省的整型常量是int型的,我们可以使用”L”或”l”后缀强制把整型常量表示成long型,另外也可加后缀”U”或”u”指定成无符号数,例如:128U、1024UL、1L、8Lu
    3、 浮点型float:一个字长度的单精度浮点数
    双精度double:两个字长度的双精度浮点数
    长双精度long double:3个或4个字长度的扩展精度浮点数
    (1)浮点常量可以写成科学计数法或普通十进制数
    (2)浮点常量缺省为double型,可以加后缀“F”“f”“L”“l”修饰为单精度浮点数或扩展精度浮点数,但是只能修饰十进制表示的浮点数。还有跟整型常量不一样的地方是,浮点数部分正负,也就是说不能使用“U”“u”后缀。
    例如:3.14159F 0.1f  12.345L        0.0    3e1  1.0E-3  1.0L
    4、 布尔常量boolean:true或false
    5、 字符串常量:比较特殊的一种类型,它不是内置或基本的数据类型,实际上就是字符常量数组,它由字符串文字本身以及编译器加上的表示结束的空(NULL)字符组成。
    字符串常量“Ab”在内存中的实际格式是’A’’b’’/0’
    如果程序中”two””Some”紧邻,C++编译器会把它们连在一起,并在最后加上一个空字符,即输出为”twosome”
    字符串常量还可换行表示,只需在换行的地方加上“/”,例如:
    “abc/
    de/
    fgh”
    实际上就是表示”abcdefgh”

    文章出处:DIY部落(http://www.diybl.com/course/3_program/c++/cppjs/20091021/179797.html 地址已失效)

  • 相关阅读:
    Web框架之Django_01初识(三大主流web框架、Django安装、Django项目创建方式及其相关配置、Django基础三件套:HttpResponse、render、redirect)
    前端Web框架的实现过程
    HTML、CSS 和 JS框架之Bootstrap
    前端之JQuery
    前端基础之JavaScript_2
    进程池、线程池、回调函数、协程
    前端基础之JavaScript_1
    前端基础之CSS_2
    前端基础之CSS_1
    前端基础之HTML
  • 原文地址:https://www.cnblogs.com/kimiway/p/3229596.html
Copyright © 2011-2022 走看看