`
lovnet
  • 浏览: 6706571 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

数组名不是指针

 
阅读更多

很多人认为数组名除了能使用中括号加下标这种特殊用法外就跟指针一样,就是一个指针.

比如int arr[] = {1,2,3};

int* pInt = arr; //数组名直接赋值给指针

void Function(int* pInt)

{

cout<<"this is a function with pointer parameter.";

}

Function(arr); //数组名arr作为指针参数传给函数

从上面两个例子很容易觉得数组名就是指针.

既然他们能如此相似肯定是有很多联系的,但也不是完全一样.要弄清指针和数组的区别得先弄清两个概念.左值和右值,指针是什么.

指针是什么

其实我们可以把指针看成一个特殊的变量.它里面保存的是地址值.我们知道像int型变量可以保存整数值,在内存中占两个字节.而指针这个变量保存的值其实也是整数,这些整数表示内存中的地址,内存以一个字节(8bit)为单位,每个字节都是有一个整数地址.在内存中如果是32位系统这个地址值占4个字节,如果64位系统则占8字节.

那指针是不是还分不同类型的指针呢? 实际上在内存中所以指针都是一样的,全部是占4或8个字节,里面的值全部是一样的表示地址的整数.没有任何区别.我们所说的指向int或long或者指向指针的指针那是由应用程序也就是编译器去识别,去处理.比如int * p; 假如p中保存的是某个字节的地址12345678,那读取它的值是时因为知道int是占4个字节所以要把地址12345678里的值和它后面一字节里的值一起读出来当作一个值来处理.如果是是char类型指针我们就直接读取指针指向的地址中的值就OK了.

举几个简单例子(其中等式右边&表示取址,获取某个值的地址,*表示解引用,获取它后面那地址中的值)

int num = 123; //num占4个字节,假如用每个字母代表一字节,表示为abcd

int* p = &num; //p占4个字节(32位系统),设为efgh,这4字节里面的内容是a的地址.

int no = *p; //用*取p中的值时是先找到a的地址,因为知道是int型,所以还要读a后面一字节的内容.于是把abcd值读出来.

int** pp = &p; //指向指针的指针,pp里面某保存的地址是e的地址,当用*pp时得到的是efgh4个字节中的内容,也就是a的地址.再用**p这样得到abcd中的值123

左值和右值

关于它们的定义貌似挺复杂的,比如有说左值表示特定的名字引用,而右值没有特定的名字引用.看得有点云里雾里的.

在表达式中我们可以这样简单的来理解(我不确定对不对啊).有确定值的字面值,不是变量,它自己本身就是值,比如数字1,2,3.字符串"abc",字符'a'.它们永远是右值.或者它是相当是于字面值的别名,比如用#define PI 3.14这样定义的PI,它就永远只能是右值.

而左值是一个变量,可以给它赋值,而且能做左值的话就也能做右值.当然要符合一些语法规则,使用时要类型匹配.

我们用的时候只要看到有等号出现的地方,等号左边的就是左值,等号右边的右值.如果没等号出现那就全部是右值.

比如int num = 88; //num是左值,88是右值

int* pInt = &num; //pInt是左值,&num是右值

num++; //num++是右值

cout<<pInt; //pInt是右值

左值只是一个变量,实际上只是内存中的一个地址,相当于是一个盒子.而右值是地址中的实际内容,是盒子中具体装的东西.盒子刚开始只是个空的大小固定的空间,里面可以装尺寸匹配的东西进去,也可以把里面的东西换成另外的东西.这就是我可以给变量赋不同的值.

刚说的是在表达式中,如果在函数中,形参是左值,所谓形参嘛只是形式上的,摆个空盒子在那里面没实际的值嘛,实参则是右值有实际的内容.也就是定义一个函数时参数都是左值.只有调用函数时传进去的参数才是右值.

相同的东东位置不同,代表的意义就不同了啊.比如同样是搞女人,人家有身份有地位的人搞是风流,搞的是情人.你一穷光蛋就叫下流,叫搞破鞋.

int num = 88; //num在左边时,是左值,它实际上也只是一个地址,是个盒子,88才是盒子里的内容.我们不能把盒子和里面的内容混为一谈.

int no = num; //num跑右边来了,不再是左值,而是右值.它就是88

上面说了那么多现在可以来澄清指针和数组的关系了.

int arr[] = {1,2,3};

int* pArr = arr;

cout<<arr<<pArr; //它们俩的值是一样的

arr = pArr; //会出错,为啥它们的值是一样的,不能赋值呢,奇怪吧?

其实数组名它永远是右值,你放到左边当左值时就会出错.它的值就是数组的首地址,就像保存int型数字1的4个字节中的首字节地址.数组名只是一个地址值.本身是一个值.

而指针pArr,它可以做左值,它只是一个盒子,里面可以保存不同的的地址值,但它不是地址值本身.但它做右值时就是地址值本身了,和数组名arr等价.所以cout<<arr<<pArr相同.

另外开头说的void Function(int* p)这样的函数,可以这样Function(arr)调用.因为arr是右值,自然可以当实参.

但我们可以arr[0] = 10;这样做左值用.但arr加个中括号后和数组名arr就不是同一个概念了.

arr[0]就等价于是一个int型变量了.而&arr[0]才和arr是等价的.

所以我们可以int * p = &arr[0]或int* p = arr;这样用

把上面所有的复杂的讨论再简化下.指针和数组的关系有点像

int num = 88;

其中num就有点像指针,而88就有点像数组名

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics