将把 c 的地址赋给变量 p,我们称 p 为“指向”c的指针。地址运算符
&
只能应用于内存中的对象,即变量与数组元素。它不能作用于表达式、常量或
register
类型的变量。
一元运算符
*
是间接寻址或间接引用运算符 。当它作用于指针时,将访问指针所指向的对象。我们在这里假定 x 与 y 是整数,而
ip 是指向 int 类型的指针
,下面的代码段说明了如何在程序中声明指针以及如何使用运算符
&
和
*
:
1 2 3 4 5 6
int x = 1, y = 2, z[10]; int *ip; /* ip is a pointer to int */ ip = &x; /* ip now points to x */ y = *ip; /* y is now 1 */ *ip = 0; /* x is now 0 */ ip = &z[0]; /* ip now points to z[0] */
不管指针指向什么类型的数据,指针本身占4个字节的空间。
指针的声明
1
int *ip;
这样声明是为了便于记忆。该声明语句表明表达式 *ip 的结果是 int 类型。这种声明变量的语法与声明该变量所在表达式的语法类似。
在这个例子中我们还看到,如果给程序建立符号链接,然后通过符号链接运行这个程序,就可以得到不同的argv[0]。通常,程序会根据不同的命令行参数做不同的事情,例如
ls -l
和
ls -R
打印不同的文件列表,而有些程序会根据不同的argv[0]做不同的事情,例如专门针对嵌入式系统的开源项目Busybox,将各种Linux命令裁剪后集于一身,编译成一个可执行文件busybox,安装时将busybox程序拷到嵌入式系统的/bin目录下,同时在/bin、/sbin、/usr/bin、/usr/sbin等目录下创建很多指向/bin/busybox的符号链接,命名为cp、ls、mv、ifconfig等等,不管执行哪个命令其实最终都是在执行/bin/busybox,它会根据argv[0]来区分不同的命令。
指向数组的指针与多维数组
以下定义一个指向数组的指针,该数组有10个int元素:
1
int (*a)[10]; /* a points to an array of 10 ints */
用 typedef 类型定义可使指向多维数组元素的指针更容易读、写和理解。上面的句子可以拆成两句:
1 2
typedefint int_array[10]; int_array *a;
t代表由10个int组成的数组类型,a则是指向这种类型的指针。
下面代码分别演示了上述的两种定义方法。
直接定义一个指向多维数组的指针:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#include<iostream> usingnamespacestd; intmain() { int ia[3][4] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; typedefint int_array[4]; int (*p)[4]; for (p = ia; p != ia + 3; ++p) { for (int *q = *p; q != *p + 4; ++q) cout << *q << endl; } }
用 typedef 简化指向多维数组的指针:
1 2 3 4 5 6 7 8 9 10 11 12
#include<stdio.h> intmain() { int ia[3][4] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; typedefint int_array[4]; for (int_array *p = ia; p != ia + 3; ++p) { for (int *q = *p; q != *p + 4; ++q) printf("%d\n", *q); } }
下列代码演示了使用
pa
或
ppa
访问数组 a 中的
r
元素。注意理解 pa 和 ppa 所保存的内容的不同:
#include<stdio.h> intsort(int a, int b) { return a > b ? a : b; } intmain(void) { int (*max)(int a, int b) = sort; /* 声明一个函数指向 sort */ printf("TEST: %d is same as %d.\n", max(2, 3), sort(2, 3)); return0; }