解析:数组名a、数组名取地址&a、数组首地址&a[0]、数组指针*p

数组和指针向来就是傻傻分不清,当他们一起出现的时候就更加懵逼。

1 解析不同变量之间的区别:

数组名a

数组名可以作为数组第一个元素的指针。我们由数组和指针的关系知道,a代表这个地址数值,它相当于一个指针,指向第一个元素(&a[0]),即指向数组的首地址。数组中的其他元素可以通过a的位移得到,此时的进阶是以数组中单个的元素类型为单位的,即a+i= & a[i]。

数组名取地址&a

对于一个普通的变量b,&b是指用取地址符号取得变量b的存放地址;a在内存中没有分配空间,只对数组a的各个元素分配了存储空间,此处数组名字a显然不是普通的变量,&a也不代表所取a的存储地址。

&a在数值上等于&a[0],也等于a。此时,&a数值上等于整个数组的起始位置地址,含义上代表整个数组所占内存的大小,因为它的进阶单位是整个数组的字节长度,(&a + 1)等于的是数组结束之后的下一段的起始位置地址。

数组首地址&a[0]

这个就是取地址的最直接的应用,a[0]在内存中实际分类存储空间,而&a[0]就是取该存储空间的地址,这与对于任意满足范围的i,&a[i]就是取第i个元素的存储地址一样。

数组指针*p:

指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。经常用取地址符&将某个变量的地址赋给它,同时常常对指针用取值符号*取得对应地址的内容。

暂时还没做指针相关的总结,贴一篇不错的博客。让你不再害怕指针——C指针详解(经典,非常详细)大佬的这篇博客,内容和它的标题一样经典和详细,非常值得参考。

讲了四个概念你可能还是不太清楚,下面通过一个简单的例子进行说明:
这里写图片描述

程序代码和运行的结果如上,可以看到其实数组名字、数组名字取地址、数组首元素取地址、指向首元素的指针值着四个变量的数值大小是相等的,都是0026F910。但是在后面的地址加1的操作中,数组名字取地址所得地址在+1之后所得的是0026F910+4*5+4=0026F920。具体地址和变量对应图如下所示(忽略考虑大小端)(忽略地址表示形式如此不规范)。

这里写图片描述

其实也可以换一种理解方式,理解

a的类型是int[5] 数组
&a的类型是int(*)[5] 指针——指向int[5]数组的指针
&a[0]的类型是int* 指针——指向int类型的指针

另外,当用sizeof时,由于a是个关键词,而不是个函数,所以数组不自动转换为指针,得到的结果=(数组的长度*数组中元素类型所占的字节数)=5*4=20,本例中sizeof(a)和sizeof(&a)都是20.

以上内容来源分开__旅行:数组名和数组名取地址的区别这篇博客通过代码实例展示了数组名字和数组名字取地址之间的区别,个人认为讲的通俗易懂,非常值得参考。这篇博客数组名a和&a的区别在讲&a+1和a+1的区别上也非常详细,可以参考。

2 关于字符类型数组的小插曲

在C++语言环境下,把上述int类型的数组改成char类型数组,咦。怎么结果不一样了,难道数组名字不能作为指向首元素的指针呢?看例子。
这里写图片描述

发现除了&a和&a+1之外,其他的都输出了一堆奇奇怪怪的东西。先看结论

数组名字可以作为数组首元素的指针,仍成立,请放心!

C++语言中用cout输出字符串名称有讲究,导致了上述的结果。

 char *p="abcd";

2.1 为什么只有&a和&a+1能正确输出地址

在C语言里,输出一个字符串的指针很方便,直接printf("%p/n",p) ;就输出了。

而C++里cout太自作聪明了,为了省去我们循环输出字符的麻烦,cout<<p<<endl ;被翻译为输出p指向的字符串值

依据之前讲的,只有&a是指向整个数组,而其他的都是指向某一个元素。于是都将以这些元素为起始位置,输出一个字符串。这也就解释了为什么只有&a和&a+1能正确输出地址。

2.2为什么烫烫烫烫烫烫屯屯屯屯

关于烫烫烫屯屯屯,在网上流传着一首打油诗。

手持两把锟斤拷,口中疾呼烫烫烫。脚踏千朵屯屯屯,笑看万物锘锘锘

其实是很多程序员经常遇到的问题。

简单来说。在Debug 模式下,

VC 会把未初始化的栈内存全部填成0xcc,当字符串看就是 烫烫烫烫……
会把未初始化的堆内存全部填成0xcd,当字符串看就是 屯屯屯屯……
可以让我们方便地看出那些内存没初始化

举个例子,下面的代码运行在单步调试中,定义了两个字符串数组str1和str2,运行到142行代码的时候,str2只是定义了但还未初始化。在下面的监控窗口可以看到,就是一串“烫烫烫烫烫烫”。
这里写图片描述

需要注意的是,“烫烫”的个数是不一定的,并且有些编译器并不是“烫烫”而是其他字符。

之前代码运行之后出现烫烫烫等奇怪的汉字就是因为那些内存未初始化

如果对烫烫烫屯屯屯想要更加细致的了解可以参考烫烫烫的实例,仔细看完这个例子就会理解烫烫烫的来源了。

2.3如何避免输出烫烫烫

cout输出的时候>>遇到'\0'的时候就会停止输出,那加一个'\0'就可以避免 输出未初始化区域的内容咯

这里写图片描述

猜你喜欢

转载自blog.csdn.net/loongkingwhat/article/details/78910921