指针的加减操作及对指针和数组类型的理解

先来看看一道题,分析指针的加减操作:

例题1:写出下面程序的运行结果

<span style="font-size:18px;">int a[3];
a[0] = 0,a[1] = 1,a[2] = 2;
int *p,*q;
p=a;
q = &a[2];	
cout<<a[q-p]<<endl;           //输出结果是2</span>

可作如下验证程序:

<span style="font-size:18px;">int main ()
{
	int a[3];
	a[0] = 0,a[1] = 1,a[2] = 2;
	int *p,*q;
	p=a;
	cout<<p<<endl;           //输出0027FAE8(指向数组的首元素)
	cout<<*p<<endl;          //输出0
	q = &a[2];
	cout<<q<<endl;           //输出0027FAF0(指向数组的第三个元素)
	cout<<*q<<endl;          //输出2   
	cout<<(q-p)<<endl;       //输出2
	cout<<a[q-p]<<endl;      //输出2
	return 0;
}</span>
从以上验证程序中可以看出,指针相减时得到的值不是实际的地址差值(0027FAF0-0027FAE8 = 0x08),而是在差值的基础上再除以数据类型的大小,这里面存储的是int型数据,因此q-p=0x08/sizeof(int)=2.

同样的道理,指针加上一个整数得到的并不是指针地址值的单纯相加,而是指针的地址值+这个整数*指针存储的类型的大小。比如double *p = 1.0;p+2 = p的地址值+ 2*sizeof(double)。

所以我们可以得出结论:

1. 两个指向同一数组的指针相减得到两个指针之间元素的个数

2.指针加一个数a等于指向同类型的下a个数的元素

3.指针减去一个数a等于指向同类型的上a个数的元素(当然前提同类型元素地址是连续的)


下面再看看另一道题,解析数组名a、&a的区别:

<span style="text-indent: 28px; background-color: rgb(240, 240, 240);">int main()
</span><span style="background-color: rgb(240, 240, 240);">{</span>    int a[5]={1,2,3,4,5};
     int *ptr=(int *)(&a+1);
     printf("%d,%d",*(a+1),*(ptr-1));  //结果为2,5
     return 0;
}

根据上面的讲解得知,对指针进行加1操作,得到的是下一个元素的地址,而不是原有地址值直接加1。所以,一个类型为T的指针的移动,是以sizeof(T) 为移动单位。

对上题来说,a是一个一维数组,数组中有5个元素,所以a的类型是数组指针

ptr是一个int 型的指针,ptr的类型是整型指针。 

&a + 1:取数组a 的首地址,该地址的值加上sizeof(a) 的值,即&a + 5*sizeof(int),也就是下一个数组的首地址而这个&a+1显然当前指针已经越过了数组的界限。  

(int *)(&a+1): 则是把上一步计算出来的地址,强制转换为int * 类型,赋值给ptr。

数组a与&a的辨析:  

1. a,&a的值是一样的,但意思不一样。

2. a是数组首元素的首地址,也就是a[0]的首地址,a+1是数组下一元素的首地址,也就是啊a[1]的首地址。

3. &a是数组的首地址,&a+1是下一个数组的首地址。

因此:

*(a+1):对指向数组中第二个元素的首地址解引用,得到的结果为a[1],即为2,很好理解。

*(ptr-1):因为ptr是指向了数组的外面,且地址刚好差一个int类型的大小,这一点可以上次测试,我们可以把它理解为a[5],而ptr是int * 类型,所以*(ptr-1)又指向了a[4],即输出5。



1


 



猜你喜欢

转载自blog.csdn.net/dby3579/article/details/52004952