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

FY

Johnson 's Blog

 
 
 

日志

 
 

数组与指针的不同  

2014-07-31 12:14:13|  分类: C Programming L |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |


最近被问到了数组和指针的不同点,

为了清楚的说明写了如下两个.c文件,并通过反汇编进行详细解释

 

/////////////////////////////////////////////////////////////////////////////////////////////////////

t1.c

#include <stdio.h>

 

char arr[] = "hello,world";

 

void print_arr(void)

{

        printf("arr addr:%p\n",arr);

        printf("arr[1] is :%c\n",arr[1]);

}

 

t2.c

#include <stdio.h>

 

extern char *arr; //注意它和 extern char arr[]; 的不同

extern void print_arr(void);

 

 

int main()

{

 

print_arr();

printf("%c\n",arr[1]);

 

}

 

 

以下是反汇编的结果,只是为了证明我的观点,不明白可以直接略过,跳至★★★处

/////////////////////////////////////////////////////////////////////////////////////////////////////

Section Headers:

  [Nr] Name              Type             Address           Offset

  [13] .text             PROGBITS         00000000004003e0  000003e0

       0000000000000228  0000000000000000  AX       0     0     16

  [14] .fini             PROGBITS         0000000000400608  00000608

       000000000000000e  0000000000000000  AX       0     0     4

  [15] .rodata           PROGBITS         0000000000400618  00000618

  [24] .data             PROGBITS         0000000000600900  00000900 // .data section loading address is 0x0000000000600900

       0000000000000010  0000000000000000  WA       0     0     4 // “hello,world\0”

 

/////////////////////////////////////////////////////////////////////////////////////////////////////

 

Symbol table '.symtab' contains 67 entries:

   Num:    Value          Size Type    Bind   Vis      Ndx Name

    58: 0000000000600904    12 OBJECT  GLOBAL DEFAULT   24 arr // arr[] ‘s address is  0x0000000000600904

/////////////////////////////////////////////////////////////////////////////////////////////////////

 

Hexdump –C a.out

 

00000900  00 00 00 00 68 65 6c 6c  6f 2c 77 6f 72 6c 64 00  |....hello,world.|

 

/////////////////////////////////////////////////////////////////////////////////////////////////////

 

Program Headers:

  Type           Offset             VirtAddr           PhysAddr

                 FileSiz            MemSiz              Flags  Align

  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040

                 0x00000000000001c0 0x00000000000001c0  R E    8

  INTERP         0x0000000000000200 0x0000000000400200 0x0000000000400200

                 0x000000000000001c 0x000000000000001c  R      1

      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]

  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000

                 0x0000000000000714 0x0000000000000714  R E    200000

  LOAD           0x0000000000000718 0x0000000000600718 0x0000000000600718

                 0x00000000000001f8 0x0000000000000208  RW     200000

 

/////////////////////////////////////////////////////////////////////////////////////////////////////

00000000004004c4 <print_arr>: //定义和编译于 t1.c文件中

  4004c4:       55                      push   %rbp

  4004c5:       48 89 e5                mov    %rsp,%rbp

  4004c8:       b8 28 06 40 00          mov    $0x400628,%eax

  4004cd:       be 04 09 60 00          mov    $0x600904,%esi  // 将数组arr的地址0x600904 直接传参给printf函数

  4004d2:       48 89 c7                mov    %rax,%rdi

  4004d5:       b8 00 00 00 00          mov    $0x0,%eax

  4004da:       e8 d9 fe ff ff          callq  4003b8 <printf@plt>

  4004df:       0f b6 05 1f 04 20 00    movzbl 0x20041f(%rip),%eax        # 600905 <arr+0x1> //对数组进行取值 arr[1]的方式,编译器则直接将 0x600905(0x600904 +1)地址中的内容取出

  4004e6:       0f be d0                movsbl %al,%edx

  4004e9:       b8 35 06 40 00          mov    $0x400635,%eax

  4004ee:       89 d6                   mov    %edx,%esi

  4004f0:       48 89 c7                mov    %rax,%rdi

  4004f3:       b8 00 00 00 00          mov    $0x0,%eax

  4004f8:       e8 bb fe ff ff          callq  4003b8 <printf@plt>

  4004fd:       c9                      leaveq

  4004fe:       c3                      retq

  4004ff:       90                      nop

 

0000000000400500 <main>:

  400500:       55                      push   %rbp

  400501:       48 89 e5                mov    %rsp,%rbp

  400504:       e8 bb ff ff ff          callq  4004c4 <print_arr>

  400509:       48 8b 05 f4 03 20 00    mov    0x2003f4(%rip),%rax        # 600904 <arr>  //arr[]数组的地址(0x600904)当作指针变量自己的地址,取其中的内容赋给临时寄存器‘0x68’

  400510:       48 83 c0 01             add    $0x1,%rax                 // ‘0x68’ +1   => 0x69

 

  400514:       0f b6 00                movzbl (%rax),%eax              //取出‘0x69’地址中的内容 ,会发生 segmentation fault错误

  400517:       0f be d0                movsbl %al,%edx                 //

  40051a:       b8 44 06 40 00          mov    $0x400644,%eax

  40051f:       89 d6                   mov    %edx,%esi

  400521:       48 89 c7                mov    %rax,%rdi

  400524:       b8 00 00 00 00          mov    $0x0,%eax

  400529:       e8 8a fe ff ff          callq  4003b8 <printf@plt>

  40052e:       c9                      leaveq

  40052f:       c3                      retq

 

 

////////////////////////////////////////////////////////////

[root@localhost c]# ./a.out

arr addr:0x600904

arr[1] is :e

Segmentation fault (core dumped) //是由访问0x69地址的内容造成的

 

////////////////////////////////////////////////////////////

 

★★★

制作了一张图,方便说明

如果你声明了 char * p = arr;

 或者 char * p = &arr[0];

那么针对 p[1]这么一个动作

编译器会作出如下的操作

(1)   找到P这个变量本身存储的地址(0x600901)

(2)   取出P变量的内容 (0x600904)

(3)   对内容进行偏移offset ( +1 ) 0x600905

(4)   对偏移后的地址进行取内容

即,对0x600905地址进行取内容

 

 

t1.c中,定义了一个数组arr[],并且对这个数组进行 arr[1]

编译器会作出如下操作

(1)     得到arr的地址 (0x600904)

(2)     直接进行偏移offset (+1) 0x600905

(3)     偏移后进行取地址中的内容

 

最后,我们来分析t2.c中的情况

由于声明了extern char * arr;

所以单就t2.c进行编译时,

编译器会作出上述P一样的动作:

(1)   这出arr这个变量本身存储的地址(0x600904)

(2)   取出arr地址中的内容 (0x68 : ‘h’)

(3)   对内容进行偏移 (+1) : 0x69

(4)   对偏移后的地址进行取内容

即对 0x69的地址进行取内容,会造成段错误


数组与指针的不同 - FY - FY

 

  评论这张
 
阅读(105)| 评论(0)
推荐 转载

历史上的今天

评论

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

页脚

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