注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

落叶清风L的博客

努力向前

 
 
 

日志

 
 
 
 

小议数组名称和指针的区别  

2013-07-10 18:21:10|  分类: 指针和数组 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
     前些天,有个Geeker给我出道题,难了我几天,觉得十分有价值。题目是这样的:
 在a.c文件件里写了:
     #include <stdio.h>

     char array[10] = "Hello!";

     void testpoint();

     int main(int argc , char * argv[])
    {
         printf("%s\n",array);
         testpoint();
         return 0;
    }
在b.c文件里写了:
    #include <stdio.h>

    void testpoint()
   {
        extern char *array;
        printf("%s\n",array);
   }
然后一起编译:gcc a.c b.c -o test.out
然后执行:./test.out

    当时一口报出来输出结果:“都是'Hello!'吧".
    结果  当然是段错误了!~!也就是所谓的Access Volation.
    后来......我明白了。

其实:
    声明一个数组时,编译器将根据声明所指定的元素数量为数组保留内存空间,然后再去创建数组名。数组名是一个常量,指向这段空间的起始位置。它其实只是一个符号地址常量(一个指针常量,不能被更改的)而已。在编译时求值并且存在于编译器的常量符号表里面,它的值就是一个内存地址,所以可以认为程序没有给它分配存储空间,数组名仅仅只代表了那块存储空间。
    但是,指针就不一样了,指针指向一块存储空间,同时指针本身也存在于某个空间。可以认为数组名存在符号表里,对应这段空间的起始位置,指针变量名也存在符号表里,对应指针变量自己的地址。符号表是编译器用的,我们管不到;a和&a值是一样的,后者表示的是一个数据块单位。标准组织没有规定对数组名取地址是非法还是合法,所以因编译器而异。
   

    1.编译器对数组名和指针变量的处理方式:

    编译器在编译时会产生一个符号表,记录了符号名和它的地址,这对于指针变量,很好理解。而数组名就不那么明显,它仅仅是一个符号,没有地址的啊!!!所以,编译器是这样处理的,它记录下了array[0]的地址;这样就符合我们平常的理解了。

    2.带下标形式的数组和指针的寻址方式

    (1)数组情形
        char  a[10] = "Hello!";
        char h;
        ......
        h = a[i];
    在编译期,会在符号表中创建这样一条记录:
    name : a    address  : 8888
    要获取a[i]的值分两个步骤:
        step1:取得i的值并和8888相加;
        step2:在内存地址为(8888+i)的地方取出其内容;
    (2)指针情形
        char *p = "Hello!";
        char h;
        ......
        h = a[i];
    在编译期,会在符号表中创建这样一条记录:
        name : p    address : 9999
    要获取p[i]的值分三个步骤:
        step 1 : 在内存地址为9999的地方取出期内容,加入为“7887";
        step 2 : 取得i的值并和7887相加;
        step 3 : 在内存地址为(7887+i)的地方取其内容

    好了,现在我们有了这些知识,前面出现的情况就很容易解决了。在a.c中array是一个char类型的数组,那么在符号表中就会把array和array[0]的地址相关联起来,也即:
    name : array    address array[0]的地址  (当然,符号表不会这么写,这样大家好理解)
    而在b.c中,把array看做是一个char类型的指针。于是乎,按照上面所说的寻址方式,把符号表里的array的地址(即&array[0])的内容作为指针来寻找地址。这显然不对。结果如果当掉,那么你是幸运的。如果没有当掉,得到垃圾值,可能造成下面的代码本意全部错误!~!
    因为现行的操作系统都是运作在保护地址模式下的,对于内存的前一段和尾一段的内存都是限制使用的,连读的权限都没有!所以,程序会被当掉。

                                                                                                                                            ————参考《C专家编程》
                                                                                                                                            ————引用来自ChinaUnix dump_crash博文
                                                                                                                                            ————特别感谢陈志伟同学
  评论这张
 
阅读(65)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018