1、为了说清楚什么是指针,必须弄清楚数据在内存中为了说清楚什么是指针,必须弄清楚数据在内存中是如何存储的,又是如何读取的。是如何存储的,又是如何读取的。 计算机中,所有的数据都是存放在存储器的内存计算机中,所有的数据都是存放在存储器的内存单元中的。一般把存储器中一个字节称为一个内存单元中的。一般把存储器中一个字节称为一个内存单元,不同数据类型所占用的内存单元数不等,如单元,不同数据类型所占用的内存单元数不等,如整型变量占整型变量占2个字节,字符变量占个字节,字符变量占1个字节等。个字节等。 为了正确地访问这些内存单元,必须为每个内存为了正确地访问这些内存单元,必须为每个内存单元编上号,根据一个内存
2、单元的编号即可准确地单元编上号,根据一个内存单元的编号即可准确地找到该内存单元。找到该内存单元。内存单元的编号,称为内存单元的编号,称为“地址地址” 。内存单元的内存单元的地址地址和内存单元的和内存单元的内容内容是两个不同的概念:是两个不同的概念:假设程序中定义了整型变量假设程序中定义了整型变量i,并赋值为,并赋值为3。编译时系统。编译时系统分配分配2000和和2001两个字节给变量两个字节给变量i,此时两个内存单元,此时两个内存单元的编号为单元的地址,其中存放的数据即是该单元的内的编号为单元的地址,其中存放的数据即是该单元的内容。容。两种访问方式:两种访问方式:直接访问方式:直接访问方式:在
3、程序中一般是通过变量名来对内存单元进行存取操作在程序中一般是通过变量名来对内存单元进行存取操作的,其实程序在编译后,已经将变量名转换成变量的地的,其实程序在编译后,已经将变量名转换成变量的地址,对变量值的存取都是通过地址进行的。址,对变量值的存取都是通过地址进行的。间接访问方式:间接访问方式: 将变量将变量i的地址存放在另一个变量中,的地址存放在另一个变量中,C语言规定,可语言规定,可以在程序中定义一种特殊的变量,用来存放地址。以在程序中定义一种特殊的变量,用来存放地址。假设定义一个变量假设定义一个变量p,用来存放整型变量的地址,它被,用来存放整型变量的地址,它被分配为分配为3010、3011
4、两个字节。两个字节。可以通过下面语句将可以通过下面语句将i的地址的地址(2000)存放到存放到p:p=&i; 对变量对变量i是访问,可直接访问,已知变量是访问,可直接访问,已知变量i的地址,根的地址,根据此地址直接对变量据此地址直接对变量i的存储单元进行存取访问;的存储单元进行存取访问; 也可间接访问,先找到存放变量也可间接访问,先找到存放变量i的地址的变量的地址的变量p,从,从其中得到变量其中得到变量i的地址,然后找到变量的地址,然后找到变量i的存储单元,对的存储单元,对它进行存取范围。它进行存取范围。 一个变量的地址称为该变量的一个变量的地址称为该变量的“指针指针”。如,地址。如,地址20
5、00是变量是变量i的指针。的指针。 C语言中,用一个变量存放指针语言中,用一个变量存放指针(地址地址),此变量称为,此变量称为指针变量指针变量,上述的变量,上述的变量p是指针变量,指针变量的值是是指针变量,指针变量的值是某个内存单元某个内存单元 的地址的地址(指针指针)。 严格地说,一个指针是一个地址,是一个常量;而一严格地说,一个指针是一个地址,是一个常量;而一个指针变量却可以被赋予不同的指针值,是变量。但通个指针变量却可以被赋予不同的指针值,是变量。但通常把指针变量简称指针。常把指针变量简称指针。指针变量的值不仅可以是变量的地址,也可以是其他数指针变量的值不仅可以是变量的地址,也可以是其他
6、数据结构的地址。据结构的地址。例如:在一个指针变量中可存放一个数组或一个函数的例如:在一个指针变量中可存放一个数组或一个函数的首地址。首地址。区别:区别:变量的指针变量的指针和和指针变量指针变量1.变量的指针就是变量的地址。变量的指针就是变量的地址。2.存放变量地址的变量是指针变量,它用来指向存放变量地址的变量是指针变量,它用来指向另一个变量。另一个变量。 为了表示指针变量和它所指向的变量之间的联系,为了表示指针变量和它所指向的变量之间的联系,在程序中用在程序中用“ * ”符号表示符号表示“指向指向”。 若已定义若已定义i_pointer为指针变量,则为指针变量,则* i_pointer是是i
7、_pointer所指向的变量,因此所指向的变量,因此* i_pointer也代表一个也代表一个变量,它和变量变量,它和变量i是同一回事。是同一回事。下面两个语句作用相同:下面两个语句作用相同:(1)i=3;(2) * i_pointer=3;第二个语句含义是将第二个语句含义是将3赋给指针赋给指针变量变量i_pointer所指向的变量所指向的变量i.一、一、 指针变量的定义指针变量的定义指针变量在使用前必须先定义,一般形式为:指针变量在使用前必须先定义,一般形式为: 类型说明符类型说明符 *指针变量名;指针变量名;其中,其中,*表示这是一个指针变量,表示这是一个指针变量,类型说明符类型说明符 表
8、示该指表示该指针变量所指变量的数据类型。针变量所指变量的数据类型。例如:例如:int *p1;(其中其中p1(而不是而不是 *p1)是一个指向整型变量的指针变量,是一个指向整型变量的指针变量,它的值是某个整型变量的地址。它的值是某个整型变量的地址。) float *p2;(其中其中p2是指向浮点型变量的指针变量是指向浮点型变量的指针变量)说明:说明:(1)指针变量名的构成原则是标识符,前面必须有指针变量名的构成原则是标识符,前面必须有“ * ” , 表示该变量的类型是指针型变量。表示该变量的类型是指针型变量。(2)在一个定义语句中,可以同时定义普通变量、数组、在一个定义语句中,可以同时定义普通
9、变量、数组、 指针变量。指针变量。(3)类型说明符说明的数据类型不是指针变量中存放的类型说明符说明的数据类型不是指针变量中存放的数据的数据类型,而是它数据的数据类型,而是它将要指向的变量或数组的数据将要指向的变量或数组的数据类型类型。因此,一个指针变量只能用来指向同种数据类型。因此,一个指针变量只能用来指向同种数据类型的其他变量或数组,不能时而指向一个浮点型变量,时的其他变量或数组,不能时而指向一个浮点型变量,时而指向一个整型变量。而指向一个整型变量。二、二、 指针变量的引用指针变量的引用 指针变量中只能存放变量的地址,绝不能存放任何指针变量中只能存放变量的地址,绝不能存放任何其他数据。其他数
10、据。例如:例如:int *p; p=2000; /*2000是一个整数而不是一个地址是一个整数而不是一个地址*/C语言提供两种有关的运算符:语言提供两种有关的运算符:(1)&:取地址运算符取地址运算符 (用来表示变量的地址用来表示变量的地址)(2)* :取内容运算符取内容运算符 (用来取其指向的内容,或称用来取其指向的内容,或称“间接间接 访问访问”运算符,或称指针运算符运算符,或称指针运算符)两种运算符都是单目运算符,其结合性都为自右向左,两种运算符都是单目运算符,其结合性都为自右向左,优先级别相同。优先级别相同。例如:例如:&a为变量为变量a的地址,的地址, *p为指针变量为指针变量p所指
11、向的内存单元的内容所指向的内存单元的内容 (即即p所指向的变量的值所指向的变量的值)。说明:说明:(1)设有指向整型变量的指针变量设有指向整型变量的指针变量p,若要把整型变量,若要把整型变量a的地址赋予的地址赋予p,有以下方式:,有以下方式: 指针变量初始化的方法:指针变量初始化的方法: int a; int *p=&a; 赋值语句的方法:赋值语句的方法: int a,*p; p=&a;(2)指针运算符指针运算符*和指针变量说明中的和指针变量说明中的指针说明符指针说明符*不是不是一回事。后者表示其后的变量是指针类型,前者则是一一回事。后者表示其后的变量是指针类型,前者则是一个运算符用以表示指针
12、变量所指的变量。个运算符用以表示指针变量所指的变量。说明:说明:(3)如果已执行了语句如果已执行了语句p=&a; ,则:,则: &*p:先进行:先进行*p的运算,即是变量的运算,即是变量a,再执行,再执行&运算运算, 即变量即变量a的地址。的地址。因此因此&*p与与&a相同。相同。 *&a:先进行:先进行&a的运算,即得的运算,即得a的地址,再执行的地址,再执行*运运 算算, 即即&a所指向的变量,即变量所指向的变量,即变量a。 因此因此*&a与与a相同。相同。#include void main( )int a,b; int *p1,*p2; a=100; b=10; p1=&a; p2=&
13、b; printf(“%d,%d n”,a,b); printf(“%d,%d n”,*p1,*p2);例例: : 通过指针变量访问整型变量。通过指针变量访问整型变量。 运行结果:运行结果:100,10100,10#include void main( )int a=5,b,c,*p; p=&a; b=*p; c=a+*p; printf(“%d,%d n”,b,c);例例: : 通过指针变量进行运算。通过指针变量进行运算。 运行结果:运行结果:5,10说明:说明:(1) 指针变量的运算种类也是有限的,它只能进行赋值指针变量的运算种类也是有限的,它只能进行赋值运算和部分算术运算及关系运算。运算
14、和部分算术运算及关系运算。(2) 指针变量还可以赋空值,其赋空值后,则可以使用,指针变量还可以赋空值,其赋空值后,则可以使用,只是它不指向具体的变量而已。只是它不指向具体的变量而已。 例如:例如:#define NULL 0 int *p=NULL;三、三、 指针变量作函数参数指针变量作函数参数#includeswap(int x,int y)int t; t=x; x=y; y=t;void main( )int a=3,b=5; if(ab) swap(a,b); printf(“a=%d,b=%d n”,a,b);C C语言是通过传值将参数传递给函数的,对被调函数来说,语言是通过传值将参
15、数传递给函数的,对被调函数来说,没有直接的方法来改变主调函数内的变量的值。没有直接的方法来改变主调函数内的变量的值。 例:对两个整数按大小顺序输出。例:对两个整数按大小顺序输出。运行结果:运行结果:a=3,b=5#includeswap(int *x,int *y)int t; t=*x; *x=*y; *y=t;void main( )int a=3,b=5; if(ab) swap(&a,&b); printf(“a=%d,b=%d n”,a,b);使主调函数传递指向要被改变量的指针,即可使被调函数使主调函数传递指向要被改变量的指针,即可使被调函数能改变主调函数的参数值。能改变主调函数的参
16、数值。例:对两个整数按大小顺序输出。例:对两个整数按大小顺序输出。运行结果:运行结果:a=5,b=3 一个数组是由连续的一块内存单元组成的,数一个数组是由连续的一块内存单元组成的,数组名即是这块连续内存单元的首地址。组名即是这块连续内存单元的首地址。 一个变量有地址,一个数组包含若干元素,每一个变量有地址,一个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们都有个数组元素都在内存中占用存储单元,它们都有相应的地址。相应的地址。指针变量既然可以指向变量,当然指针变量既然可以指向变量,当然也可以指向数组元素也可以指向数组元素(把某一元素的地址放到一(把某一元素的地址放到一个指针变量中)。
17、所谓个指针变量中)。所谓数组元素的指针就是数组数组元素的指针就是数组元素的地址元素的地址。 指向数组的指针变量称为指向数组的指针变量称为数组指针变量数组指针变量。其一般形式为:其一般形式为:类型说明符类型说明符 * *指针变量名;指针变量名;其中,类型说明符表示所指数组的类型。从中可其中,类型说明符表示所指数组的类型。从中可以看出指向数组的指针变量和指向普通变量的指以看出指向数组的指针变量和指向普通变量的指针变量的说明是相同的。针变量的说明是相同的。一、指向数组元素的指针一、指向数组元素的指针说明:说明:设有实型数组设有实型数组a,指向,指向a的指针变量为的指针变量为pa,则有以下关系:,则有
18、以下关系:pa,a,&a0均指向同一内存单元,它们是数组均指向同一内存单元,它们是数组a的首的首地址,即是地址,即是a0的首地址;的首地址;pa+1,a+1,&a1均指向元素均指向元素a1的地址;的地址;pa+i,a+i,&ai均指向元素均指向元素ai的地址。的地址。*(pa+i),*(a+i)是是pa+i 或或a+i 所指向的数组元素,即所指向的数组元素,即ai注意:注意:pa是变量,是变量,a与与&ai都是常量都是常量(地址地址)。引入指针变量后,可以用两种方法来访问数组元素:引入指针变量后,可以用两种方法来访问数组元素:1.下标法:采用下标法:采用ai形式访问数组元素:形式访问数组元素:
19、2.指针法:采用指针法:采用*(pa+i)或或*(a+i)形式,用间接访问的形式,用间接访问的 方法来访问数组元素,即通过指向数组元方法来访问数组元素,即通过指向数组元 素的指针找到所需的元素。素的指针找到所需的元素。例例:(1)int a; (2)int a; 初始化赋值初始化赋值 int *p=&a0; int *p=a; (3)int a; (4)int a; 赋值语句赋值赋值语句赋值 int *p; int *p; p=&a0; p=a;按按C C语言的规定:如果指针语言的规定:如果指针p p已指向数组中的一个元素,已指向数组中的一个元素,则则p+1p+1指向同一数组中的下一个元素指向
20、同一数组中的下一个元素,而不是将,而不是将p p的值的值( (地址值地址值) )简单地加简单地加1 1。例如:例如:数组元素是数组元素是floatfloat型,每个元素占型,每个元素占4 4个字节,则个字节,则p+1p+1意味意味着使着使p p的值的值( (地址值地址值) )加加4 4个字节,以使它指向下一个元个字节,以使它指向下一个元素,此时,素,此时,p+1p+1所代表的地址实际上是所代表的地址实际上是p+1 dp+1 d,d d是一是一个数组元素所占的字节数。个数组元素所占的字节数。二、通过指针引用数组元素二、通过指针引用数组元素(1)下标法下标法 #include void main(
21、 )int a10,i; for(i=0;i10;i+) scanf(“%d”,&ai); printf(“n”); for(i=0;i10;i+) printf(“%d”,ai); printf(“n”);例:输出数组中的全部元素。例:输出数组中的全部元素。( (设一个设一个a a数组,整型,有数组,整型,有1010个元素,要输出各元素的值有个元素,要输出各元素的值有3 3种方法种方法) )(2)通过数组名计算数组元素通过数组名计算数组元素 的地址,找出元素的值的地址,找出元素的值 for(i=0;i10;i+) printf(“%d”,*(a+i);(3)用指针变量指向数组元素用指针变量指
22、向数组元素 for(p=a;p(a+10);p+) printf(“%d”,*p);#include void main( )int a10,i,*p; p=a; for(i=0;i10;i+) scanf(“%d”,p+); printf(“n”); for(i=0;ipa表示表示qa处于高地址位置;处于高地址位置;pa处于低地址位置;处于低地址位置;#include void main( )int a5,i,*pa,*qa; pa=qa=a; for(i=0;i5;i+) *qa=i; qa+; /*将指针将指针qa指向指向a数组中的下一元素数组中的下一元素 */ for(i=0;paqa
23、;i+) printf(“a%d=%-2d”,i,*pa); pa+; 例:通过指针变量的运算输出例:通过指针变量的运算输出a a数组中的数组中的5 5个元素。个元素。运行结果:运行结果:a0=0 a1=1 a2=2 a3=3 a4=42.指针变量的自增自减运算指针变量的自增自减运算如果先使如果先使p指向数组指向数组a的首元素的首元素(即即p=a),请分析:,请分析:(1)p+:使:使p指向数组指向数组a的下一元素,即的下一元素,即a1。(2)*p+:由于元素符:由于元素符+和和*同优先级,结合方向为自同优先级,结合方向为自 右向左,因此它等价于右向左,因此它等价于*(p+)。(3)*(p+)
24、 与与*(+p)作用不同。作用不同。(4)(*p)+:表示:表示p所指向的元素值加所指向的元素值加1,它等价于,它等价于 (a0)+。若。若a0=3,则,则(*p)+的值为的值为4。 注意:是元素值加注意:是元素值加1,而不是指针值加,而不是指针值加1。前面已介绍过可以用数组名作函数的参数,例如:前面已介绍过可以用数组名作函数的参数,例如:void f(int arr ,int n) void main( ) int array10; f(array,10); f (int arr , int n)但在编译时是将但在编译时是将arr按指针变量处理的,相当于将函数按指针变量处理的,相当于将函数f
25、的首部写成的首部写成f (int *arr, int n)以上两种写法是等价的。以上两种写法是等价的。三、用数组名和数组指针变量作函数参数三、用数组名和数组指针变量作函数参数以变量名和数组名、数组指针变量作为函数参数的以变量名和数组名、数组指针变量作为函数参数的比较:比较:实参类型变量名数组名要求形参的类型变量名数组名或指针变量传递的信息变量的值 实参数组的首地址通过函数调用能否改变实参的值不能能 归纳起来,如果有一个实参数组,想在函数中改变归纳起来,如果有一个实参数组,想在函数中改变此数组中的元素的值,实参与形参的对应关系有以下此数组中的元素的值,实参与形参的对应关系有以下种情况:种情况:
26、(1) 形参和实参都用数组名,如:形参和实参都用数组名,如:void main() void (int ,int ) int ; (,); (2) 实参用数组名,形参用指针变量。如:实参用数组名,形参用指针变量。如:void () void (int *,int )int ; (,); (3)实参形参都用指针变量。例如:实参形参都用指针变量。例如:void main() void (int *,int )int , *p=a; (p,); (4) 实参为指针变量,形参为数组名。如:实参为指针变量,形参为数组名。如: void main() void (int x ,int ) ,*p=a; (
27、p,); #include void main( )void inv(int *x,int n); int i,a10=3,7,9,11,0,6,7,5,4,2; printf(“The original array:n”); for(i=0;i10;i+) printf(“%d”,ai); printf(“n”); inv(a,10); printf(“The array has been inverted:n”); for(i=0;i10;i+) printf(“%d”,ai); printf(“n”);例:将例:将a a数组中数组中n n个整数按相反顺序存放。个整数按相反顺序存放。voi
28、d inv(int *x,int n)int *p,temp,*i,*j,m=(n-1)/2; i=x; j=x+n-1; p=x+m; for(;i=p;i+,j-) temp=*i; *i=*j; *j=temp; return;运行结果:运行结果:The original array:3,7,9,11,0,6,7,5,4,2The array has been inverted:2,4,5,7,6,0,11,9,7,3四、四、 多维数组与指针多维数组与指针 用指针变量可以指向一维数组中的元素,用指针变量可以指向一维数组中的元素,也可以指向多维数组中的元素。也可以指向多维数组中的元素。下面
29、以二维数组为例下面以二维数组为例。 1. 多维数组元素的地址的表示方法多维数组元素的地址的表示方法定义定义int a34=1,2,3,4,5,6,7,8,9,10,11,12;C语言允许把一个二维数组分解为多个一维数组来处语言允许把一个二维数组分解为多个一维数组来处理。理。a是一个数组名,是一个数组名, a数组包含数组包含3个元素:个元素:a0,a1,a2,而每一个元素又是一个一维数组,包含而每一个元素又是一个一维数组,包含4个元素个元素(即即4个个列元素列元素)。如行元素。如行元素a0所代表的一维数组包含所代表的一维数组包含4个元个元素:素: a00,a01,a02,a03。故可以认为二维数
30、组是故可以认为二维数组是“数组的数组数组的数组”,即二维数组,即二维数组a是由是由3个一维数组所组成的。个一维数组所组成的。从二维数组的角度看,从二维数组的角度看,a代表二维数组首元素的地代表二维数组首元素的地址。现在的首元素不是一个简单的整型元素,而是址。现在的首元素不是一个简单的整型元素,而是由由4个整型列元素所组成的一维数组,个整型列元素所组成的一维数组,因此因此a代表的是首行代表的是首行(0行行)的首地址;的首地址; a+1代表代表1行的首地址;行的首地址; a+2代表代表2行的首地址。行的首地址。如果二维数组首行的首地址是如果二维数组首行的首地址是2000,则,则a+1的首地的首地址
31、为址为a+4*2=2008。a0,a1,a2是一维数组名,而是一维数组名,而C语言规定了数组名语言规定了数组名代表数组首元素地址,代表数组首元素地址,因此因此a0代表一维数组代表一维数组a0中第中第0列元素的地址,即列元素的地址,即二维数组二维数组0行行0列元素的地址,即列元素的地址,即&a00; a1的值是的值是&a10 ; a2的值是的值是&a20。a0+0,a0+1, a0+2,a0+3分别是分别是&a00, &a01, &a02, &a03。由于由于a0与与*(a+0)等价,由于等价,由于ai与与*(a+i)等价,等价,因此因此 a0+1、 *(a+0)+1都是都是&a01, a1+2
32、、 *(a+1)+2都是都是&a12。如何用地址法表示如何用地址法表示&a01的值?由于的值?由于a0+1、 *(a+0)+1都是都是a01的地址,的地址,则则*(a0+1)、 *(*(a+0)+1)、*(*a+1)都是都是a01的值的值2.指向多维数组的指针变量指向多维数组的指针变量 (1) 指向数组元素的指针变量指向数组元素的指针变量#include void main( )int a34=1,3,5,7,9,11,13,15,17,19,21,23; int *p; for(p=a0;pa0+12;p+) if(p-a0)%4=0) printf(“n”); printf(“%4d”,*
33、p); printf(“n”);分析:分析:指针变量指针变量p是用是用“int *p;”定义的,定义的,它是指向整型数它是指向整型数据的据的,p+1所指向的元素是所指向的元素是p所指向的元素的下一元所指向的元素的下一元素。素。(2) 指向由指向由m个元素组成的一维数组的指针变量个元素组成的一维数组的指针变量 此时此时p不是指向整型变量,而是指向一个包含不是指向整型变量,而是指向一个包含m个个元素的一维数组。元素的一维数组。 如果如果p先指向先指向a0,则,则p+1是指向是指向a1,p的增值以一的增值以一维数组的长度为单位。维数组的长度为单位。二维数组指针变量说明的一般形式为:二维数组指针变量说
34、明的一般形式为:类型说明符类型说明符 (*指针变量名指针变量名)长度长度;其中,其中,“类型说明符类型说明符”是所指数组的数据类型;是所指数组的数据类型; “*”表示其后的变量是指针类型;表示其后的变量是指针类型; “长度长度”表示二维数组分解为多个一维数组时,表示二维数组分解为多个一维数组时,一维数组的长度,即是二维数组的列数。一维数组的长度,即是二维数组的列数。注意:注意:(*指针变量名指针变量名)两边的括号不能省,如缺少括两边的括号不能省,如缺少括号则表示指针数组。号则表示指针数组。#includevoid main( )int a34=1,3,5,7,9,11,13,15,17,19,
35、21,23; int (*p)4,i,j; p=a; scanf(“i=%d,j=%d”,&i,&j); printf(“a%d,%d=%d n”,i,j,*(*(p+i)+j);例:输出二维数组任一行任一列元素的值。例:输出二维数组任一行任一列元素的值。运行结果:运行结果:i=1,j=2a1,2=13一、字符串的表示形式一、字符串的表示形式 对指向字符变量的指针变量应赋予该字符变量的地址对指向字符变量的指针变量应赋予该字符变量的地址例如:例如:char ch,*pch=&ch; 其中其中pch是一个指向字符变量是一个指向字符变量ch的指针变量。的指针变量。在在C语言中,可以用两种方法访问一个
36、字符串:语言中,可以用两种方法访问一个字符串:1.用用字符数组字符数组存放一个字符串;存放一个字符串;2.用用字符指针字符指针指向一个字符串。指向一个字符串。 (可以不定义字符数组,而只定义一个字符指针,可以不定义字符数组,而只定义一个字符指针, 用字符指针指向字符串中的字符用字符指针指向字符串中的字符)例:例:#include void main( ) char *string=“I love China!”; printf(“%s n”, string); 注意:注意:1.其中其中string是一个指向字符串的指针变量,把字符是一个指向字符串的指针变量,把字符串的首地址赋予串的首地址赋予s
37、tring。2.定义定义string部分:部分:char *string=“I love China!”; 等价于:等价于:char *string; string=“I love China!”;但对字符数组使用方式但对字符数组使用方式char *str =“I love China!”; 不能写为:不能写为:char *str80; str=“I love China!”;二、字符指针作函数参数二、字符指针作函数参数 将一个字符串从一个函数传递到另一个函数,可以用将一个字符串从一个函数传递到另一个函数,可以用地址传递地址传递的办法,即用的办法,即用字符数组名字符数组名作参数,也可以用作参数
38、,也可以用指向字符的指针变量指向字符的指针变量作参数。作参数。在被调函数中可以改变字符串的内容,在主调函数中在被调函数中可以改变字符串的内容,在主调函数中可以得到改变了的字符串。可以得到改变了的字符串。(1)实参用指针变量,形参用数组名实参用指针变量,形参用数组名#includevoid main( )void copy_string(char str1 ,char str2 ); char s1 =“I am a teacher.”; char s2 =“You are a student.”; char *a=s1,*b=s2; printf(“string a=%snstring b=%
39、sn”,a,b); printf(“copy string a to string b:n”); copy_string(a,b); printf(“string a=%snstring b=%sn”,a,b);例:用函数调用实现字符串的复制。例:用函数调用实现字符串的复制。void copy_string(char str1 ,char str2 )int i=0; while(str1 !=0) str2i=str1i; i+; str2i= 0;例:用函数调用实现字符串的复制。例:用函数调用实现字符串的复制。运行结果:运行结果:string a= I am a teacher.strin
40、g b= You are a student.copy string a to string b:string a= I am a teacher.string b= I am a teacher.(2)实参、形参都用字符指针变量实参、形参都用字符指针变量#includevoid main( )void copy_string(char *str1,char *str2); char s1 =“I am a teacher.”; char s2 =“You are a student.”; char *a=s1,*b=s2; printf(“string a=%snstring b=%sn”,
41、a,b); printf(“copy string a to string b:n”); copy_string(a,b); printf(“string a=%snstring b=%sn”,a,b);void copy_string(char *str1,char *str2)int i=0; for(;*str1!=0;str1+,str2+) *str2=*str1; *str2= 0;运行结果:运行结果:string a= I am a teacher.string b= You are a student.copy string a to string b:string a= I
42、am a teacher.string b= I am a teacher. 可以用指针变量指向整型变量、字符串、数组,也可以用指针变量指向整型变量、字符串、数组,也可以指向一个可以指向一个函数函数。 C语言中规定,一个函数占用一段连续的内存单元,语言中规定,一个函数占用一段连续的内存单元,函数名即是函数所占内存单元的首地址函数名即是函数所占内存单元的首地址(或称函数的或称函数的入口地址,函数的指针入口地址,函数的指针)。 可以把可以把函数的首地址函数的首地址(即入口地址即入口地址)赋予一个指针变赋予一个指针变量量,使该指针变量指向该函数,然后通过该指针变量,使该指针变量指向该函数,然后通过该
43、指针变量可以找到并调用此函数。可以找到并调用此函数。把指向函数的指针变量称为把指向函数的指针变量称为“函数指针变量函数指针变量”。函数指针变量定义的一般形式为:函数指针变量定义的一般形式为:类型说明符类型说明符 (*指针变量名指针变量名)(函数参数表列函数参数表列);其中,其中,“类型说明符类型说明符”表示被指函数的返回值的类型。表示被指函数的返回值的类型。例:例:int (*p)(int,int); 其中其中p是一个指向函数的指针变量,该函数有两是一个指向函数的指针变量,该函数有两个整型参数,函数值为整型。个整型参数,函数值为整型。#includeint max(int a,int b)re
44、turn(ab)?a:b);void main( )int (*pmax)(int,int),x,y,z; pmax=max; printf(“Input two numbers:n”); scanf(“%d%d”,&x,&y); z=(*pmax)(x,y); /*等价于等价于z=max(x,y);*/ printf(“max=%d”,z);例:求例:求a a和和b b中的最大者。中的最大者。( (通过指针变量调用函数通过指针变量调用函数) )说明:说明:(1)定义定义“int (*pmax)(int,int);”中的中的*pmax两侧的两侧的括括号不可省略号不可省略,表示,表示pmax先与
45、先与*结合,是指针变量,结合,是指针变量,然后再与后面的然后再与后面的( )结合,表示此指针变量指向函数,结合,表示此指针变量指向函数,这个函数值这个函数值(即函数返回值即函数返回值)是整型的。是整型的。 若写成若写成“int *pmax(int,int);”,则由,则由( )优先级高于优先级高于*,它就成了声明一个它就成了声明一个pmax函数了,此函数的返回值函数了,此函数的返回值是指向整型变量的指针。是指向整型变量的指针。说明:说明:(2)函数指针变量不能进行算术运算函数指针变量不能进行算术运算,如,如p+、p-、p+n等运算是无意义的。等运算是无意义的。 因为函数指针变量因为函数指针变量
46、p只能指向函数的入口处,而不只能指向函数的入口处,而不能指向函数中的某一条指令处,因此不能用能指向函数中的某一条指令处,因此不能用(*p+1)来来表示函数的下一条指令。表示函数的下一条指令。 一个函数可以返回一个整型值、字符值、实型值等,一个函数可以返回一个整型值、字符值、实型值等,也可以返回指针型是数据,即地址。也可以返回指针型是数据,即地址。这种返回指针值的函数,称为这种返回指针值的函数,称为指针型函数指针型函数。一般定义形式为:一般定义形式为:类型说明符类型说明符 *函数名函数名(形参表列形参表列);其中,其中,“*”在函数名之前,表示此函数是指针型函数;在函数名之前,表示此函数是指针型
47、函数; “类型说明符类型说明符”表示被指函数的返回值的类型。表示被指函数的返回值的类型。#includefloat *search(float (*pointer)4,int n)float *pt; pt=*(pointer+n); return(pt);例:有若干个学生的成绩例:有若干个学生的成绩( (每个学生有每个学生有4 4门课程门课程) ),要求在,要求在用户输入学生序号以后,能输出该学生的全部成绩。用户输入学生序号以后,能输出该学生的全部成绩。 用指针函数来实现。用指针函数来实现。void main( )float score 4=60,70,80,90,56,89,67,88,
48、34,78,90,66; float *p; int i,m; printf(“enter the number of student:”); scanf(“%d”,&m); printf(“The scores of No.%d are:n”,m); p=search(score,m); for(i=0;i4;i+) printf(“%5.2ft”,*(p+i); printf(“n”);运行结果:运行结果:enter the number of student:1 The scores of No.1 are:56.00 89.00 67.00 88.00一、一、 指针数组指针数组 一个数
49、组,若其元素均为指针类型数据,称为一个数组,若其元素均为指针类型数据,称为指针指针数组数组。即指针数组中的每一个元素都相当于一个指针变量。即指针数组中的每一个元素都相当于一个指针变量。指针数组说明的一般形式为:指针数组说明的一般形式为:类型说明符类型说明符 *数组名数组名数组长度数组长度;其中,其中,“类型说明符类型说明符”为指针值所指向的变量的类型。为指针值所指向的变量的类型。例:例:int *p4; 由于由于 比比*优先级高,因此优先级高,因此p先与先与4结合,说明结合,说明p是是一个数组,有一个数组,有4个元素。个元素。 *表示其后的数组为指针类型的,每个数组元素表示其后的数组为指针类型
50、的,每个数组元素(即即指针变量指针变量)都可指向整型变量。都可指向整型变量。说明:说明:(1)通常可用一个指针数组来指向一个二维数组通常可用一个指针数组来指向一个二维数组,指,指针数组中的每个元素被赋予二维数组每一行的首地针数组中的每个元素被赋予二维数组每一行的首地址,因此也可理解为指向一个一维数组。址,因此也可理解为指向一个一维数组。(2)指针数组也常用来表示一组字符串指针数组也常用来表示一组字符串,此时指针数,此时指针数组的每个元素被赋予一个字符串的首地址。组的每个元素被赋予一个字符串的首地址。注意:注意:指针数组和二维数组指针变量的区别:指针数组和二维数组指针变量的区别:两者虽然都可用来