【文档说明】c语言课件第10章指针1011.ppt,共(77)页,544.535 KB,由小橙橙上传
转载请保留链接:https://www.ichengzhen.cn/view-44590.html
以下为本文档部分文字说明:
第十章指针•掌握指针与指针变量的概念;•掌握数组的指针和指针数组的使用;•掌握字符串指针和指向字符串的指针变量的使用;•掌握指针函数和函数指针的使用;•了解指向指针的指针的概念及其使用。预备知识内存:CPU处理的数据都保存在内存中。内存分为一个个单元,这些单元顺序排列,每
一个单元有一个称为内存地址的编号,对内存数据的访问都是通过地址进行的。高级语言用变量等高级概念把内存单元、地址等低级概念掩盖起来,使我们在写程序时不必关心硬件的细节,但内存与地址仍是最基本的概念。存储单元的最小单位是字节。1.内存的概念地址:为了
对内存中的某个存储单元进行访问,要为它编号,这种编号称为内存地址。通过地址我们就能够访问该地址所标识的存储单元。2.地址的概念变量的地址:每一个变量在内存中总占用几个连续的字节,开始字节的地址,就是变量的地址。2007存
储单元§10.1指针及其相关概念指针:一个变量的地址称为该变量的指针。许多高级语言都把程序对象的地址作为一种数据,称之为地址值或指针值。指针变量:若一个变量专用于存放另一个变量的地址(指针),则该变量称为指针变量。换句话说,以地址为值的变量称为指针变量,简称指针。指针的对
象:当把变量的地址存入指针变量后,我们就可以说这个指针指向了该变量。变量的存取方法:直接存取和间接存取。直接存取:直接根据变量名存取数据。间接存取:通过指针变量存取相应变量的数据。§10.2变量的指针和指向变量的指针变量一、指针变量的定义一般形式:类型标识符*变量名;例如:int*ptr1,*p
tr2;指针变量的类型:说明该指针所指向的变量的类型。在定义指针变量时要注意以下几个问题:⑴变量名ptr2前面的“*”不能省略,如果写成int*ptr1,ptr2;则ptr2被定义为整型变量,而非整型指针变量。⑵定义中的“*”表示所定义的变量是指针变量,但指针变量名是ptr1、ptr2,而非*pt
r1、*ptr2。⑶指针变量只能指向定义时所规定类型的变量。这个规定的类型称为该指针变量的“基类型”。如:上例中ptr1、ptr2只能指向整型变量,不能指向实型或字符型变量。其“基类型”相同,都是整型。⑷定义指针变量后,并未确定该变量指向何处
。也就是说该变量的值是不确定的。在引用指针变量前必须首先让它指向一个变量,这一点非常重要。二、指针变量的运算㈠指针运算符(“&”和“*”)“&”(取地址运算符):取变量的存储地址“*”(取值运算符):取指针所指向
变量的内容例如:&a是求变量a的地址。ptr指向了i变量,*ptr表示i的值,即3我们还可以用这种方法实现对变量的改变:*ptr=15;等价于i=15;由此可见:通过指针运算符“*”可以引用一个变量。如:当ptr已经指向变量i后,*ptr就等同于i。*ptr&i进一步理解“&”和
“*”:“&”运算和“*”运算是一对互逆运算。&*ptr&iptr*&i*ptri等价于㈡指针的赋值运算(=)指针的赋值运算:就是把地址赋值给指针变量。指针的赋值运算可以是以下三种方式:⑴使用取地址运算符,把地址值赋值给指针
变量。如:inti,*pi;pi=&i;⑵把指针变量的值赋给另一个指针变量。如:inti,*pa,*pb;pa=&i;pb=pa;⑶给指针变量赋值为符号常量NULL。说明:NULL是一个空指针,表示该指针变量的值没有
意义。作用是为了避免对没有被初始化的指针变量的非法引用。NULL的定义在“stdio.h”中。如:int*pi;pi=NULL;说明:⑴在定义指针变量时,可以立即将一个地址值赋给指针变量,这就是指针变量的初始化。
指针变量的初始化也是指针的赋值运算。如:floatflt,*f_ptr=&flt;注意:这不是给*f_ptr赋值。⑵指针变量间的赋值和引用应保证基类型相同。若有定义:int*p,i;float*q,x;则:q=&i;╳p=&x;╳㈢移动指针的运算•指针的加减运算
(+、-)•指针的自加自减运算(++,--,+=,-=)1.指针的+、-运算指针±整数指针-指针+、-说明:⑴指针与整型值加减的结果是指针,表示使该指针指向该指针下移或上移存储单元个数(整型值)之后的内存地址。存储单元的大小就是该指针的数据类型所需的内存大小。例如:ptr+n(指针p
tr,n为整数)这个指针值代表的内存单元的地址是:ptr+n*d(其中d是指针所指向变量的数据类型所占内存字节数),即指针移动了n个元素。⑵指针与指针的加运算毫无意义,所以指针与指针没有加运算。⑶指针与指针的减
运算要求相减的两个指针属于同一类型,其结果是整数,表示两个指针之间的数据的个数。其结果值的计算公式是:ptr1-ptr2=(ptr1的值-ptr2的值)/指针的数据类型所占的字节数例如:int*ptr1,*ptr2,*ptr3,x;intary[5]={2,4,8,16,32};ptr1=&ar
y[0];ptr2=&ary[3];ptr3=ary;x=ptr2-ptr1;x的值是32.指针的++、--、+=、-=运算++、+=:是移动指针到下一个或下几个存储单元。--、-=:是移动指针到上一个或上几个存储单元。例如:int*ptr,ary[5]
={2,4,6,8,10};ptr=ary;ptr+=3;ptr--;想一想:*ptr++和(*ptr)++有什么区别?㈣关系运算基类型相同的两个指针进行比较运算,其意义是两个指针的位置比较,结果是逻辑值。指针运算的程序举例:把a,b按大小顺序输出。main(){int*p1,
*p2,*p,a,b;a=45;b=76;p1=&a;p2=&b;if(*p1<*p2){p=p1;p1=p2;p2=p;}printf("a=%d,b=%d,max=%d,min=%d",a,b,*p1,*p2);
}输出结果:a=45,b=76,max=76,min=45三、指针变量作为函数参数指针可以用作函数参数,这在调用函数希望改变参数的值时非常有用。例如:用指针变量编写实现两个数的交换的函数voidswap(int*p1,int*p2);main(){intx1=100,x2=200;printf("
x1=%d,x2=%d\n",x1,x2);swap(&x1,&x2);printf("x1=%d,x2=%d\n",x1,x2);}voidswap(int*p1,int*p2){inttemp;temp=*p1;*p1=*p2;*p2=temp;}图示交换过程中存储单元内容的变化:
123456想一想:如果函数的参数不用指针而用整型变量,能否实现值的交换?为什么?通过函数调用得到n个要改变的值的方法:⑴在主调函数中设n个变量,用n个指针变量指向它们;⑵将指针变量作实参,将这n个变量的地址传给所调
用的函数的形参;⑶通过形参指针变量,改变该n个变量的值;⑷主调函数中就可以使用这些改变了值的变量。注意:不能企图通过改变指针形参的值而使指针实参的值改变。如:上例swap函数中不能写成:temp=p1;p1=p2;
;p2=temp;§10.3数组的指针和指向数组的指针变量一、概念数组的指针:是数组的起始地址。数组元素的指针:是数组元素的地址。当指针变量指向数组或数组元素时,它就是指向数组的指针变量。C规定:⑴数组名代表
数组的首地址(起始地址),也就是数组第一个元素的地址。⑵当指针变量p指向数组的某个元素时,p+1指向数组的下一个元素。假设一个整型元素占两个字节,p+1是使p的地址加2个字节。如:inta[10],*p;则:p=a;与p=
&a[0];等价称指针变量p指向数组元素a[0]p+i、a+i、&a[i]都是a[i]的地址。二、数组元素的引用1.用下标法引用数组元素如:a[3]=45;b[2][5]=200;2.用指针法引用数组元素假如:inta[10],*p,i;p=a;则:⑴*(p+i)、*(a+i)则代表
元素a[i]⑵*(p+i)也可以写成p[i]⑶*(p+i)、*(a+i)、a[i]、p[i]等价,都代表数组a的第i+1个元素。程序举例:输出10个元素数组中的全部元素。方法二:通过数组名计算数组元素地址,找出元素的值。main(){inta[10
]={54,65,8,2,3,56,8,21,57,98},i;for(printf("\n"),i=0;i<10;i++)printf("%4d",*(a+i));}方法一:下标法。main(){inta[10]={54,65,8,2,3,56,8,21,57,98},i;for
(printf("\n"),i=0;i<10;i++)printf("%4d",a[i]);}方法三:用指针变量指向数组元素main(){inta[10]={54,65,8,2,3,56,8,21,57,98},*p,i;p=a;for(printf("\n"),i=
0;i<10;i++)printf("%4d",*p++);}以上三种方法,利用指针变量效率最高。说明:⑴指针变量与数组名的区别:指针变量是地址变量,数组名是地址常量。即指针变量的内容可以在程序运行过程中被改变;而数组名一旦被定义,它的地址就不能再改变了。例如:
inti,*p,a[6];则:p=&i;√a=&i;a++;a+=i;不能给常量赋值⑵利用指针变量编程时特别要注意指针变量的当前值。例如:通过指针变量输入输出a数组元素。main(){int*p,i,a[10];p=a;for(i=0;i<10;i
++)scanf("%d",p++);printf(“\n”);for(i=0;i<10;i++)printf(“%6d”,*p++);}应插入语句p=a;注意:*p++、*(p++)、(*p)++、*(++p)的含义三、数组名作函数的参数例如
:f(intarr[],intn){……}main(){intarray[10];……f(array,10);……}现在解释:实际上,能够接受并存放地址值的只能是指针变量。因此,C编译系统都是将形参数组名作为指针变量来处理的。上例中f(intarr[],int
n)等价于f(int*arr,intn)。arr[i]=*(arr+i)使用形参数组的概念只是为了与实参数组对应,直观,便于理解而已。例:从10个数中找出其中最大值和最小值(用数组)。main(){voidmax_min(inta[],in
tn,int*max,int*min);inti,a[]={2,4,1,6,7,32,45,75,45,90},max,min;printf("Theoriginalarray=");for(i=0;i<10;i++)printf("%5d",a[i]);max_mi
n(a,10,&max,&min);printf("max=%d,min=%d",max,min);}voidmax_min(inta[],intn,int*max,int*min){inti;*max=*mi
n=a[0];for(i=1;i<n;i++){if(*max<a[i])*max=a[i];a[i]*(a+i);if(*min>a[i])*min=a[i];}}上例中如果形参数组用指针变量,则程序如下:main(){voidmax_min(int*x,i
ntn,int*max,int*min);inti,a[10]={2,4,1,6,7,32,45,75,45,90},max,min;for(printf("Theoriginalarray="),i=0;i<1
0;i++)printf("%5d",a[i]);max_min(a,10,&max,&min);printf(“max=%d,min=%d",max,min);}voidmax_min(int*x,intn,int*max,int*mi
n){inti;*max=*min=*x;for(i=1;i<n;i++){if(*max<*(x+i))*max=*(x+i);if(*min>*x)*min=*(x+i);}}数组名做函数参数小结:如果有一个实参数组,想在函数中改变此数组的元素的值,实参与形参都可用
数组名或指针变量。其对应关系有以下4种情况:⑴实参与形参都用数组名;⑵实参用数组名,形参用指针变量;⑶实参、形参都用指针变量;⑷实参为指针变量,形参用数组名。注意:用指针变量作实参时一定要有确定的值。例a:实参和形参都用数组名main(){inta[10];……f(a,10);……}
f(intx[],intn){……}例b:实参用数组名,形参用指针变量main(){inta[10];……f(a,10);……}f(int*x,intn){……}例c:实参、形参都用指针变量main(){inta
[10],*p;p=a;……f(p,10);……}f(int*x,intn){……}例d:实参为指针变量,形参用数组名main(){inta[10],*p;p=a;……f(p,10);……}f(intx[],intn){……}本章程序举例:习题10.1:输入3个整数,按由小到大的顺
序输出。voidswap(int*p,int*q);main(){inta,b,c,*p1=&a,*p2=&b,*p3=&c;scanf(“%d%d%d”,p1,p2,p3);if(*p1>*p2)swap(p1,p2);if(*
p1>*p3)swap(p1,p3);if(*p2>*p3)swap(p2,p3);printf("\n%6d%6d%6d",*p1,*p2,*p3);}voidswap(int*p,int*q){intx;x=*p;*p=*q;*q=x;}习题10.14
:将n个数按输入时顺序的逆序排列,用函数实现。voidinverse(int*a,intn);main(){inti,a[10]={2,4,1,6,7,32,45,75,450,89};for(puts(""),i=0;i<10;i++)printf(
"%5d",a[i]);inverse(a,10);for(puts(""),i=0;i<10;i++)printf("%5d",a[i]);}voidinverse(int*x,intn)0123456789{int*i=x,
*j=x+n-1,t;for(;i<j;i++,j--){t=*i;*i=*j;*j=t;}*i*j}10.4:有N个数,使前面各数顺序向后移M个位置。main(){intnum[20],m,n,i;printf("\nm=n=");scanf("%d%d
",&m,&n);for(i=0;i<n;i++)scanf("%d",num+i);move(num,n,m);for(i=0;i<n;i++)printf("%6d",*(num+i));}move(int*pnum,intn,intm){in
tt,i,j;for(i=0;i<m;i++)/*m是移动次数*/{t=*(pnum+n-1);for(j=n-1;j>0;j--)*(pnum+j)=*(pnum+j-1);*pnum=t;}}作业(均要求用指针实现)(1)任意输入5个整数,按由大到小的
顺序输出;(2)写一个函数select(intn,doublea[],doubleb[],doublex),它将数组b中大于x的数顺序复制到数组a中。a数组的内容为空,n是两个数组的大小。四、二维数组的指针1
.二维数组的地址概念在C语言中,一个二维数组可以看成是一个一维数组,该一维数组中的每个元素又是一个包含若干元素的一维数组。假如有定义:inta[3][4];则C语言编译程序认为a数组是由a[0],a[1],a[2]3个元素组成
的一维数组,而a[0]和a[1],a[2]又分别是包含4个元素的一维数组名,分别代表a数组元素的起始地址(即a[0]是第0行元素的首地址,a[1]是第1行元素的首地址…)。因此,a和a[i]是两个基类型不同的指针常量。2.通过
地址引用二维数组元素假如有定义:inta[3][4],i,j;(其中0≤i<3,0≤j<4)则:⑴a[i]和*(a+i)(无条件等价)都是第i行数组的首地址,也是第i行第0列(第1列)元素的地址;那么a[i]+j、*(a+i)+j、&a[0][0]
+4*i+j都是第i行第j列元素的地址。⑵数组a中任意元素a[i][j]的引用可以表示成如下几种形式:a[i][j]、*(a[i]+j)、*(*(a+i)+j)、(*(a+i))[j]、*(&a[0][0]+4*i+j)二维数组的数组元素(一维数
组)的首地址的运算(各班长的地址的运算)inta[3][4]首地址数组元素a(排长)a[0]*(a+0)a[0][0]a[0][1]a[0][2]a[0][3]a[1]*(a+1)a[1][0]a[1][1]a[1][2]a[1][3]a[2]*(a+2)a[2][0]a[
2][1]a[2][2]a[2][3]排0班1班2班二维数组一维数组班长战士一维数组的数组元素及地址运算(各班战士及地址运算)0班长地址a[0]*(a+0)0班j战士的地址*(a+0)+j0班j战士*(*(a+0)+j)|a[0][0]a[0][1]a[0][2]a[0][3]1班长地址a[1]*
(a+1)1班j战士的地址*(a+1)+j1班j战士*(*(a+1)+j)|a[1][0]a[1][1]a[1][2]a[1][3]2班长地址a[2]*(a+2)2班j战士的地址*(a+2)+j2班j战士*(*(a+2)+j)
|a[2][0]a[2][1]a[2][2]a[2][3]3.通过一个行指针变量引用二维数组的元素定义一个由m个元素组成的一维数组的指针变量:类型标识符(*指针变量名)[m];例如:假若有语句inta[3][4],(*p)[4];p=a;注意:*p两侧的圆括号不可缺少。则:⑴p
是一个指针变量,它指向由4个整型元素组成的一维数组。⑵p指向a数组,p+1指向数组a的下一行首地址,a和p的基类型相同,则a数组中任意元素a[i][j]还可以如下表示:*(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]、p[i
][j]例:使用行指针变量访问九九乘法表的数组元素。main(){floatfa[9][9],(*pf)[9]=fa;inti,j;for(i=0;i<9;i++)for(j=0;j<=i;j++)*
(*(pf+i)+j)=(i+1)*(j+1);for(i=0;i<9;i++)for(j=0;j<=i;j++)printf(“%f”,fa[i][j]);//或者printf("%f",*(*(pf+i)+j));}
习题10.9:写一函数,将一个3×3的矩阵转置。main(){inta[3][3]={1,2,3,4,5,6,7,8,9},i,j;for(i=0;i<3;i++)for(puts(""),j=0;j<3;
j++)printf("%6d",a[i][j]);transpose(a);for(i=0;i<3;i++)for(puts(""),j=0;j<3;j++)printf("%6d",a[i][j]);}transpose(int(*p)[3]){inti,j,t;for(i=0
;i<3;i++)for(j=0;j<i;j++){t=*(*(p+i)+j);*(*(p+i)+j)=*(*(p+j)+i);*(*(p+j)+i)=t;}}§10.4字符串指针和指向字符串的指针变量字符串指针:字符串的首地址。字符指针变量:指向字符串的指针变量。例如:char*strp=“He
llo!”;定义了一个指向字符串的指针变量,并将字符串的首地址赋值给strp指针变量,即:使指针变量strp指向字符串首地址。字符指针变量定义的一般形式:char*指针变量名;字符指针变量定义时可以赋初值。C
程序访问字符串有以下两种方法:1.用字符数组存放一个字符串例如:chars[]="Iamastudent.";字符串输出语句可写成:⑴printf(“%s\n”,s);⑵for(i=0;s[i]!=„\0‟;i++)printf(
“%c”,s[i]);⑶for(i=0;s[i]!=„\0‟;i++)printf(“%c”,*(s+i));2.用字符指针指向一个字符串例如:char*ps="Iamastudent.";字符串输出语句
可写成:for(;*ps!=„\0‟;ps++)printf(“%c”,*ps);说明:⑴字符数组由若干个元素组成,每个元素中放一个字符。而字符指针变量中存放的是地址(字符串的首地址),决不是将字符串放到字符指针
变量中;⑵字符数组和字符指针变量都可以在定义时赋初值,但以下方法对字符数组非法,对字符指针变量合法:chars[10];s=“hello!”;╳char*ps;ps=“hello!”;√⑶字符指针变量必须先赋值后使用,否则对系统构成危险。因此
,不可以如下编程:char*ps;scanf(“%s”,ps);╳而应写成:char*ps,s[10];ps=s;scanf(“%s”,ps);√⑷字符数组名是指针常量,表示一个字符串的首地址,该地址不能改变。而字符指针变量的值是可以改变的,它
可以代表不同的字符串。⑸若定义了一个指针变量使它指向一个字符串,就可以用下标形式引用指针变量所指字符串中的字符。如:char*a=“IloveChina!”;printf(“%c”,a[5]);⑺若把字符指针所指对象当作数组使用,应注意对象的长度
。如:charstr1[10],*ps=str1;ps[10]=„\0‟;╳⑹用指针变量指向一个格式字符串,可以用它代替printf函数的格式字符串。如:inta;char*format;format=“a
=%d\n”;则:printf(format,a);相当于printf(“a=%d\n”,a);程序举例:将字符串a复制为字符串b。main(){chara[]="Iamaboy.",b[20];inti=0;do{*(b+i)=
*(a+i);i++;}while(*(a+i)!=„\0‟);puts(b);}上例程序还可写成:main(){chara[]="Iamaboy.",b[20],*p1=a,*p2=b;inti=0;while((*p2=*p1)!=„\0‟){p2++;p1++;}puts(b);}//或
者while((*p2++=*p1++)!=„\0‟)§10.5指针函数和函数的指针一、指针函数返回指针的函数称作指针函数。指针函数定义函数首部的一般形式:类型名*函数名(参数表)含意:函数的返回值是一个指针,它指向所定义类型的数据。例如:int*a
(intx,inty);/*函数原型声明*/含意:a是函数名,调用它以后能得到一个指向整型数据的指针(地址)。例:编写能返回结果串地址的串拷贝函数。#include"stdio.h"main(){char*st
rcpy1(char*str1,char*str2);char*ps,s1[80]="yhhhj";ps=strcpy1(s1,"fdgjdfh");puts(ps);}char*strcpy1(char*str1,char*str2){char*s=str1;while(*str2)*str
1++=*str2++;*str1='\0';returns;}二、函数的指针及指向函数的指针变量1.函数的指针(地址)概念每一个函数都占用一段内存,在编译时,被分配一个入口地址,这个入口地址就称为函数的指针。2.指向函数的指针变量定义指向函数的指针变量的一般形式:类型标识符(*指针变量名)(
);例如:float(*p)();含意:定义了p是指向函数的指针变量,函数的返回值是float类型。⑴(*p)()表示定义一个指向函数的指针变量,它不是固定指向哪个函数。3.对指向函数的指针变量赋值将一个函数的函数名(代表入口地址
)赋值给指向函数的指针变量,也称该指针变量指向了这个函数。如:intmax(intx,inty);/*函数的原型声明*/int(*p)();p=max;注意:赋值时,只需给出函数名而不必给出参数。注意:⑵对指向函数的指针变量,p+n,p++,p--等运算是无意义的。⑶注意区别int(
*p)()、int*p()4.函数的调用函数的调用通过函数名调用函数通过指向函数的指针调用函数当指向函数的指针变量p指向某一函数时(即指针变量p被赋值),调用函数的形式为:(*p)(实参1,实参2,……)即,只需将(*
p)代替函数名即可。例如:若有定义intmax(intx,inty);int(*p)(),a,b,c;p=max;则可有语句c=(*p)(a,b);例:求a和b中的大者。main(){intmax(int,int);int(*p)();/*
指向函数的指针*/inta,b,c;p=max;scanf(“%d,%d”,&a,&b);c=(*p)(a,b);printf(“a=%d,b=%d,max=%d”,a,b,c);}max(intx,inty){
intz;if(x>y)z=x;elsez=y;returnz;}§10.7指针数组和指向指针的指针一、指针数组指针数组:就是数组中每个元素是基类型相同指针变量。定义指针数组的一般形式:类型标识符*指针变量名[
常量表达式];例如:int*p[2];含意:p是一个一维指针数组,每个元素都是一个指向整型变量的指针变量。可以将整型变量的地址赋值给元素p[0]或p[1]。注意:区别int*p[2]、int(*p)[2]的含意。二、指针数组的应用1.利用指针数组处理多
个字符串方法⑴:先用指针数组指向字符数组,再处理。main(){charname[][80]={"aaa","bbb","ccc","ddd","eee"};char*pname[10],i;for(
i=0;i<5;i++)pname[i]=name[i];for(i=0;i<5;i++)puts(pname[i]);}main()/*与用行指针解决上述问题比较*/{charname[][80]={"aaa
","bbb","ccc","ddd","eee"};char(*pname)[80]=name,i;for(i=0;i<5;i++)puts(pname[i]);}方法⑵:用指针数组指向字符串常量。main(){char*pname[10]={"aaa",
"bbb","ccc","ddd","eee"};inti;for(i=0;i<5;i++)puts(pname[i]);}2.用指针数组指向动态内存void指针类型介绍:ANSI新标准增加了void指针类型,它用于定义一个指针变量,但不指定
它是指向哪种类型数据。在将它的值赋给另一个指针变量时要进行强制类型转换使之适合于被赋值的变量的类型。例如:char*p1;inta=2;void*p2;p2=&a;p1=(char*)p2;强制类型转换void指
针变量定义同样,可用p2=(void*)p1;将p1的值转换成void指针类型。可以将一个函数定义为void指针类型。表示该函数返回的是一个地址,它指向空类型,如需要引用此地址,也需要根据情况进行类型转换。如,库函数:voi
d*malloc(unsignedsize);功能:分配size字节的存储区。函数调用例:char*p;p=(char*)malloc(60);分配60字节的存储区,并返回该内存区的地址,并赋值给p。voidso
rt(char*ps[],intn);#defineN5main(){char*ps[100],i;for(i=0;i<N;i++)ps[i]=(char*)malloc(60);for(i=0;i<N;
i++)gets(ps[i]);sort(ps,N);for(i=0;i<N;i++)puts(ps[i]);}voidsort(char*ps[],intn){inti,k;char*p,s[100];for(
i=0;i<n-1;i++)for(k=i+1;k<n;k++)if(strcmp(ps[i],ps[k])<0){p=ps[i];ps[i]=ps[k];ps[k]=p;}}例:用指针数组指向动态内存,进行字符串的排序。三、指向指针的指针变量指向指针的指针变量(也称多级指针
)只能存放指针变量的地址。定义形式:类型标识符**指针变量名;例如:int**q,*p,i=5;p=&i;q=&p;5i20002000p4000q4000注意:要使用一个多级指针指向目标值,必须连续使用指针运算符“*”。例如:上例中**q就是i的值。含意:使指针变量p指向i,指针变
量q指向p。§10.8指针的数据类型小结定义含义int*p;p为指向整型数据的指针变量int*p[n];定义指针数组p,它有n个指向整型数据的指针元素int(*p)[n];p为指向含n个元素的一维数组的指针变量int*p();p为带回一个
指针的函数,该指针指向整型数据int(*p)();p为指向函数的指针,该函数返回一个整型值int**p;p是一个指针变量,它指向一个指向整型数据的指针变量习题10.2:输入3个字符串,按由小到大的顺序输出。voidswap(char*ps1
,char*ps2);main(){chars1[]="abc",s2[]="rst",s3[]="xyz";if(strcmp(s1,s2)<0)swap(s1,s2);if(strcmp(s1,s3)
<0)swap(s1,s3);if(strcmp(s2,s3)<0)swap(s2,s3);printf("\n%10s%10s%10s",s1,s2,s3);}voidswap(char*ps1,char*ps2){charps[100];strcpy(ps,ps
1);strcpy(ps1,ps2);strcpy(ps2,ps);}习题10.17:写一函数,实现两个字符串的比较。main(){chars1[128],s2[128];gets(s1);gets(s2);pri
ntf("cmps(s1,s2)=%d",cmps(s1,s2));}cmps(char*s1,char*s2){while(*s1&&*s2&&*s1==*s2);return*s1-*s2;}习题10.6:写一个函数,求字符串的长度,在main函
数中输入字符串,并输出其长度。intlen(char*ps);main(){charstr[30];gets(str);printf("\nlen=%d",len(str));}intlen(char*ps){intn=0;while(*ps++
)n++;returnn;}习题10.7:有一字符串包含N个字符,写一个函数,将字符串中从第M个字符开始的全部字符复制成为另一个字符串。main(){charsn[100]="fasjfkjsdfsdfjsdjkfdfjssdf",sm[100];intn=strlen
(sn),m=n/2;scopy(sn,sm,m);printf("\nsn=%s\nm=%d\nsm=%s",sn,sm,m);}scopy(char*psn,char*psm,intm){while(*(psn+m))*psm++=*(m+psn++);*
psm=‟\0‟;}习题10.8:输入一行文字,找出其中大写字母、小写字母、空格、数字以及其他字符各有多少?main(){chars[100],*p;intlowc=0,upc=0,space=0,num=0;gets(s);p=s;while
(*p){if(*p>='A'&&*p<='Z')upc++;elseif(*p>='a'&&*p<='z')lowc++;elseif(*p>='0'&&*p<='9')num++;elseif(*p=='')space++;p++;}printf("\nupc=%d
lowc=%dnum=%dspace=%d",upc,lowc,num,space);}习题10.11:对10个等长的字符串排序并输出。voidsort(char(*p)[60]);main(){chars[10][60],i;
for(i=0;i<10;i++)gets(s+i);sort(s);for(i=0;i<10;i++)puts(s+i);}voidsort(char(*p)[60]){inti,j;chars[60];for(i=
0;i<9;i++)for(j=i+1;j<10;j++)if(strcmp(p[i],p[j])>0){strcpy(s,p[i]);strcpy(p[i],p[j]);strcpy(p[j],s);}}10.12:用指针数组处理上一个题目,字符串不等长。voidsort(char
*p[],intn);main(){char*s[10]={"AAA","DDD","878787"},*ps[10],i;for(i=0;i<10;i++)ps[i]=s[i];sort(ps,3);for(i=0;i<3;i++)
puts(ps[i]);}voidsort(char*ps[],intn){inti,j;char*s;for(i=0;i<n-1;i++)for(j=i+1;j<n;j++)if(strcmp(ps[i],ps[j])<0)s=ps[i],ps
[i]=ps[j],ps[j]=s;}习题10.16:输入一个字符串,将其中的数字串转换成数值送数组A。main(){chars[128],*ps=s;inta[100],i,n;gets(s);for(i=0,n=0;*ps;ps++
)if(*ps>='0'&&*ps<='9')n=n*10+*ps-'0';else{if(n>0)a[i++]=n;n=0;}if(n>0)a[i++]=n;for(n=0;n<i;n++)printf("%6
d",a[n]);}习题10.18:根据输入的月份输出月的英文名。main(){char*month[]={"January","February","March","April","May","June","July","August","Septermber","Octo
ber","Noverber","Decermber"};intmon;scanf("%d",&mon);if(mon<1||mon>12)printf("montherror!");elseputs(month[mon-1]);}作业(上机运行以下程序,要求使用指针)(1)写一函数,
将一个3×4的矩阵转置,将数据存储到一个4×3的矩阵后,将两个矩阵输出;(2)输入3个字符串,按由小到大的顺序输出,要求不使用strcpy(string.h库函数)语句;(3)对n个等长的字符串排序并输出,n在2~10之间可变;(4)写出前述习题10.16各条语句的含义。(5)对习题10.5
,写出各程序行或程序段的含义,并将“凡报到3的人退出圈子”修改为“凡报到5的人退出圈子”,上机运行该程序。1.Statethefollowingstatementsaretrueorfalse.判断下列说
法是真还是假•A)Pointervariablesaredeclaredusingtheaddressoperator.•指针变量用地址运算符(&)来定义。•B)Theunderlyingtypeofapointervariableisvoid.•指针变量名不能使用下划线。•C)Pointe
rstopointersisatermusedtodescribepointerswhosecontentsaretheaddressofanotherpointer.•指向指针的指针是这样一种参数,它用于描述一种把其他指针的地址作为内容的指针。•D)Itispossibletocastapoi
ntertofloatasapointertointeger.•可以把float型的指针指定为integer型的指针。•e)Anintegercanbeaddedtoapointer.•指针可以与一个整数相加。
•f)Apointercanneverbesubtractedfromanotherpointer.•指针不能与指针相减。•g)Whenanarrayispassedasanargumenttoafunction,apointerispassed.•当
把数组作为变量传递给一个函数时,就等于传递了一个指针。•h)Pointerscannotbeusedasformalparametersinheaderstofunctiondefinition.•进行函数定义时,函数头的形参不能使用指针。2.Fillintheblanksinthefo
llowingstatements.•a)Apointervariablecontainsasitsvaluethe____ofanothervariable.•b)The_____operatorisusedwithapointertode-referencet
headdresscontainedinthepointer.•c)The____operatorreturnsthevalueofthevariabletowhichitsoperandpoints.____操作符所返回的值是变量的
操作数(变量的值)所指向的值。3.Ifmandnhavebeendeclaredasintegersandp1andp2aspointerstointegers,thenstateerrors,ifany,int
hefollowingstatements.a)p1=&m;b)p2=n;c)*p1=&n;d)p2=&*&me)m=p2-p1;f)p1=&p2;g)m=*p1+*p2++;4.Findtheerror,ifany,ineacho
fthefollowingstatements.a)intx=10;b)int*y=10;c)inta,*b=&a;d)intm;int**x=&m;1.Giventhefollowingdeclarations:intx=10,y=10;int*p1=&x,*
p2=&y;Whatisthevalueofeachofthefollowingexpressions?a)(*p1)++b)--(*p2)c)*p1+(*p2)--d)++(*p2)-*p1