在学习的过程中,发现了 一个有趣的东西,那就是数组的三值合一,不知道大家听过没有,我是第一次听,原来也没有注意到这个问题,学习过后,今天总结一下,以下就是我的一些见解。

首先来看下边的代码


测试代码一



#include<iostream>

using namespace std;

void  main()

{

int a;

int arry[10] = {0};

cout<<arry<<endl;

cout<<&arry<<endl;

cout<<&arry[0]<<endl;

cout<<sizeof(arry)<<endl;

cout<<sizeof(arry[0])<<endl;

cout<<sizeof(&arry)<<endl;


}


     对于普通×××变量a,a为变量名当赋值以后,我们就可以通过变量名操作变量中存储的数据,那么对于数组是一类相同数据类型数据的集合,我们就不能通过数组名直接操作其中是数据,要通过数组名与下标的方式访问,那么问题来咯,数据名是什么呢?查阅c语言的基础语法书籍,我么可以知道,书中这样讲到:数组名的值是一个指针常量,也就是数组的第一个元素的地址ok,我也通过程序分别求出了他们的地址,见测试结果图一


测试结果图一:


wKioL1jSVJGyr7YmAABbjoAk89M185.png-wh_50





对的,我们看到也就是这样,数组名的值和数组的首元素的地址一样,我也顺便把数组名的地址也求了,现在先不用理他,我们只要看他们,数组名的值数组首元素的地址,以及数组名的地址值是一样的,既然地址一样那么我们是不是可以理解为他们三个是一个东西。ok,看到这里,是不是觉得博主有病,书上都讲了 ,你还在这里讲什么,no,我的问题刚刚开始,既然数组名和数组首元素的地址一样,那么我们分别对他们用sizeof()函数求字节长度,按照之前的逻辑,地址一样求得的大小是一样的,但是结果确实不是,见测试测试结果图一数组名的大小是40字节个也就是数组的大小,然而对数组首元素的大小是4个字节,对于数组名的的地址求大小也是4个字节,看到这里是不是觉得有点意思,ok,接下来我们先从最简单的开始解释。虽然三者的值都一样,但是代表的含义是完全不一样的(后边我会用代码验证)

    按照我的理解,arry[0]代表数组的首元素,那么对那对他求大小的时候,那么由于此数组是一个×××数组,在win32的环境下,×××占四个字节,那么它求得的大小也就是四个字节,ok,肯定有人会说,不一定吧!为了消除大家的疑虑,我用其他类型 的数组做了测试,可以看代码块二 和测试结果图二;ok,我想我把数组首元素这个解释清楚了。



测试代码二



void  main()

{

   char  ch[20] = {'d'};

   int arry1[10] = {0};

   double  Doub[30] = {3.14};

   cout<<sizeof(ch[0])<<endl;

   cout<<sizeof(arry1[0])<<endl;

   cout<<sizeof(Doub[0])<<endl;


}


测试结果图二:



wKioL1jSWrbgX6D2AABOEpQYn5o236.png-wh_50



    继续,按照我的理解,数组名就是代表整个数组,数组名有一个值就是数组首元素的地址,这也就解释了为什么分别对数组名和数组首元素求地址的时候他们的值一样,而当对他们分别用sizeof()函数求大小的时不一样,数组名代表的整个数组的空间所以求得的大小是整个数组空间的大小,而数组首元素就是一个×××变量占四个字节,对于其他类型的数组求大小值当然不同,前边我已经解释过了。

    好了我们来解释最后一个对数组名取地址,这个就是对整个数组取地址,但是数组的首元素数组的入口,所以,我们可以看到数组名取地址数组首元素的地址一样,但两者的意义是完全不一样的。空口无凭,我们继续看测试代码三:


测试代码三(1)


#include<iostream>

using namespace std;

void  main()

{

    int arry[10] = { 0 };

    int *p1;

    int *p2;

    int *p3;

    p1 = &arry[0];

    p2 = arry;

    p3 = &arry;

}


error C2440: “=”: 无法从“int (*)[10]”转换为“int *” 与指向的类型无关;转换要求 reinterpret_cast、C 样式转换或函数样式转换



测试结果图三(1):



wKioL1jSbN7zNSelAABIdmAI1Bk347.png-wh_50


测试代码三(2)


void  main()

{

    int arry[10] = { 0 };

    int *p1;

    int *p2;

    int *p3;

    p1 = &arry[0];

    p2 = arry;

    //p3 = &arry;

}


测试结果图三(2)


wKiom1jSbN7iyo5yAAA4S1fBiPg790.png-wh_50



    首先告诉大家这段代码是不能编译通过的,错误的,我也把错误信息放了上去,那么这段代码错误在那块呢?我来解释一下,首先呢,这段代码也解释了我前边说的虽然数组的三值合一,但其代表的含义是不同的,前边讲了,数组的数组名数组的首元素的地址数据名的地址三者值一样。ok,首先我们分别定义了三个指针变量p1、p2、p3;由于数组首元素,就是一个×××元素,所以我们可以用一个×××指针变量接收数组首元素的地址,然后,数组名存储着数组首元素的地址,我们就可用一个同种类型的指针变量接收,换句换说,就相当于指针变量之间的赋值;最后,我们一直强调,数组名代表整个数组,即使三者的值一样,但是其意义是不一样的,我们来看测试代码三(1)的最后一行,我先说明,就是这行代码导致编译不能通过,运行结果如测试结果图三(1)假如说数组名不代表整个数组,那么对它取地址是可以赋值给变量p3的,但是程序不能编译通过,给出了测试代码三(1的下边的报错信息,注释掉那一行后运行结果就好了,代码如测试代码三(2),结果如测试结果三(2)。我们很容易可以看到对于类型不一样,不能匹配,好了写到这里也就解释的差不多了。最后我把今天写的总结一下:


    数组中的三值合一数组名、数组首元素地址、数组名的地址。但是三者代表的意义完全不同,数组名就代表整个数组,数组名中保存首元素的地址,数组首元素就是代表数组中首元素。 所以 数组名取地址 代表针对整个数组取地址,因而当对其求大小时其大小就是整个数组的大小