1
C语言程序设计
1.6.2 5.2 指针运算

5.2 指针运算

指针是一种值为地址值的特殊变量,指针的运算实质上是地址运算。除了赋值运算外,指针还有以下几种运算:

1.取地址运算(&)和取内容运算(*

如前所述,单目运算符“&”的功能是取操作对象的地址,单目运算符“*”的功能是取指针指向的目标变量的内容。这两个运算符互为逆运算。如有定义:

img417

第一个表达式表示取指针的目标变量*ptr(即变量x)的地址,亦即为指针ptr;第二个表达式表示取变量x的地址中所存储的内容,即表示变量x。

例如,有程序段:

  int*p,x,y;

  x=1;y=2;

  p=&x;

  *p=y;

  x=7;

  p=&y;

  *p=x;

如图5.2.1所示画出了各语句执行的情况:对指针变量赋地址值&x或&y,即将指针p指向变量x或y。对指针p所指向的目标变量*p赋值,即对p指针当前所指向的变量赋值。

执行过程:

img418

图5.2.1 指针赋值

例5-3 使用指针运算符“&”和“*”的简单程序。

程序如下:

img419

程序运行结果:

  u1=16 u2=16

表达式2*(v+5)是一般整型算术运算表达式,而表达式2**pv+5)中包含指针pv。由于v 和*pv均为pv的目标变量,其值相同,故两个表达式等效。

2.指针与整数的加减运算

指针变量加上或减去一个整数n,是指针由当前所指向的位置向前或向后移动n个数据的位置。通常这种运算只能用于指针指向一个数组中,由于各种类型的数据的存储长度不同,因此在数组中加减运算使指针移动n个数据后的实际地址与数据类型有关。

例如,如果编译器定义整形为16位(2字节),对指针加1操作的含义是:

  对char型,相当于当前地址加1个字节。

  对int型,相当于当前地址加2个字节。

  对float型,相当于当前地址加4个字节。

一般地,如果p是一个指针,n是一个正整数,则对指针p进行±n操作后的实际地址是:

  p±n*sizeof(数据类型)

其中,sizeof(数据类型)是取数据类型长度的运算符。

如有定义:

  char*p;

  int *q;

  float*t;

假设指针的当前地址值为:

  p=2110,q=2442,t=2488

则执行以下语句:

  p+=1; 结果是:p=p+1=2111

  q+=5; 结果是:q=q+2*5=2452

  t−=2; 结果是:t=t−2*4=2480

同样,指针自增(加1)、自减(减1)的运算也是地址运算。指针加1运算后指针指向下一个数据,指针减1运算后,指针指向上一个数据的起始位置。

指针自增、自减单目运算也分前置和后置运算,当它们与其他运算符组成一个表达式时,应注意其优先顺序和结合性。

例如,p为指针变量:

  v=*p++;

*”与“++”的优先级高于“=”,而“*” 与“++”两个单目运算符的优先级相同,其结合性为从右到左。以上赋值语句相当于

  v=*(p++);

由于p++是后置运算,运算规则为“先引用后增值”,故运算步骤为:

①先取指针p当前所指目标变量的值,赋予变量v;

②p做增1运算,即指针p指向下一个目标变量。

又如:

  v=*++p;

则指针p先进行自增1的运算,即指针p指向下一个目标变量,再将目标变量的值赋给v。

下面两个表达式具有不同的意义:

  v=(*p)++;

  v=++(*p);

前者是将目标变量*p的值赋予变量v,然后变量*p自增1;后者是将目标变量*p的值自增1后赋予变量v。

3.指针相减运算

在一定条件下,两个指向同种数据类型的指针可以相减。例如,指向同一数组的两个指针相减,其差表示这两个指针所指向的数组元素之间所相差的元素个数。可见,指针相减的运算并不是两个指针的值单纯相减,而与数据类型的存储长度有关,编译程序按下式进行运算:

(两指针地址值之差)÷(一个数据项存储字节数)

例5-4 指针相减的运算。

程序如下:

img420

程序运行结果:

  px=194 py=19e

  py−px=5

程序第8、9行分别将a[0]和a[5]的地址赋予指针变量px和py。根据运算结果,编译程序给数组a分配的首地址为194(十六进制),即为a[0]的地址,亦即指针px的值。而a[5]的地址,即py的值为19e。由于px、py定义为指向整型数组a的指针,每个数组元素占2个字节的长度,故py−px=(19e−194)÷2=5,即指针py与指针px之间相差5个数组元素。

4.指针的关系运算

两个指向同种数据类型的指针可做关系运算。指针的关系运算表示它们所指向的地址之间的关系。

指针间允许4种关系运算:

〈 或 〉  比较两指针所指向的地址的大、小关系。

= =或!=  判断两指针是否指向同一地址,即是否指向同一数据。

若有指针p和q,指向同一类型的数据,关系表达式为:

  p〈q

当p指针所指向变量的地址(p的值)小于q指针所指向变量的地址(q的值)时。表达式值为非零,否则为零。

又如:

  p==q 若表达式值为非零,表示指针p、q指向同一变量。

  p!=q 若表达式值为非零,表示指针p、q不指向同一变量。

指针不能与一般数值进行关系运算,但指针可以和零(NULL字符)之间进行等于或不等于的关系运算,如:

  p==0;  p!=0; 或 p==NULL; p!=NULL;

用于判断指针p是否为空指针。

综上所述,由于指针的运算实质上是地址运算,因此,指针运算是很有限的,除了以上四类运算外,其他运算都是非法的。

常见的编程错误5.2

img421 间接引用一个未被正确初始化的或未被赋值指向变量地址的指针,可能导致致命的运行错误,或意外修改了重要数据,以致程序运行结束后可能得到错误结果。

img422 试图间接引用非指针变量,会导致编译错误。

img423 间接引用空指针,通常导致致命的运行错误。

img424 当需要间接引用一个指针以获取该指针指向的值时,却不间接引用。