本节书摘来自异步社区《指针的编程艺术(第二版)》一书中的第3章,第3.1节,作者 蔡明志,更多章节内容可以访问云栖社区“异步社区”公众号查看
指针的编程艺术(第二版)
3-1 指针与一维数组
3-2 指针与二维数组
3-3 数组指针
3-4 为什么parr等同于 *parr?
3-5 指向数组的指针
3-6 多重指针
3-7 命令行参数
3-8 改错题
3-9 练习
3-10 程序实战
指针其实就是一个地址。数组的名称,表示这个数组的第1个元素的地址,所以它也是指针。由此可知,指针与数组的关系是很密切的。为了与指针变量(pointer variable){xe "指標變數(pointer variable)"}有所区别,我们称数组名就是指针常量(pointer constant){xe "指標常數(pointer constant)"}。指针变量与指针常量的不同之处在于,前者可以使用递增运算符(++)或递减运算符(--)来递增和递减指针;但后者不行。因此,如果在程序中使用arr++或arr--,就会出现错误的信息。
我们先来看一下指针与一维数组(one dimension array)的关系。请参阅范例pointerarr1-5。
范例pointerarr1-5
输出结果
从输出结果可以知道,arr是数组名,它是指针常量,而ptr是指针变量。arr表示这个数组第1个元素的地址,也就是arr等同于&arr[0]。
arr可以使用指针变量的符号,如arr等同于arr[0],(arr+1) 等同于arr[1],依此类推。同理,ptr也可以使用指针常量的[]符号,例如,当前ptr所指向变量地址的值为ptr[0],它等同于ptr,而ptr[1]等同于*(ptr+1),依此类推。
再来看范例pionterarr1-10。
范例pointerarr1-10
ptr与i数组的关系图如下所示。
程序一开始将ptr指向i+2(它是i[2] 的地址),所以ptr[0] 等于i[2],因为ptr[0]表示当前ptr所指向变量地址的值。同时也知道ptr[-1] 是i[1]、ptr[-2] 是i[0]、ptr[1]是i[3]、ptr[2] 是i[4]。我们从这个范例得到以下的公式
大部分的用户都是用*(ptr+i)间接访问数组中索引为i的元素值。
当指针与++递增运算符一起运算时,必须注意++的作用对象在哪里,是对地址加1,还是将变量值加1。如果是对地址加1,则将指针移到下一元素的地址。请参阅范例pointerand++。
范例pointerand++
从输出结果可知,pi+1只是将当前的pi向下移到下一个元素的地址,它并没有覆盖pi。而pi++不仅将当前的pi移到下一个元素的地址,而且还将它的新值还覆盖了pi。我们可以对指针变量pi做++的动作,但不可以对数组名i做++的动作。
当指针、递增运算符(++){xe "遞增(++)運算子" y "ㄉㄧˋㄗㄥㄩㄣˋㄙㄨㄢˋㄗˇ"}或递减运算符(--){xe "遞減(--)運算子" y "ㄉㄧˋㄐㄧㄢˇㄩㄣˋㄙㄨㄢˋㄗˇ"},及 * 这3个运算符同时出现时,要注意++的作用点在哪里。请参阅范例pointerand++2。
范例pointerand++2
从程序定义中
int i[ ] = {100, 200, 300, 400, 500};
int *pi = i;
得知,其示意图如下。
下一条语句
当和++在同一个语句中时,要注意++的作用对象,是对地址加1还是对值加1。如果对地址加1,表示将pi指针移到下一地址。由于和++的运算优先级相同,且其结合性是由右至左,因此pi++其实就是(pi++),但这里的++为后置加,所以先得到*pi为100之后,才会处理++的动作。因此语句先输出100,再将pi指向下一个地址。如下图所示。
接下来的
由于这条语句相当于(++pi),这里的 ++ 是前置加,所以pi指针先移到了下一个地址,再输出pi的值(300),如下图所示。
最后
这条语句相当于++(pi),由此可知,++是针对pi的值加1,这条语句等同于
将pi(= 300)加1,再放入pi中,如下图所示。
最后,*pi的运算结果为301