• MIT 6.828 JOS学习笔记8. Exercise 1.4


    Lab 1 Exercise 4

      阅读关于C语言的指针部分的知识。最好的参考书自然是"The C Programming Language"。

      阅读5.1到5.5节。然后下载pointers.c的代码,并且编译运行它,确保你理解在屏幕上打印出来的所有的值是怎么来的。尤其要重点理解第1行,第6行的指针地址是如何得到的,以及在第2行到第4行的值是如何得到的,还有为什么在第5行打印出来的值看起来像程序崩溃了。

      答:

      首先编译运行文件pointer.c,得到如下结果:

      

      首先程序声明了3个重要的数组,指针

      int型数组--int a[4];    int类型指针--int *b = malloc(16);     int类型指针--int *c;

      打印的第一句:

        printf("1: a = %p, b = %p, c = %p ", a, b, c);    

      其中:

        a输出的是数组a的首地址,0xbfb4bf84。  

        b输出的是指针b所指向的操作系统分配给它的空间的起始地址,0x8886008

        c输出的是未定义的指针变量c的值,0xb75d8255

      打印第二句之前,完成的操作:

        c = a;  让c指针和a指向同一个内存地址,0xbfb4bf84;

        for(i = 0; i<4; i++) a[i] = 100+i;   这个操作会让数组a的四个单元的值变为,100,101,102,103。

        c[0] = 200;   由于c和a指向同一个地方,c[0] = a[0] = 200;

        printf("2: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d,", a[0], a[1], a[2], a[3]); 所以打印第二句,第一个元素的值会是200.

      打印第三句之前,完成操作:

        c[1] = 300;

        *(c+2) = 301;

        3[c] = 302;

        分别代表访问数组中的值的三种不同的方法。由于c和a相同,所以它们也是在修改数组a的值。把a[1], a[2],a[3]全都被改变。printf("3: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d,", a[0], a[1], a[2], a[3]);

      打印第四句前,完成操作:c = c+1; 

        将指针c指向数组中下一个单元,即a[1]

        *c = 400

         修该a[1]值为400

         printf("4: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d,", a[0], a[1], a[2], a[3]);

      打印第五句前,完成操作

         c = (int *)((char *)c + 1);

        先把c强制转换为char类型指针,然后指针加1,此时c的数值应该也加1,由于之前c指向a数组中1号元素的起始地址,1号元素起始地址为0xbfb4bf88,之后加1,变为0xbfb4bf89。然后再把c强制转换回int类型指针,此时c所操作的地址为0xbfb4bf89~0xbfb4bf8c。

        *c = 500

        把地址地址为0xbfb4bf89~0xbfb4bf8c的值换为500,此时会影响原来数组a的1,2号元素。原来一号元素在内存中存放在地址0xbfb4bf88~0xbfb4bf8b处,存放的值为400,十六进制为0x00000190

         0xbfb4bf88  0xbfb4bf89  0xbfb4bf8a  0xbfb4bf8b     

          90                 01                 00                00 

         原来二号元素在内存中存放在地址0xbfb4bf8c~0xbfb4bf8f处,存放的值为301,十六进制为0x0000012D。

         0xbfb4bf8c  0xbfb4bf8d  0xbfb4bf8e  0xbfb4bf8f 

           2D                 01                 00                00 

        而现在c操作的地址为0xbfb4bf89~0xbfb4bf8c,并赋值500,十六进制为0x000001F4,所以内存单元变为

        0xbfb4bf88  0xbfb4bf89  0xbfb4bf8a  0xbfb4bf8b     

         90                 F4                 01                00 

        0xbfb4bf8c  0xbfb4bf8d  0xbfb4bf8e  0xbfb4bf8f     

        00                 01                 00                00 

        所以此时a[1]的值变为0x0001F490 = 128144, a[2]的值变为0x00000100 = 256.

        打印第六句前,完成操作:

        b = (int *)a + 1;

          这步操作会把b的值加1,由于b现在是int类型指针,所以数值上b的值增加4,所以b的值变为 0xbfb4bf84 + 0x4 = 0xbfb4bf88

        c = (int *)((char *)a+1);

          这步还是先把a转换为char型指针,然后加1,此时加1会让数值上只增加1,所以c的值变为 0xbfb4bf84 + 0x1 = 0xbfb4bf85

       当然运行在你的机器上,这些地址的值一定和我的不一样,但是原理是相同的。

     

  • 相关阅读:
    C# partial 作用
    C#中internal关键字是什么意思?什么叫做“只能在包含它的程序集中访问该方法”
    [转]利用.NET中的反射机制实现IList到DataTable的转换
    你可能已经知道或者不知道的ASP.NET 2.0技巧
    SQL Server基本函数详细介绍--字符串函数
    在Web.config配置文件中自定义配置节点
    SQL SERVER事务处理
    专用于SqlServer2005的高效分页存储过程(支持多字段任意排序,不要求排序字段唯一)
    SQL SERVER 高效存储过程分页(Max/Min方法)
    该字符串未被识别为有效的 DateTime
  • 原文地址:https://www.cnblogs.com/fatsheep9146/p/5216735.html
Copyright © 2020-2023  润新知