C Primer Plus 第9章 函数 9.7 指针简介

原创
2016/07/15 07:05
阅读数 77

一般来讲,指针是一个其数值为地址的变量(或更一般地说是一个数据对象)。
正如char类型的变量用字符作为其数值,而int类型变量的数值是整数,指针变量的数值表示的是地址。
如果您将某个指针变量命名为ptr,就可以使用如下语句:
ptr=&pooh;    /*把pooh的地址赋给ptr*/
对于这个语句,我们称ptr指向poohptr和&pooh的区别在于前者为一变量,而后者是一个常量。当然,ptr可以指向任何地方:
ptr=%bah;    /*令ptr指向bah而不是pooh*/
这时,ptr的值是bah的地址。
要创建一个指针变量,首先需要声明其类型。假设您想把ptr声明为可以存放一个int数值的地址,就需要 使用下面介绍的新运算符。

9.7.1  间接运算符
假定ptr指向bah,如下所示:
ptr = &bah;
这时就可以使用间接(indirection)运算符*(也称作取值(dereferencing))来获取bah中存放的数值(不要把这种一元运算符和表示乘法的二元运算符*相混淆)。
val = *ptr;  /*得到ptr指向的值*/
语句ptr=&bah;以及语句val=*ptr;放在一起等同于下面的语句:
val = bah;
由此看出,使用地址运算符和间接运算符可以间接完成上述语句的功能,这也正是“间接运算符”名称的由来。

9.7.2  指针声明
pointer ptr;  /*不能这样声明一个指针*/
为什么不能这样声明?因为这对于声明一个变量为指针是不够的,还需要说明指针所指向变量的类型原因是不同的变量类型占用的存储空间大小不同,而有些指针操作需要知道变量类型所占用的存储空间。同时,程序也需要了解地址中存储的是何种类型的数据。例如,long和float两种类型的数值可能使用相同大小的存储空间,但是它们的数据存储方式完全不同。指针的声明形式如下:
int *pi;  /*pi是指向一个整数变量的指针*/
char *pc; /*pc是指向一个字符变量的指针*/
float *pf,*pg;  /*pf和pg是指向浮点变量的指针*/
类型标识符表明了被指向变量的类型,而星号(*)表示该变量为一指针。声明int *pi; 的意思是pi是一个指针,而且*pi是int类型的。
*和指针之间的空格是可选的。
pc所指向的值(*pc)是char类型的。而pc本身又是什么类型呢?我们把它描述为“指向char的指针”类型。pc的值是一个地址,在大多数系统内部,它由一个无符号整数表示。但是,这并不表示可以把指针看作是整数类型。一些处理整数的方法不能用来处理指针,反之亦然。例如,可以进行两个整数相乘,而指针则不能。因此,指针的确是一种新的数据类型,而不是整数类型。所以,正如前面提到的,ANSI C 专门为指针提供了%p输出格式 。

9.7.3  使用指针在函数间通信

在程序清单9.15中,函数interchange()使用了指针参数,我们将对该函数进行详细的讨论。

程序清单9.15 swap3.c程序

#include <stdio.h>
void interchange(int *u,int *v);
int main(void)
{
    int x = 5,y = 10;
    printf("Originally x = %d and y=%d.\n",x,y);
    interchange(&x,&y);  /*向函数传送地址*/
    printf("Now x = %d and y = %d.\n",x,y);
    return 0;
}

void interchange(int *u,int *v)
{
    int temp;
    temp = *u;  /*temp得到u指向的值*/
    *u = *v;
    *v = temp;
}

下面我们分析程序清单9.15的运行情况,首先,函数调用语句如下:

interchange(&x,&y);

可以看出,函数传递的是x和y的地址而不是它们的值。这就意味着interchange()函数原型声明和定义中的形式参数u和v将使用地址作为它们的值。因此,它们应该声明为指针。由于x和y都是整数,所以u和v是指向整数的指针。其声明如下:

void interchange(int *u,int *v)

接下来,函数体进行如下声明:

int temp;

从而提供了所需的临时变量。为了把x的值存储在temp中,需要使用以下语句:

temp = *u;

注意,因为u的值是&x,所以u指向x的地址。这就意味着*u代表了x的值,而这正是我们需要的数值。不要写成如下这样:

temp  = u;  /*这样做不行*/

上面的语句中,因为赋给变量temp的只是x的地址而不是x的值,所以不能实现数值的交换。

同样,把y的值赋给x,需要使用下面的语句:

*u = *v;

其执行结果相当于:

x = y;

在示例程序中,我们用一个函数实现了x和y的数值交换。首先,函数使用xy的地址作为参数,这使它可以访问xy变量。通过使用指针和运算符*,函数可以获得相应存储地址的数据,从而就可以改变这些数据。

通常情况下,可以把关于变量的两类信息传递给一个函数。如果函数的调用形式如下:

funcation (x);

这是传递的是x的值。但是如果使用下面这种函数调用形式:

funcation (&x);

那么会把x的地址传递给函数。第一种调用形式要求函数定义部分必须包含一个和x具有相同数据类型的形式参数。如下所示:

int function (int num);

而第二种形式要求函数定义部分的形式参数必须是指向相应数据类型的指针:

int funcation (int *ptr);

使用函数进行数据计算等操作时,可以使用第一种形式。但是,如果需要改变调用函数中的多个变量的值时,就需要使用第二种形式。其实,使用scanf()时已经使用了第二种形式。例如,当需要为变量num读取一个数值时,可以调用函数scanf("%d",&num);该函数调用的意思是先读取一个数值,然后将其存储到通过参数获得的地址中。

尽管interchange()只使用局部变量,但是通过使用指针,该 函数可以操作main()中变量的值。

***************************************************

关于变量:变量名称、地址和数值

前面关于指针的讨论中,变量名称、地址以及数值之间的关系是其关键所在。

编写程序时,一个变量一般有两种属性:变量名和数值(当然,还有其他属性,如数据类型等,但它们与这个主题无关)。程序被编译和加载后,同一个变量在计算机中的两个属性是地址和数值变量的地址可以被看作是在计算机中变量的名称

在许多编程语言中,变量地址只由计算机处理,对于编程人员来讲完全不可见。但是在C中,可以使用运算符&对变量的地址进行操作。

&barn就表示变量barn的地址。

可以通过使用变量名获得变量的数值。

例如printf("%d\n",barn)输出的是barn的数值。

当然 ,也可以使用运算符*从地址中获取相应的数值。

对于语句pbarn = &barn;,*pbarn是存储在地址&barn中的数值。

总之,普通的变量把它的数值作为基本数值量,而通过使用运算符&将它的地址作为间接数值量。但是对于指针 来讲,地址是它的基本数值量,使用运算符*后,该地址中存储的数值是它的间接数值量。

 

展开阅读全文
打赏
0
1 收藏
分享
加载中
更多评论
打赏
0 评论
1 收藏
0
分享
返回顶部
顶部