博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
数组首地址取地址
阅读量:6573 次
发布时间:2019-06-24

本文共 2789 字,大约阅读时间需要 9 分钟。

一、问题来由

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

#include 
using namespace std;int main(int argc,char *argv[]){ int a = 6; int *p = &a; //p存放一个地址,pp存放p的地址,上面的代码可以让p存放的地址偏移 cout<<&a<

运行结果:

这里写图片描述

但是数组首地址却不行:

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

运行结果:

这里写图片描述

于是…

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

打印出来,果然:

cout<<
<<&b<

这里写图片描述

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

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

初学者应该都知道,数组名相当于指针,指向数组的首地址,而函数名相当于函数指针,指向函数的入口地址。

#include
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
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
#include
using namespace std;int main(){ int a[5]={
0x11121314,0x21222324,0x31323334,0x41424344,0x51525354}; printf("%p\n%p\n",a,&a); //数值相等 cout<
<

运行结果如下:

这里写图片描述

你可以说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]

你可能感兴趣的文章
excel中如何批量将所有的网址设为超链接
查看>>
Nodejs学习笔记(十二)--- 定时任务(node-schedule)
查看>>
加密算法使用(五):RSA使用全过程
查看>>
root用户重置其他密码
查看>>
C#------如何获取本机IP地址
查看>>
关于查询扩展版ESI高被引论文的说明
查看>>
【iCore3应用】基于iCore3双核心板的编码器应用实例
查看>>
Oracle推断值为非数字
查看>>
得知发行组长老潘今天岗位上最后一天就要离开有感
查看>>
[转]WF事件驱动(1)
查看>>
异常关闭MyEclipse 8.6后,不能重启
查看>>
android recover 系统代码分析 -- 选择进入
查看>>
问卷调查模块实现的过程中的历程
查看>>
排序合并连接(sort merge join)的原理
查看>>
【转】CCScale9Sprite和CCControlButton
查看>>
多年前写的一个ASP.NET网站管理系统,到现在有些公司在用
查看>>
解决Web部署 svg/woff/woff2字体 404错误
查看>>
经验总结21--抓取WEB数据,汇率,HtmlAgilityPack
查看>>
TThread类详解<转>
查看>>
查看数据库文件大小写
查看>>