指针的算术运算不象普通变量增大和减小那么简单,它意味着对物理内存的偏移访问,一旦步子跨得不对,后果就是非法访问甚至crash。所以指针运算有严格限制:它只允许加上或减去一个整数,而不允许加减变量以及乘除法操作。并且指针加减运算和通常的整数加减有所不同,比如:
char a[20];
int *ptr=a;
ptr = ptr +1;
注意,尽管后面被初始化指向字符数组a[20]的首地址,但int *ptr这一定义形式表明ptr指向的内存类型是int。以此为依据,对下一句ptr = ptr+1,编译器是这样处理的:把指针ptr的值加上1*sizeof(int)。地址以字节为单位,sizeof(int)等于4字节,所以ptr指向的地址将由原来数组a首地址向高地址方向增加4字节。a[20]中每个char单元占1字节,所以ptr的指向从a[0]移到a[4]。再看:
char a[20];
int *ptr=a;
ptr+=6;
这次对ptr加6,编译器做类似处理:将指针ptr加上6*sizeof(int)=6*4=24字节,但如果ptr向高地址方向移动24字节,就指向了数组a的合法范围之外。这就是内存访问越界的错误,但语法上却可以编译通过。这两个例子充分体现了指针的灵活性与危险性。ptr减n,处理基本一样,只是把ptr值减去n*sizeof(int),即ptr向低地址方向移动n*sizeof(int)个字节。
总结:指针ptrold加上(减去)一个整数n,结果是一个新的指针ptrnew,ptrnew和ptrold指向相同的内存类型,ptrnew的值比ptrold的值增加(减少)n*sizeof(ptrold所指内存类型)个字节。即ptrnew指向的内存将比ptrold指向的内存向高(低)地址方向移动n*sizeof(ptrold所指内存类型)个字节。下面是一个常见面试题:
short array[10]={0,1,2,3,4,5,6,7,8,9};
int *pVal = array;
...
pVal += 2;
printf(“pVal =%d\n”,*(short* )pVal);
结果是: pVal = 4;
同样是一步,姚明和潘长江绝对不一样。所以涉及指针算术运算时,一定要看这一步是以什么为单位,即反复重复的:要关注指针指向的内存类型,而不能和指针赋值对象的类型混淆。