zoukankan      html  css  js  c++  java
  • 数组首地址取地址

    一、问题来由

    普通指针可被改动导致地址偏移:

    #include <iostream>
    using namespace std;
    
    int main(int argc,char *argv[])
    {
        int a = 6;
        int *p = &a;
    
        //p存放一个地址。pp存放p的地址,上面的代码能够让p存放的地址偏移
        cout<<&a<<endl;
        int *pp = (int *)&p;
        cout<<p<<endl;
        (*pp) += 4;
        cout<<p<<endl;
    
        return 0; 
    }
    

    执行结果:

    这里写图片描写叙述

    可是数组首地址却不行:

    #include <iostream>
    using namespace std;
    
    int main(int argc,char *argv[])
    {
        int b[5]={111,666,3,4,5};
        int *pos = (int *)&b;
    
        cout<<*pos<<endl;
        (*pos)++;
        cout<<*pos<<endl;
    
        return 0; 
    }
    

    执行结果:

    这里写图片描写叙述

    于是…

    这说明数组首地址取地址有问题…

    打印出来,果然:

    cout<<b<<endl;
    cout<<&b<<endl;

    这里写图片描写叙述

    数组首地址是指向地址的指针,可是这个指针取地址跟里面存的一样。。。

    二、数组首地址和数组名取地址

    刚開始学习的人应该都知道。数组名相当于指针。指向数组的首地址,而函数名相当于函数指针,指向函数的入口地址。

    #include<stdio.h>   
    
    int main()   
    {   
        int a[10];
    
        printf("a:	%p
    ", a);
        printf("&a:	%p
    ", &a);
        printf("a+1:	%p
    ", a+1);
        printf("&a+1:	%p
    ", &a+1);
    
        return 0;
    }

    输出:

    a: 0032FCBC
    &a: 0032FCBC
    a+1: 0032FCC0
    &a+1: 0032FCE4

    a和&a指向的是同一块地址。但他们+1后的效果不同。a+1是一个元素的内存大小(添加4),而&a+1添加的是整个数组的内存大小(添加40)。

    即a和&a的指向和&a[0]是同样的,但性质不同!

    int main()   
    {   
        int a[10];   
        printf("%d
    ",sizeof(a));   
        return 0;   
    }  

    这段代码会输出整个数组的内存大小。而不是首元素的大小,由此我们是否联系到,sizeof(a)这里的a和
    &a有些同样之处呢?! 是的,没错。&a取得的是整个数组的地址!既数组名取地址等价于对数组取地址。

    总结一下

    事实上a和 &a结果都是数组的首地址。但他们的类型是不一样。
    a表示&a[0],也即对数组首元素取地址。a+1表示首地址+sizeof(元素类型)。


    &a尽管值为数组首元素地址。但类型为:类型 (*)[数组元素个数],所以&a+1大小为:首地址+sizeof(a)。

    说明:

    应该在了解数组名即是数组的首地址的同一时候,也要知道,数组名仅仅是“相当于”指针。而并不是真的是指针,数组名是仅仅是个常量(一个值为数组首元素地址的常量),所以不能进行++或者–运算。而常量更是无法取地址的,而之所以有&a,事实上这里的a的意义早已经不是当初那个数组名了,它此时代表了整个数组。

    三、补充

    注明:例如以下补充摘录自參考资料里面出现的还有一段文字,文字内容非常好,可是安排非常乱,特整理例如以下。

    先上第一段代码:

    #include<stdio.h>
    
    int main()
    {
        int a[5]={0x11121314,0x21222324,0x31323334,0x41424344,0x51525354};
        int *ptr1=(int *)(&a+1);
        int *ptr2=(int *)(a+1);
    
        printf("%x
    %x
    ",ptr1[-1],*ptr2);
    }

    打印结果例如以下:

    这里写图片描写叙述

    这说明 &a+1 跨过了整个数组长度,而 a+1 仅仅是在数组首地址上递增了一个元素空间大小,同上文所述。

    再想一下,假设将第一例第五行改为

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

    打印结果会是什么?

    这里写图片描写叙述

    这里要考虑数据在计算机中的存储模式:大端模式和小端模式。解释一下:

    大端模式(Big_endian):字数据的高字节存储在低地址中。而字数据的低字节则存放在高地址中。


    小端模式(Little_endian):字数据的高字节存储在高地址中,而字数据的低字节则存放在低地址中。

    在大端模式下。a在计算机中存储例如以下(从低地址到高地址,一个十六进制数代表内存的一个字节,下同):
    0x11 0x12 0x13 0x14 0x21 0x22 0x23 0x24 0x31 0x32 0x33 0x34 0x41 0x42 0x43 0x44 0x51 0x52 0x53 0x54

    在小端模式下,a在计算机中存储例如以下:
    0x14 0x13 0x12 0x11 0x24 0x23 0x22 0x21 0x34 0x33 0x32 0x31 0x44 0x43 0x42 0x41 0x54 0x53 0x52 0x51

    (int)a表示将a的首地址强转为整型数据(若原来是0012FF6C,转换后仍为0012FF6C,可是这时已经不是表示地址而是一个
    十六进制整型数了)。这时+1代表整型数(int)a加1(变为0012FF6D),再把结果强转为整形指针,故指向的数据地址为0012FF6D。
    即上述存储去的第二个字节開始处。此时输出*ptr2。即输出a数组存储区中第二到第五字节组成的一个整型数,若为大端模式则输出
    12131421,若为小端模式则输出24111213。

    #include<stdio.h>
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        int a[5]={0x11121314,0x21222324,0x31323334,0x41424344,0x51525354};
        printf("%p
    %p
    ",a,&a); //数值相等
    
        cout<<sizeof(a)<<endl; // a是复合类型 int[5]
        cout<<sizeof(&a)<<endl; // &a是int(*)[5]
    
        cout<<sizeof(a+1)<<endl; // a+1 变成指向数组第二个元素的指针,其类型是 int *
        cout<<sizeof(&a+1)<<endl; // &a+1 还是 int(*)[5]。类型还是指针
    
        //a+1 由于 a 指向int(但不是普通指针),加1移动int个大小
        //&a+1 由于 &a 指向 int[5],加1移动 int[5] 个大小
        printf("%p
    %p
    ",a+1,&a+1);
    }
    

    执行结果例如以下:

    这里写图片描写叙述

    你能够说a+i和&a[i]含义同样,可是绝不能说a和&a[0]或a+0含义同样。

    补充说明下。在vc6.0上,上面sizeof(&a)才是20,而在GCC ,以及之后的vc版本号(如vs2005及之后版本号)则是将&a全然视作一个指针,sizeof(&a)为4 (32位机器)

    四、二维数组传參

    三种写法

    (1)int (*p)[5]

    (2)int a[][5]

    (3)int a[5][5]


    參考资料

    [1] http://blog.csdn.net/syzobelix/article/details/40054095

  • 相关阅读:
    C++11 学习总结
    平衡二叉树 (AVL) 笔记
    拼图模板
    2013.9.12
    2013.9.11
    2013.9.10
    2013.9.9
    下载网站
    ubuntu 安装codeblocks
    12个球称3次找坏球的完美解答
  • 原文地址:https://www.cnblogs.com/yxysuanfa/p/7352619.html
Copyright © 2011-2022 走看看