C中的数组与指针问题

  反复在数组名与指针上犯错误,特记录下。

  int a[] = {1,2,3,4,5};

  int *p, *q;

  p = (int *)(a+1);

  q = (int *)(&a-1);

  *(p+1)?   *(q-1) ?

答案是 3, 5。这里主要涉及的问题就是指针参与运算时,它的地址是怎么增加的,也就是它的地址变化单位。首先,明确一点,指针参与算术运算时,指针地址变化是:offset * 指针指向对象长度。例如,上面的代码中,p, q都是int *类型的,那么指针对象长度就是4,同理,char *ptr, 它的就是1。再看看p q此时的指向,关键点就是对于数组名,a和&a有和不同?它们两的值其实是一样的,但是指向的数据类型就不一样了,a指向的是数组第一个元素,也就是说a = &(a[0]),而&a呢,指向的数据类型是int a[5]这样一个数组,而a[0]是个int型数据,所以,a: int * , &a: int [5] *,那么它们指向对象的长度就分别是4,和20了。问题解决。

  此外,sizeof(a) ? sizeof(&a) ?

  答案是 20, 4。sizeof发生在程序的编译阶段,求指定对象占的存储空间。a对象就是整个数组,&a对象就是指向这个数组对象的指针。所以答案就是20, 4。貌似这一切都是一些规定性的东西,说不出一个好的彻底的理由。

  还有一点就是数组名是一个常量指针。额,不是没用const修饰吗?其实说是常量指针不够严谨,应该是只读指针。被const修饰意味着只读。看看其汇编就明白了。

 1     .arch armv4t
 2     .fpu softvfp
 3     .eabi_attribute 20, 1
 4     .eabi_attribute 21, 1
 5     .eabi_attribute 23, 3
 6     .eabi_attribute 24, 1
 7     .eabi_attribute 25, 1
 8     .eabi_attribute 26, 2
 9     .eabi_attribute 30, 6
10     .eabi_attribute 18, 4
11     .file    "a.c"
12     .text
13     .align    2
14     .global    main
15     .type    main, %function
16 main:
17     @ Function supports interworking.
18     @ args = 0, pretend = 0, frame = 24
19     @ frame_needed = 1, uses_anonymous_args = 0
20     @ link register save eliminated.
21     stmfd    sp!, {r4, fp}
22     add    fp, sp, #4
23     sub    sp, sp, #24
24     ldr    r3, .L3      //ldr伪指令,将数组所在段的标签地址加载到r3,.L3这个标签可以理解为数组名
25     sub    ip, fp, #24
26     mov    r4, r3
27     ldmia    r4!, {r0, r1, r2, r3}
28     stmia    ip!, {r0, r1, r2, r3}
29     ldr    r3, [r4, #0]
30     str    r3, [ip, #0]
31     mov    r3, #0
32     mov    r0, r3
33     sub    sp, fp, #4
34     ldmfd    sp!, {r4, fp}
35     bx    lr
36 .L4:
37     .align    2
38 .L3:
39     .word    C.0.1261
40     .size    main, .-main
41     .section    .rodata
42     .align    2
43     .type    C.0.1261, %object
44     .size    C.0.1261, 20
45 C.0.1261:
46     .word    1
47     .word    2
48     .word    3
49     .word    4
50     .word    5
51     .ident    "GCC: (ctng-1.6.1) 4.4.3"
52     .section    .note.GNU-stack,"",%progbits

 这个数组的定义位于上面汇编的38-50行,可以看到41行对此段声明为rodata。未完,39-40行的修饰应该是针对标签 .L3。熟悉下汇编后再来完善。

 

为什么不能修改数组名的值?从C语言的角度,如果修改了数组名的值,例如a++,也就是a = a + 1;那么此后,数组a将失去其基地址,后面的代码将无法访问a[0]了。也许你会说,a = a -1;不就找到了吗?但是每次修改后又要恢复,岂不是极其麻烦,容易导致编程的人疏漏出错。所以编译器干脆规定不允许修改。

 

posted @ 2016-03-18 15:11  thammer  阅读(245)  评论(0编辑  收藏  举报