zoukankan      html  css  js  c++  java
  • 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;不就找到了吗?但是每次修改后又要恢复,岂不是极其麻烦,容易导致编程的人疏漏出错。所以编译器干脆规定不允许修改。

  • 相关阅读:
    核新同花顺数据结构
    python发送各类邮件的主要方法
    Tesseract-OCR引擎 入门
    ruby函数回调的实现方法
    软件单元测试之我见
    cocos cteator中tiled模式 用图集容易出线
    入坑CCC遇到的一些坑啊
    关于委托的理解
    火狐浏览器的三个坑
    抗锯齿的BUG
  • 原文地址:https://www.cnblogs.com/thammer/p/5292209.html
Copyright © 2011-2022 走看看