第7章指针C语言之所以被认为是功能最强大的语言之一,其中一个主要原因是其具有极高的自由度,而这个自由度在指针方面得到了充分的体现。指针是C语言中最具特色的部分,具有功能异常强大和用法极其灵活的特点。利用指针可以编写出既简洁又高效的程序,但过于灵活的指针功能也会带来一些副作用。7.1变量的指针与指针变量可为了理解指针的概念,先来看一下数据在内存中是如何存储的。在一个程序运行之前,需要首先将程序的代码和数据存入计算机内存中。为便于管理,通常将内存划分为一个一个的内存单元,在当今的计算机中一般以1字节作为一个内存单元。同时,给每个内存单元分配一个编号,称为内存单元的地址。7.1.1指针C语言程序中的数据,在内存中所占用内存单元的个数是由其类型决定的。例如,int型数据占用4个内存单元,char型数据占用1个内存单元。可以发现,不管一个变量占用几个内存单元,只要知道了这个变量第一个单元的地址和这个变量的长度,就能够从内存中找到这个变量。因此,C语言规定:将一个变量所占内存单元区的首地址,简称为这个变量的地址。例如,有如下变量定义:inta;char ch;假设C语言编译系统对这两个变量的内存分配情况如图7.1(a)所示,那么就说变量a的地址是2009,变量ch的地址是201320092009201020101002011201120122012chAch20132013(a)(b)图7.1变量的地址与变量的值
一旦为变量分配了内存单元,对变量的操作实质上就是对其内存单元的操作。例如:a=100;ch="A';这两条赋值语句实现的功能,就是将整数100的二进制补码形式,存入从地址2009开始的4个连续内存单元中,将字符常量'A'的二进制ASCII码存人地址为2013的1个内存单元中,如图7.1(b)所示。什么是指针呢?一个变量的指针其实就是这个变量的地址。只不过指针这个名称,在某些场合显得更加形象一些。7.1.2指针变量在程序中,有时需要将一个变量的地址存储到另一个变量中。那么,这种专门用来存储其他变量地址(指针)的变量,就称为指针变量。如果在一个指针变量中存储了另一个变量的地址,就形象地说该指针变量指向了这个变量。指针变量也必须先定义后使用,定义指针变量的一般形式为类型说明符*变量名;其中,“*”表明这是一个指针变量:“类型说明符”是这个指针变量所指向的变量的数据类型。例如:int *pifloat *qi其中,p、q都是指针变量,不过二者是有区别的。p是指向int型变量的指针变量,只能存储一个int型变量的地址;q是指向float型变量的指针变量,只能存储一个float型变量的地址。需要注意,这里的“*”是指针类型的符号,但并不是变量名的组成部分。也就是说,这里定义的指针变量名是p、,而不是*p、*q。7.2变量的间接引用指针的基本功能是实现变量的间接引用。为了实现这种功能,在程序中需要使用两个最基本的运算符:&和*。c语7.2.1取地址运算符&言程取地址运算符&用于得到一个变量的地址。其一般引用形式为库&变量名设该表达式的运算结果就是取地址运算符&之后的变量的内存地址。计【例7.1】获取变量的地址示例。新#include<stdio.h>思int main(void)路100
int i,*qi/*将变量1的地址赋给指针变量g*/q=&i;/*P用于以十六进制形式输出地址值*printf("q-opln",q);return O;程序运行结果:q=000000000022FE44需要注意,该程序的运行结果并不是固定不变的。因为变量i的内存空&i间是由编译系统随机分配的,所以这一次运行的结果跟下一次运行的结果有可能是不一样的。一旦将变量i的地址赋给了指针变量q,就形象地说q指向了变量i,如图7.2所示。图7.2&运7.2.2间接引用运算符*算符的使用间接引用运算符*也称作指针运算符,其一般使用形式为*指针变量该表达式的功能是间接引用给定的指针变量所指向的变量。【例7.2】通过指针变量实现间接引用。#include<stdio.h>intmain(void){inta,b,*p,*q;a=10;b=20;/*不能写成*p=&a;*/p=&a;/*不能写成*g=&b:*/q=&b;*p=100;*q=200;printf("a=%d,b=%din",a,b);return 0;程序运行结果:a=100,b=200这里的*p代表指针变量p所指向的变量,即变量a,因此*p=100与a=100是等价的;*g代表指针变量g所指向的变量,即变量b,因此*q=200与b=200是等价的。由此可见,对变量的访问有以下两种引用方式。(1)直接引用,即通过一个变量的变量名本身直接访问它。第例如:7a=10;章(2)间接引用,即通过一个指针变量对另一个变量进行间接访问。例如:指int a,*p;p=&a针*p=100;101
这里的*p就是对变量a的间接引用。【例7.3】通过间接引用方式,交换两个整型变量的值。编程思路:欲采用间接引用方式访问两个整型变量,需首先定义两个指针变量,并使之分别指向这两个整型变量。源程序:#include <stdio.h>int main(void)int a,b,t;int *pl,*p2;a=123;b=456;pl=&ai版社p2=&b;/*此语句等价于t=a;*/t=*pl;/*此语句等价于a=b;*/*p1=*p2;/*此语句等价于b=t:*/*p2=t;printf("a=ed,b=dln",a,b);printf("*pl=%d,*p2=%dln",*pl,*p2);return o;程序运行结果:a=456,b=123*p1=456,*p2=123在该程序中,由于指针变量pi和p2分别指向变量a和b,所以*pi就是变量a的间接引用,*p2就是变量b的间接引用。或许有人会问,在该程序中采用间接引用的形式有什么优势吗?其实并没有,此例只是用来说明如何采用间接引用的形式来访问变量。指针的优势主要体现在后面几章的字符串处理和跨函数间接引用等方面。7.2.3指针变量的初始化在定义一个指针变量的同时给它赋值,称为指针变量的初始化,例如:int a,*p=&a;c要特别注意,上述语句的功能等价于以下这两条语句:语言int a,*p;程p=&a;/ /使得p指向变量a而不是以下这两条语句:序设inta,*pi计//不是使得*p指向变量a*p=&a;新因为这里的*p不是指针变量名,所以不能存储地址。这就是C语言的特点,有时候过思于灵活与简洁往往容易产生歧义。路102
几点说明:(1)不能使用未经赋值的指针变量进行间接引用。这是因为在计算机的内存中,通常有多个程序同时运行。为了避免不同程序之间相互干扰而造成内存数据覆盖,规定每个程序只能访问在该程序中明确分配的内存数据区(如在该程序中定义的变量和数组的内存单元)未经赋值的指针变量的值是随机的,它指向随机的内存单元,这些内存单元不属于明确分配的内存数据区,因而是禁止访问的【错例】#include <stdio.h>int main(void)(int *p;/*指针变量p未经赋值*/*p=100;printf("*p=edin",*p):return 0;该程序运行时,将会显示应用程序错误提示,如m例.exea图7.3所示。错例.exe已停止工作Windows正在检重流问题的筛决方富(2)不能通过指定具体地址的方式对内存单元进行间接引用。这是因为在C语言中,内存单元是由编译取清系统负责管理和分配的。用户并不知道哪些内存单元是图7.3应用程序错误提示可用的,所以不能由用户直接指定内存单元的地址。【错例】#include<stdio.h>int main (void)(int *p;/*不能直接指定内存单元的地址*P=2000;*p=100;printf("*p=%d/n",*p);return 0;该程序运行时,同样将会显示如图7.3所示的错误提示。(3)两个类型不同的指针量之间,不能直接赋值。例如:int a,*p :floatx,*qip=&x;q=&a;这里的p=&x:和g-&a:都是错误的,因为赋值运算符两侧的类型不是赋值兼容的。第7品汇章7.3指针与一维数组指在C语言中,数组与指针的关系非常密切,可以说凡是用数组解决的问题都可以用指针解决。同时,可以通过指针灵活地访问数组的元素。针103