C提供了6种基本的指针操作,下面的程序将具体演示这些操作。为了显示每一个操作的结果,程序将打印出指针的值(即指针指向的地址)、指针指向地址中存储的内容,以及指针本身的地址(如果您的编译器不支持%p说明符,那么想要打印出地址,就需要使用%u或者%lu)。
程序清单10.13示例了可对指针8种基本操作。除了这些操作,你还可以使用关系运算符来比较指针。
程序清单10.13 ptr_ops.c程序
//ptr_ops.c指针操作
#include <stdio.h>
int main(void)
{
int urn[5]={100,200,300,400,500};
int * ptr1,* ptr2,* ptr3;
ptr1 = urn; //把一个地址赋给指针
ptr2 = &urn[2]; //同上
//取得指针指向的值,并且得到指针的地址
printf("pointer value, dereferenced pointer, pointer address:\n");
printf("ptr1 = %p,*ptr1 = %d,&ptr1 = %p\n",
ptr1,*ptr1,&ptr1);
//指针加法
ptr3 = ptr1 + 4;
printf("\nadding an int to a pointer:\n");
printf("ptr1 + 4 = %p, *(ptr1+3)=%d\n",
ptr1+4,*(ptr1+3));
//递增指针
ptr1++;
printf("\nvalues after ptr1++\n");
printf("ptr1 = %p,*ptr1 = %d,&ptr1 = %p\n",
ptr1,*ptr1,&ptr1);
//递减指针
ptr2--;
printf("\nvalues after ptr2--\n");
printf("ptr2 = %p,*ptr2 = %d,&ptr2 = %p\n",
ptr2,*ptr2,&ptr2);
//恢复为初始值
--ptr1;
++ptr2;
printf("\npointers reset to original values:\n");
printf("ptr1 = %p,ptr2 = %p\n",
ptr1,ptr2);
//一个指针减去另一个指针
printf("\nsubtracting one pointer from another:\n");
printf("ptr2 = %p, ptr1 = %p,ptr2 - ptr1 = %d\n",
ptr2,ptr1,ptr2-ptr1);
//一个指针减去一个整数
printf("\nsubtracting an int from a pointer:\n");
printf("ptr3 = %p, ptr3 - 2 = %p\n",
ptr3,ptr3 - 2);
return 0;
}
下面的列表描述了可对指针变量执行的基本操作:
** 赋值(assignment)---可以把一个地址赋给指针。通常使用数组名或地址运算符&来进行赋值。注意:地址应该和指针类型兼容。也就是说,不能把一个double类型的地址赋给一个指向int的指针。
** 求值(value - finding)或取值(dereferencing)---运算符*可取出指针指向地址中存储的数值。因此,*ptr1开始为100,即存储在地址0x0012ff38中的值。
** 取指针地址---指针变量同其他变量一样具有地址和数值,使用运算符&可以得到存储指针本身的地址。本例中,ptr1被存储在内存地址ox0012ff34中。该内存单元的内容是0x0012ff38,即urn的地址。
** 将一个整数加给指针---可以使用+运算符来把一个整数加给一个指针,或者把一个指针加给一个正数。两种情况下,这个整数都会和指针所指类型的字节数相乘,然后所得结果会加到初始地址上。于是ptr1+4的结果就等同于&urn[4]。如果相加的结果超出了初始指针所指向数组的范围,那么这个结果是不确定的,除非超出数组最后一个元素的地址能够确保是有效的。
** 增加指针的值 ---可以通过一般的加法或增量运算符来增加一个指针的值。对指向某数组元素的指针做增量运算,可以让指针指向数组的下一个元素。因此,ptr1++运算把ptr1加上数值4(我们系统上int为4个字节),使ptr1指向urn[1]。现在ptr1的值是0x0012ff3c,*ptr1的数值为200。请注意ptr1本身的地址仍然是0x0012ff34。别忘了,变量是不会因为它的值的变化而移动位置的。
** 从指针中减去一个整数 ---可以使用-运算符来从一个指针中减去一个整数。指针必须是第一个操作数,或者是一个指向整数的指针。这个整数都会和指针所指类型的字节相乘,然后所得到的结果会从初始地址中减掉。于是,ptr3-2的结果等同于&urn[2],因为ptr3是指向&urn[4]的。如果相减结果超出了初始指针所指向的数组范围,那么这个结果是不确定的,除非超出数组最后一个元素的地址能够确保有效。
** 减小指针的值---指针当然也可以做减量运算。请注意,你可以使用前缀或后缀形式的增量和减量运算符。
** 求差值(Differencing)---可以求出两个指针之前的差值。通常对分别指向同一个数组内的两个元素的指针求差值,以求出元素之间的距离。差值的单位是相应类型的大小。有效指针差值运算的前提是参加运算的两个指针是指向同一个数组(或是其中之一指向数组后面的第一个地址)。
** 比较---可以使用关系运算符来比较两个指针的值,前提是两个指针具有相同的类型。
注意,这里有两种形式的减法。可以用一个指针减掉另一个指针得到一个整数,也可以从一个指针中减掉一个整数得到一个指针。
在进行指针的增量和减量运算时,要牢记一些注意事项。计算机并不检查指针是否仍然指向某个数组元素。C保证指向数组元素的指针和指向数组后的第一个地址的指针都是有效的。
另外,可以对指向一个数组元素的指针进行取值运算。但不能对指向数组后的第一个地址的指针进行取值运算,尽管这样的指针是合法的。
特别注意:不能对未初始化的指针取值。
切记:当创建一个指针时,系统只分配了用来存储指针本身的内存空间,并不分配有来存储数据的内存空间。因此在使用指针之前,必须给它赋予一个已分配的内存地址。比如,可以把一个已存在的变量地址赋给指针。
指针的最初功能在于同函数交换信息。从前面所学的内容可知,如果需要让被调函数修改调用函数中的变量,就必须使用指针。
指针的另一个基本功能是用在处理数组的函数中。