从头学C(43)指针与地址

0

指针是一种保存变量地址的变量,在C语言中,用途非常广泛,而且它与数组的关系非常紧密,这也是我们即将开始学习的第五章的内容核心。

第五章 指针与数组 >> 5.1 指针与地址

通过一个简单示意图来看下内存如何存储数据的。

一般机器都有一系列连续编号/编址的存储单元,这些存储单元可以单个操作,也可以连续成组的操作。而机器的一个字节可以存放一个 char 类型的数据,两个相邻字节存储单元可存放一个 short 类型的数据,四个相邻字节存储单元可存储一个 long 类型的数据。

指针是能够存放一个地址的一组存储单元(通常是 4 个字节)。加入 c 是一个 char 类型变量,p 是一个指向 c 的指针,那么可用下图来表示它们的关系:

C语言_指针示意图

一元运算符 & 用于取一个对象的地址。我们称 p 是一个指向 c 的指针,实际上是把 c 的地址赋给变量 p,如下列语句:

p = &c;

要注意:地址运算符 & 只能用于内存中的对象,即变量与数组元素,它不能作用域表达式、常量或 register 类型的变量。

与取对象地址相对应的是,一元运算符 * 是间接寻址或间接引用运算符。它作用于指针时,是访问指针所指向的对象。

下面这段代码详细说明了关于 & 和 * 运算符的使用,以及如何声明指针:

int x = 1, y = 2, z[10];
int *ip;    /* 声明 ip 是一个指向 int 类型的指针 */

ip = &x;    /* 取变量 x 的地址赋给ip,ip 现在指向变量 x */
y = *ip;    /* 取 ip 所指向的单元的值,赋给变量 y, y = 1 */
*ip = 0;    /* 将 ip 所指向的单元的值修改为 0,即将变量 x 的值改为 0 */
ip = &z[0]; /* ip 指向数组 z 的第一个单元,即 z[0] */

可以看到指针的声明是 “int *ip”,该声明是为了便于记忆,表明表达式 *ip 的结果是 int 类型。基于同样的原因,对函数的声明也可以采用这种方式,例如:

double *dp, atof(char *);

其中 *dp 和 atof(s) 的值都是 double 类型,其 atof 的参数是一个指向 char 类型的指针。

细心的同学应该注意到了,指针只能指向某种特定类型的对象,比如 int、double,也就是说每个指针都必须指向某种特定的数据类型。(当然指向 void 类型的指针是个例外,后面我们会看到它的特性)

一元运算符 * 和 & 的优先级比算术运算符的优先级高,因此赋值语句:

y = *ip + 1;

是把 *ip 指向的对象的值取出来并加 1,再讲结果赋给 y。

另外,

*ip += 1;

是将 ip 指向的对象的值加 1,等价于:

++*ip;

(*ip)++

语句 (*ip)++ 中的圆括号不能省略,否则该表达式的实际结果是对 ip 进行加 1 运算。这是因为类似 * 和 ++ 这样的医院运算符遵循从右到左的结合顺序,所以我们建议即使是类似 ++*p 的语句,最好也都显式的加上圆括号,以强调语句执行的意图,即 ++(*p)。

最后,指针作为变量,是可以在程序中直接使用的,不必通过间接引用的方法。比如,如果 iq 是另一个指向 int 类型的指针,那么下列语句

iq = ip;

是将 ip 中的值(ip 所指向单元的地址)拷贝到 iq中,这样指针 iq 也将指向 ip 所指向的对象。

Leave A Reply