很多人认为数组名除了能使用中括号加下标这种特殊用法外就跟指针一样,就是一个指针.
比如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 = # //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 = # //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就有点像数组名
分享到:
相关推荐
彻底理解指针,指针数组和数组指针,指针函数和函数指针.doc
指针是C/C++语言的特色,而数组名与指针有太多的相似,甚至很多时候,数组名可以作为指针使用。于是乎,很多程序设计者就被搞糊涂了。而许多的大 学老师,他们在C语言的教学过程中也错误得给学生讲解:"数组名就是...
数组指针(也称行指针) 定义 int (*p)[n]; ()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。 如要将二维数组...
指针是C/C++语言的特色,而数组名与指针有太多的相似,甚至很多时候,数组名可以作为指针使用。于是乎,很多 程序设计者就被搞糊涂了。而许多的大学老师,他们在C 语言的教学过程中也错误得给学生讲解:“数组名就是...
c语言中 数组名和指针的区别 来自知网的论文
数组指针:类型名 (*指针名)[数组长度]; 例:int (*parr)[5]; 现在我们再来通过上面的定义来分析一下指针数组和数组指针。 int *parr[5];因为优先级的关系,parr先与[]结合,说明parr是一个数组,然后再与*结合说明...
数组指针和指针数组的区别
指针, 指针的指针, 数组, 指针数组, 数组指针, 指针函数, 函数指针 CC++中函数指针的含义
本文较为详细的分析了关于理解C++指针数组,数组指针,数组名,二维数组的一些技巧。是比较重要的概念,相信对于大家的C++程序设计有一定的帮助作用。 一、关于数组名 假设有数组: int a[3] = {1, 2, 3} 1.数组...
指针与二维数组 数组指针 指针数组 多级指针
·详解数组指针与指针数组 ·数组指针 ⾸先我们需要了解什么是数组指针以及什么是指针数组,如下图: int *p[5]; int (*p)[5]; 数组指针的意思即为通过指针引⽤数组,p先和*结合,说明了p是⼀个指针变量,指向⼀个...
CC++数组名与指针区别深入探索 CC++数组名与指针区别深入探索
数组的指针和指向数组的指针变量数组的指针和指向数组的指针变量数组的指针和指向数组的指针变量数组的指针和指向数组的指针变量
易语言数组转指针源码,数组转指针,子程序1,子程序2,子程序3,数组_整数转指针,数组_指针转整数,数组_文本转指针,数组_指针转文本,数组_字节集转指针,数组_指针转字节集,内存_申请,内存_释放,内存_取长度,内存_写入,...
数组和指针在各类编程语言中,都很重要,数组应用很广泛,理解基础很必要
数组指针和指针数组的区别 定义 int (*p)[n]; ()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。 如要将二...
指针是C/C++语言的特色,而数组名与指针有太多的相似,甚至很多时候,数组名可以作为指针使用。
数组指针和指针数组