数组首地址取地址

一、问题来由

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

#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:\t%p\n", a);
    printf("&a:\t%p\n", &a);
    printf("a+1:\t%p\n", a+1);
    printf("&a+1:\t%p\n", &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\n",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\n%x\n",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\n%p\n",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\n%p\n",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

时间: 2024-11-08 21:07:14

数组首地址取地址的相关文章

C/C++注 意数组后面的取地址符!!

#include<iostream> #define Min(a,b) (a>b?b:a) using namespace std; int main() { int a[5]={1,2,3,4,5}; int *p=(int *)(&a+1);//本身数组名就是地址了,也就是数组名就是指针,>取数组的地址,也就是取指针的地址,即p为指向数组的指针(指针的指针),当&a+1,p指向的其实是数组末尾5后面的地址,当p-1,往回退一格回到数组的末尾,>即5. in

C语言的数组名和对数组名取地址

http://blog.csdn.net/zdcsky123/article/details/6517811 相信不少的C语言初学者都知道,数组名相当于指针,指向数组的首地址,而函数名相当于函数指针,指向函数的入口地址.现在又这样一个问题,如果对数组名取地址,那得到的会是什么呢?很多人立刻会想到:给指针取地址,就是指针的指针,既二级指针嘛!当然这样的结论是错误的,不然这篇笔记也就没有意义了. 下面我们来逐步分析,下面是一段验证这个问题的代码 Code: #include<stdio.h> in

数组名取地址以及数组名作为sizeof操作符的操作数

数组名取地址十分好玩,在这里记录一下,如果大家有不同见解,欢迎留言探讨: 在大多数情况下,数组名都会默认转换为指向数组的第一个元素的指针.这一点相信大家都知道.比如下边的例子:   int array[3] = {1,2,3};      cout << *array << endl;      cout << array[0] << endl; 上边的两个输出的值是相同的,这个时候array作为数组名默认转换为指向数组的第一个元素的指针.对数组名称进行解引

C语言——数组名、取数组首地址的区别(一)

目录: 1. 开篇 2. 论数组名array.&array的区别 3. array.&array的区别表现在什么地方 4. 讨论 5. 参考 1.开篇 很多博客和贴吧都有讨论这个话题,各有自己的表述方式,今天在他们的基础上我将继续试着以我自己理解的方式总结一下,欢迎大家的审阅和指评. 2.论数组名array.&array的区别——省政府和市政府的区别 例如: int array[5] = {0}; 总所周知,其中的&array是整个数组array的首地址,array是数组首

数组名a、数组名取地址&amp;a、数组首地址&amp;a[0]、数组指针*p

本文链接:https://blog.csdn.net/loongkingwhat/article/details/78910921 数组和指针向来就是傻傻分不清,当他们一起出现的时候就更加懵逼. 1 解析不同变量之间的区别: 数组名a: 数组名可以作为数组第一个元素的指针.我们由数组和指针的关系知道,a代表这个地址数值,它相当于一个指针,指向第一个元素(&a[0]),即指向数组的首地址.数组中的其他元素可以通过a的位移得到,此时的进阶是以数组中单个的元素类型为单位的,即a+i= & a[i

对数组名取地址

int a[5]={1,2,3,4,5}; int b[100]; 一个数组名代表的是数组中第一个元素的位置,通过数组名我们可以访问数组,先看下面两个问题 问题一:看到一篇文章这么写的..int array[10];int (*ptr)[10];ptr=&array;//这里说明&array是指向数组的指针,但为什么&array是指向数组的指针?答一:对数组名取地址在C标准里面是未定义的行为.由于数组名是右值,而&操作符要求操作数具有具体的内存空间,换言之就是一个变量,因此

C语言中对数组名取地址

在C/C++中,数组名相当于一个指针,指向数组的首地址.这里"相当于"不代表等于,数组名和指针还是有很多区别的,这个在<C陷阱与缺陷>里有详尽的讲述.而这里要说的是对于数组名取地址的这么一个操作. 如果声明有如下数组: int arr[5]; 那么,&arr这个操作得到了什么值呢? 如果简单的认为arr就是一个指向数组首地址的指针的话,那么很自然会想到&arr得到的是一个指向存放arr这个指针的指针,也就是一个二级指针,然而事实却并不是这样. 观察以下代码:

浅谈C/C++数组取地址

本文讲的是关于C/C++数组取地址一些基本的概念,但是新手可能会在学习相关内容时产生一定的困惑,希望本文能帮助到你. 我们先来看以下一段代码: 1 #include<iostream> 2 using namespace std; 3 int main(){ 4 int array[6] = { 1,2,3,4,5,'\0'}; 5 cout<<array<<endl; 6 cout<<&array<<endl; 7 return 0;

数组名和数组名取地址、指针数组和数组指针的区别

一,首先我们先分析下数组名和数组名取地址的区别. 我们都知道数组名是数组的首地址,然而对数组名取地址又是什么那?看下面一段程序你就会懂的. #include "stdafx.h"     #include<stdio.h>    using namespace std;    void main()    {          int a[5];          printf("%d\n", a);          printf("%d\n