资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,C,语言程序设计教程,*,第8章 指针,8.1 指针与指针变量,8.2 指针与函数,8.3 指针与数组,8.4 指针与字符串,8.5 指针数组与命令行参数,8.6 程序举例,第 8 章 指针,C,语言程序设计教程,10/3/2024,1,C,语言程序设计教程,8.1 指针与指针变量,8.1.1 指针的概念,1.内存与变量地址,内存地址:,内存是计算机用于存储数据的存储器,以一个字节作为存储单元,为了便于访问,给每个字节单元一个唯一的编号,第一字节单元编号为0,以后各单元按顺序连续编号,这些单元编号称为内存单元的地址 。,变量地址:,变量所分配存储空间的首字节单元地址(字节单元编号),。,10/3/2024,2,C,语言程序设计教程,2. 变量的三要素:,名字、类型与值,每个变量都通过,变量名与相应的存储单元相连系,,具体分配哪些单元给变量,由编译系统完成变量名到对应内存单元地址的变换。,变量分配存储空间的,大小,由,类型,决定。,变量的值,则是指相应,存储单元的内容,。,3.,内存存取方式,直接存取,:把直接按变量名或地址存取变量值的方式称为 “直接存取”方式。,间接存取,:通过定义一种特殊的变量专门存放内存或变量的地址,然后根据该地址值再去访问相应的存储单元,。,10/3/2024,3,C,语言程序设计教程,系统为特殊变量,p(,用来存放地址的)分配的存储空间地址是4800,,p,中保存的是变量,a,的地址,即4000,当要读取,a,变量的值12345时,不是直接通过,a,变量,也不是直接通过保存12345的内存单元的地址4000去取值,而是先通过变量,p,得到,p,的值4000,即,a,的地址,再根据地址4000读取它所指向单元的值12345。,这种间接的通过变量,p,得到变量,a,的地址,再存取变量,a,的值的方式即为“间接存取”。,通常称变量,p,指向变量,a,,变量,a,是变量,p,所指向的对象,4000,12345,4000,4002,4800,p,a,p(4800),p(4800),a(4000),4000,12345,4000,间接存取示意图,10/3/2024,4,C,语言程序设计教程,4.指针的概念,在语言中,用,指针,来表示一个变量指向另一个变量这样的指向关系。,所谓指针即地址。,一个变量的指针即该变量的地址,如4000就是指向变量,a,的指针。,指针变量,:专门存放地址的变量,如,p,即是一个指针变量,它存放的,是,a,的地址4000。,10/3/2024,5,C,语言程序设计教程,8.1.2 指针变量的定义与初始化,1. 指针变量的定义,类型标识符 *指针变量名;,例:,float *p1;,(,定义,p1,为,指向实型变量的指针变量,),char *p2;,(,定义,p2,为,指向字符型变量的指针变量,),在指针变量定义中,*是一个说明符,它表明其后的变量是指针变量,如,p,是指针变量,而不要认为“*,p”,是指针变量。,指针变量定义时指定的数据类型不是指针变量本身(变量存放的值)的数据类型,而是指针变量所指向的对象(或称目标)的数据类型,指针变量存放的是所指向的某个变量的地址值,而普通变量保存的是该变量本身的值,指针变量并不固定指向一个变量,可指向同类型的不同变量,10/3/2024,6,C,语言程序设计教程,(1),指针运算符与地址运算符,与指针引用有关的两个运算符:&与*。,&:取地址运算符,*:指针运算符,或称指向运算符、间接访问运算 符。,指针指向的对象的表示形式:,*指针变量,此处*是访问指针所指对象的运算符,与指针定义时的*不同。,2. 指针变量初始化,10/3/2024,7,C,语言程序设计教程,(,2) 指针变量初始化,若有定义:,int,a,*p;,语句仅仅定义了指针变量,p,,但指针变量并未指向确定的变量(或内存单元)。因为这些指针变量还没有赋给确定的地址值,只有将某一具体变量的地址赋给指针变量之后,指针变量才指向确定的变量(内存单元)。,指针变量初始化:,在定义指针时同时给指针一个初始值,如:,int,a,*p=,4000,3,a(4000),pa,*pa,10/3/2024,8,C,语言程序设计教程,(3) 指针变量的引用, *指针变量名代表所指变量的值。, 指针变量名代表所指变量的地址。,有定义:,int,a,*p=,用*,p,来表示,p,指向的对象,a,*p,与,a,是等价的。,*,p,可以象普通变量一样使用。 例如:,a=12;,*p=12;,scanf,(%d,scanf,(%d,p);,printf,(,“,%d%d,”,*p,a);,注意,:,*,与,&,具有相同的优先级,,结合方向从右到左,。这样,,&*,p,即,&(*,p),是对变量,*,p,取地址,它与,&,a,等价;,p,与,&(*,p),等价,,a,与,*(&,a),等价。,10/3/2024,9,C,语言程序设计教程,例,main(0,int,a=100,b=10,*p1,p2;,p1=,printf,(,“,%d,%d,%d,%dn,”,a,b,*p1,*p2);,10/3/2024,10,C,语言程序设计教程,例 输入,a,b,两个整数,按从大到小顺序输出。,main(),int,*p1,*p2,*p,a,b;,scanf,(,“,%d,%d,”,p1=,if(ab)p=p1;p1=p2;p2=p;,printf,(,“,a=%d,b=%dn,”,a,b);,printf,(,“,max=%d,min=%d,”,*p1,*p2); ,输入:5,9,输出:,a=5,b=9,max=9,min=5,算法:不交换,int,变量的值,只交换两个指针变量的值。,10/3/2024,11,C,语言程序设计教程,程序说明:,注意程序第一行的*,p1,*p2,与程序最后一行的不同含义。,指针变量应在程序中赋值,但不能写成*,p1=&a;,如果,p,指向,a,,则*,p,可以出现在,a,可以出现的任何位置.,*,与&的说明:设,int,a=1,*p;p=,&*p,从左向右结合,相当于&,a,*&a,先取,a,的地址,再进行*运算,即指向&,a,所指向的变量,相当于,a,(*p)+,相当于,a+,10/3/2024,12,C,语言程序设计教程,例 从键盘输入三个整数,要求设三个指针变量,p1,p2,p3,,使其分别从大到小指向三个整数,然后输出。,main(),int,*p1,*p2,*p3,i,j,k,temp;,scanf,(,“,%d,%d,%d,”,p1=,if(_ )temp=*p1;_;_;,if(_)temp=*p1;_;_;,if(_ _)temp=*p2;_;_;,printf,(,“,%d%d%d,”,*p1,*p2,*p3);,10/3/2024,13,C,语言程序设计教程,8.1.3 指针运算,1. 指针的赋值运算,(1)将变量地址值赋给指针变量,使指针指向该变量。,设有如下定义:,int,a,b,*pa,*,pb,;,float *pf;,第一行定义了整型变量,a,b,及指针变量,pa,pb,。pa、,pb,还没有被赋值,因此,pa、,pb,没有指向任何变量, 下面语句完成对,pa,pb,的赋值:,pa=,pb,=,10/3/2024,14,C,语言程序设计教程,例如,:,int,j,k;,int,*pointer1,*pointer2;,pointer1=,pointer2=,pointer1,j,pointer2,k,10/3/2024,15,C,语言程序设计教程,(2) 相同类型的指针变量间的赋值,pa,与,pb,都是整型指针变量,它们间可以相互赋值,如:,pb,=pa;,即,pa,pb,都指向变量,a,,此时,a、*pa、*,pb,是等价的。指针指向变化如下图:,注意,:只有相同类型的指针变量才能相互赋值,如,pf=pa;,是不允许的。因为,pa,是整型指针,pf,是浮点型指针。,&a,&b,pa,pb,a,*pa,b,*,pb,&a,&a,pa,pb,a,*pa,*,pb,b,10/3/2024,16,C,语言程序设计教程,(),给指针变量赋,空值,给指针变量赋,空值,,说明该指针不指向任何变量。,“空”指针值用,NULL,表示,,NULL,是在头文件,stdio,.h,中预定义的常量,其值为,在使用时应加上预定义行,如:,#,include ,stdio,.h,int,*pa=NULL;,亦可以用下面的语句给指针赋“空值”:,a=0;,或:,pa=,0,;,这里指针,pa,并非指向0地址单元,而是具有一个确定的“空值”,表示,pa,不指向任何变量。,注意,:,指针虽然可以赋值0,但却不能把其它的常量地址赋给指针。例如:,pa=4000;,是非法的,。,10/3/2024,17,C,语言程序设计教程,例 8.1 指针定义与初始化,main(),int,a,b;,int,*pointer_1,*pointer_2;,a=100;b=10;,pointer_1=,pointer_2=,printf,(%d,%dn,a,b);,printf,(%d,%dn,*pointer_1,*pointer_2);,10/3/2024,18,C,语言程序设计教程,程序运行结果:,100,10,100,10,&a,&b,b,Pointer_1,Pointer_2,a,*pointer_1,*pointer_2,10/3/2024,19,C,语言程序设计教程,例8.2 从键盘上输入两个整数到,a、b,按由大到小输出。,#,include ,main( ),int,a,b,*pa=&a,*,pb,=/*,定义指针变量,pa、,pb,如下页图,a*/,scanf,(%d%d,if (*pa*,pb,) p=pa; /*,进行指针交换,如下页,图,b,c*/,pa=,pb,;,pb,=p;,printf,(n a=%d,b=%dn,a,b);,printf,(n max=%d,min=%d,*pa,*,pb,);,/* pa,指向大数,,pb,指向小数*/,10/3/2024,20,C,语言程序设计教程,若输入:,12 22,输出结果:,a=12,b=22 max=22,min=12,(,b),(c),指针变化示意图,12,22,p,pa,pb,12,22,p,pa,pb,pa,pb,a,b,10/3/2024,21,C,语言程序设计教程,2. 指针的算术运算,(1) 加减运算,:,一个指针可以加、减一个整数,n,,其结果与指针所指对象的数据类型有关。指针变量的值应增加或减少“,n,sizeof,(,指针类型)”。,加减运算常用于数组的处理,。,对指向一般数据的指针,加减运算无实际意义。例如: ,int,a10,*p=a,*x; ,x=p+3; /*,实际上是,p,加上3*2个字节赋给,x, x,指向数组的第三个分量*/,对于不同基类型的指针,指针变量,“,加上,”,或,“,减去,”,一个整数,n,所移动的字节数是不同的。例如: ,float a10, *p=a, *x; ,p=p+3; /*,实际上是,p,加上3*4个字节赋给,x, x,依然指向数组的第三个分量*/,10/3/2024,22,C,语言程序设计教程,(2) 自增自减运算,指针变量自增、自减运算具有上述运算的特点,但有前置后置、先用后用的考虑,务请小心。 例如: ,int,a10, *p=a, *x; ,x=p+; /* x,第一个元素分量,,p,指向第二个元素*/,x=+p; /* x、 p,均指向数组的第二个分量*/,*,p+,相当于*,(,p+ +)。,*(p+),与(*,p)+,含义不同,前者表示,地址自增,,后者表示,当前,所指向的数据自增,。,10/3/2024,23,C,语言程序设计教程,2.,*&,a,的含意是什么?,(答:,a,),3.,(*p)+,相当于什么?,(答:,a+,),思考:,1.若有定义,int,a,*p;,执行了,“,p=&a”,则: “&*,p”,的含意是什,么?,(答:,相当于&,a,),10/3/2024,24,C,语言程序设计教程,3.,指针的关系运算,与基本类型变量一样,指针可以进行关系运算。,在关系表达式中允许对两个指针进行所有的关系运算。若,p,q,是两个同类型的指针变量,则:,pq,p=q,都是允许的。,指针的关系运算在指向数组的指针中广泛的运用,假设,p、q,是指向同一数组的两个指针,执行,pq,的运算,其含义为,若表达式结果为真(非值),则说明,p,所指元素在,q,所指元素之后。或者说,q,所指元素离数组第一个元素更近些。,注意:在指针进行关系运算之前,指针必须指向确定的变量或存储区域,即指针有初始值;另外,只有相同类型的指针才能进行比较。,10/3/2024,25,C,语言程序设计教程,8.1.4 多级,指针,把指向指针型数据的指针变量称为指向指针的指针,或,称多级指针,。,二级指针的定义形式如下:,数据类型 *指针变量,例如:,int,a,*p,*pp;,a=22;,p=,pp=,假设变量,a,的地址为4000,指针,p,的地址为4100,二级指针,pp,的地址为4800。,a、p、pp,三者的关系如上图。,&p=4100,&a=4000,22,pp(4800) p(4100) a(4000),10/3/2024,26,C,语言程序设计教程,8.2 指针与函数,8.2.1 指针作为函数参数,利用指针作函数参数,可以实现函数之间多个数据的传递,当形参为指针变量时,其对应实参可以是指针变量或存储单元地址。,函数形参为指针变量,用,指针变量,或,变量地址,作实参,例8.3 编写一个交换两个变量的函数,在主程序中 调用,实现两个变量值的交换。,10/3/2024,27,C,语言程序设计教程,程序如下:,#,include,main(),int,a,b;,int,*pa,*,pb,;,void swap(,int,*p1,int,*p2); /*,函数声明*/,scanf,(%d%d,pa=,/* pa,指向变量,a */,pb,=,/*,pb,指向变量,b */,swap(pa,pb,);,printf,(,na,=%d,b=%dn,a,b);,或:,swap(,10/3/2024,28,C,语言程序设计教程,接上页:,void swap(,int,*p1,int,*p2),int,temp;,temp=*p1; /*,交换指针,p1、p2,所指向的变量的值*/,*,p1=*p2;,*p2=temp;,程序运行结果如下:,输入:,12 22,输出:,a=22,b=12,10/3/2024,29,C,语言程序设计教程,分析以下,swap,函数能否实现交换:,swap(,int,*p1,int,*p2),int,*p;,*p=*p1;,*,p1=*p2;*p2=*p;,swap(,int,x,int,y),int,t;t=x,x=y;y=t;,由于*,p,并不指向某一个变量,即其中的地址并不确定,可能造成系统破坏,由于函数的“值传递”,虽然交换了变量,x,y,的值,但并不能改变,a,b,的值。,10/3/2024,30,C,语言程序设计教程,两点说明:,(1) 若在函数体中交换指针变量的值,实参,a、b,的值并不改变,指针参数亦是传值。 例如:,int,*p; ,p=p1; p1=p2; p2=p; ,不要希望如此完成处理。 ,(2) 函数中交换值时不能使用无初值的指针变量作临时变量。 例如: ,int,*p; ,*p=*p1; *p1=*p2; *p2=*p; ,p,无确定值,对,p,的使用可能带来不可预期的后果。,10/3/2024,31,C,语言程序设计教程,8.2.2 指针函数,指针函数,:是指返回值为指针的函数,指针函数的定义形式:,类型标示符 *函数名(参数),例如:,int,*fun(,int,a,int,b),函数体语句,在函数体中有返回指针或地址的语句,形如:,return (&,变量名);,或,return (,指针变量);,并且返回值的类型要与函数类型一致。,10/3/2024,32,C,语言程序设计教程,例8.3 分析如下程序,main( ),int,a,b,*p;,int,*max(,int,x,int,y);,scanf,(“%d,%d”,p=max(a,b);,printf,(“max=%d”,*p);,int,*max(,int,x,int,y), if xy) return (,else return (,10/3/2024,33,C,语言程序设计教程,8.2.3 指向函数的指针,一个函数包括一组指令序列,存储在某一段内存中,这段内存空间的起始地址称为,函数的入口地址,称函数入口地址为,函数的指针,。,函数名,代表函数的入口地址,可以定义一个指针变量,其值等于该函数的入口地址,指向这个函数,这样通过这个指针变量也能调用这个函数。这种指针变量称为,指向函数的指针变量,。,定义指向函数的指针变量的一般形式为,:,类型标识符(*指针变量名)( ),;,例如:,int,(*p)(); /*,指针变量,p,可以指向一个整型函数*/,float (*q)(); /*,指针变量,q,可以指向一个浮点型函数*/,10/3/2024,34,C,语言程序设计教程,刚定义的指向函数的指针变量,亦象其它指针变量一样要赋以地址值才能引用。当将某个函数的入口地址赋给指向函数的指针变量,就可用该指针变量来调用所指向的函数,给函数指针赋初值:将函数名(函数的入口地址值)赋给指针变量,例如,int,m, (*p)( );,int,max(,int,a,int,b);,则可以,p=max; /* p,指向函数,max() */,指针调用函数的,一般形式为,:,(,*指针变量)( 实参表),;,如上例,:,m=(*p)(12,22); /*,比较,m=max(12,22); */,10/3/2024,35,C,语言程序设计教程,注意:,用函数指针调用函数是间接调用,没有参数类型说明,,C,编译系统也无法进行类型检查,因此,在使用这种形式调用函数时要特别小心。实参一定要和指针所指函数的形参类型一致。,函数指针可以作为函数参数,此时,当函数指针每次指向不同的函数时,可执行不同的函数来完成不同的功能,例 8.4,函数,max(),用来求一维数组的元素的最大值,在主调函数中用函数名调用该函数与用函数指针调用该函数来实现。,10/3/2024,36,C,语言程序设计教程,程序如下:,#,include ,stdio,.h,#define M 8,main(),float,sumf,sump;,float aM=11,2,-3,4.5,5,69,7,80;,float (*p)(); /*,定义指向函数的指针,p*/,float max(float a,int,n); /*,函数声明*/,p=max; /*,函数名(函数入口地址)赋给指针,p*/,sump=(*p)(a,M); /*,用指针方式调用函数*/,sumf,=max(a,M); /*,用函数名调用,max(),函数*/,printf,(sump=%.2fn,sump);,printf,(,sumf,=%.2fn,sumf,);,10/3/2024,37,C,语言程序设计教程,程序接上页:,float max(float a,int,n),int,k;,float s;,s=a0;,for (k=0;kn;k+),if (sak) s=ak;,return s;,程序运行结果:,sump=80.00,sumf,=80.00,10/3/2024,38,C,语言程序设计教程,指向函数的指针的使用步骤:,(1),定义一个指向函数的指针变量,形如:,float (*p)();,(2),为函数指针赋值,格式如下:,p=,函数名;,注意:赋值时只需给出函数名,不要带参数。,(3),通过函数指针调用函数,调用格式如下:,s=(*p)(,实参);,10/3/2024,39,C,语言程序设计教程,8.3 指针与数组,8.3.1 指向一维数组的指针,数组名是一个常量指针,它的值为该数组的首地址,1.指向数组的指针的定义方法与指向基本类型变量的指针的定义方法相同,,例如:,int,a10=1,3,5,7,9;,int,*p;,p=&a2,; (,把数组元素,a2,的地址赋给指针变量,p),p=a;,(,把数组的首地址赋给指针变量,p),10/3/2024,40,C,语言程序设计教程,C,语言规定,:数组名代表数组首地址,是一个地址常量,。,因此,下面两个语句等价:,p=,p=a;,在定义指针变量的同时可赋初值:,int,a10, *p= (,或,int,*p=a;),等价于:,int,*p;,p=,两句,。,10/3/2024,41,C,语言程序设计教程,指向数组的指针变量,p,&a0,1,3,15,17,19,p,a0,:,a9,p9,a+0,p+1,或,a+1,p+9,或,a+9,*(,a+9),或*(,p+9),10/3/2024,42,C,语言程序设计教程,2.通过指针引用数组元素,*,p=5;,表示,对,p,当前所指的数组元素赋以一个值5。,C,规定:,p+1,指向数组的下一元素(而不是将,p,值简单地加1)。,p+1,意味着使,p,的原值(地址),加,d,个字节(,d,为一个数组元素所占的字节数)。,如果,p,的初值为&,a0,则:,(1,),p+i,和,a+i,就是,ai,的地址,或者说它们指向,a,数组的第,i,个元素(见下页图)。,(2)*(,p+i),或,*(,a+i),是,p+i,或,a+i,所指向的数组元素,,即,ai。,(3),指向数组的指针变量也可以带下标,如,pi,与*,(,p+i)、 ai,等价 。,10/3/2024,43,C,语言程序设计教程,*(,p+i),a,数组,a0,a1,a2,ai,a9,p,p+1,a+1,p+i, a+i,p+9, a+9,综上所述,引用一个数组元素有二法:,(1)下标法:如,ai,形式;,(2)指针法:如*(,a+i),或 *(,p+i)。,其中,a,是数组名,,p,是,指向数组的指针变量,其初值,p=a。,10/3/2024,44,C,语言程序设计教程,main(),int,a10;,int,i;,for (i=0;i10;i+),scanf,(%d,printf,(n);,for (i=0;i10;i+),printf,(%d,ai,) ;,例8.5 用三种方法输出数组全部元素。,(1),下标法,10/3/2024,45,C,语言程序设计教程,main(),int,a10;,int,i;,for (i=0;i10;i+),scanf,(%d,printf,(n);,for (i=0;i10;i+),printf,(%d,*(a+i),);,(2),通过数组名计算数组元素地址,输出元素的值,10/3/2024,46,C,语言程序设计教程,(3),用指针变量指向数组元素,main(),int,a10;,int,*p,i;,for (i=0;i10;i+),scanf,(%d,printf,(n);,for (,p=a;p(a+10);p+,),printf,(%d,*p,);,三种方法的比较,:,用,下标法,比较直观,能直接知道是第几个元素;,而用,指针法,则执行效率更高。,10/3/2024,47,C,语言程序设计教程,使用指针变量时,应注意:,(1)指针变量可实现使本身的值改变。,P+,合法;但,a+,不合法(,a,是数组名,代表数组首地址,在程序运行中是固定不变的。),(2)要注意指针变量的当前值。,main(),int,a10;,int,*p, i;,p=a;,for ( ;pa+10;p+),scanf,(%d,p,);,printf,(n);,for (,;p(a+10);p+,),printf,(%d,*p,);,不能&,p,增加:,p=a;,10/3/2024,48,C,语言程序设计教程,(3),*,p+,相当于*(,p+),,因为*与+优先级相同,且结合方向从右向左,其作用是先获得,p,指向变量的值,然后执行,p=p+1;,(4),*(p+),与*(+,p),意义不同,后者是先,p=p+1,,再获得,p,指向的变量值。,若,p=a,,则输出*(,p+),是先输出,a0,,再让,p,指向,a;,输出*(+,p),是先使,p,指向,a,,再输出,p,所指的,a。,(5),(*p)+,表示的是将,p,指向的变量值+,10/3/2024,49,C,语言程序设计教程,1、写出下列程序的执行结果,#,include,main(),int,a=1,2,3,4,5,6,*p=a;,printf,(,“,%d,”,(*+p)+);,10/3/2024,50,C,语言程序设计教程,2、写出下列程序的执行结果,#,include,main(),int,a=1,2,3,4,5,6,*p=a;,*(p+3)+=2;,printf,(,“,n1=%d,n2=%d,”,*p,*(p+3);,10/3/2024,51,C,语言程序设计教程,3、写出下列程序的执行结果,#,include,main(),int,a=1,3,5,7,9,*p=a;,printf,(,“,%dn,”,(*p+);,printf,(,“,%dn,”,(*+p);,printf,(,“,%dn,”,(*+p)+);,10/3/2024,52,C,语言程序设计教程,8.3.2 二维数组与多维数组的指针表示法,1.二维数组的地址,设有一个二维数 组,a,它有三行四列:,int,a34;,数组名,a:,代表整个二维数组的首地址,也就是第0行的首地址。,a+i:,代表第,i,行的首地址。(见下页图),10/3/2024,53,C,语言程序设计教程,数组名,a,代表整个二维数组的首地址:,a0,a1,a2,a,=,=,=,1,9,17,3,11,19,7,15,23,上图,a,数组包含三个元素:,a0,a1,a2.,而每个元素又,是一个一维数组,它包含4个元素(即4个列元素),如:,a0,又包含:,a00,a01,a02,a03.,10/3/2024,54,C,语言程序设计教程,一维数组名,ai:,代表第,i,行的首地址,即第,i,行中第0列元素的地址(既,&,ai0)。,ai+j:,代表第,i,行中的第,j,个元素的地址,即为,&,aij。,注意地址变化的单位数值在不同的场合的实际字节数是不同的:,“,a+1,”,中的,“,1,”,实际代表数组中,一行,元素所占的总字节数;,“,ai+1”,中的,“,1,”,代表数组中一个元素所占的字节数。,10/3/2024,55,C,语言程序设计教程,a+2,a,数组,a0,a1,a2,a,a+1,(,2000),(,2008),(,2016),a,代表,第0行,的首地址,a+1,代表第1,行,的首地址,a+2,代表第2,行的首地址.每行存放4个整型数据(即1个元素占2个字节),因此,这里+1的含义是:+4*2=+8个字节.,10/3/2024,56,C,语言程序设计教程,2000,1,2002,3,2004,5,2006,7,2008,9,2010,11,2012,13,2014,15,2016,17,2018,19,2020,21,2022,23,a,a+1,a+2,a0+1,a0+2,a0+3,行地址,元素地址的表示法,10/3/2024,57,C,语言程序设计教程,例8.6 用指针表示法输出二维数组的各元素。,#,include,main(),static,int,a23=0,1,2,3,4,5;,int,k,j,*p;,for (j=0;j2;j+),/*,方式1 */,for (k=0;k3;k+),printf,(%5d,*(aj+k);,/* aj,是,j,行首地址,,aj+k,是,j,行,k,列元素的地址*/,putchar,(,n,);,putchar,(,n,);,10/3/2024,58,C,语言程序设计教程,接上页:,for (j=0;j2;j+) /*,方式2 */,for (k=0;k3;k+),printf,(%5d,*(*(a+j)+k);,/* *(a+j),是,j,行首地址,*(,a+j)+k,是,j,行,k,列元素的地址*/,putchar,(,n,);,p=a;,/* p,指向数组的第一个元素 */,for (j=0;j2;j+) /*,方式3 */,for (k=0;k=n) p+=n-1;,/*,指针指到要复制的第一个字符 */,10/3/2024,68,C,语言程序设计教程,for (;*p!=,0,;p+,q+),*q=*p;,*q=,0,; /*,字符串以,0,结尾 */,printf,(String a : %sn,a);,printf,(String b : %sn,b);,输入:,3,输出:,computer,mputer,考虑一下,若输出语句改为如下语句会如何?,printf,(“string a is :%sn”,p);,printf,(“string b is %sn”,q);,10/3/2024,69,C,语言程序设计教程,8.4.2 字符串数组,字符串数组,:是指数组中的每个元素都是一个存 放字符串的数组。,字符串数组可以用一个二维字符数组来存储,。,例如:,char,languge,3 10;,数组的第一个下标决定字符串的个数,第二个下标是字符串的最大长度(实际最多9个字符,0占一位置)。,可以对字符串数组赋初值。例如:,char,languge,3 10;=“Basic”, “c+”, “,pascal,”,10/3/2024,70,C,语言程序设计教程,综合练习:,分别用字符数组和指针变量两种方法将字符串,a,复制到字符串,b,中。,10/3/2024,71,C,语言程序设计教程,用字符数组:,main(),char a=,”,i am a boy.,”,b;,int,i,j;,for(i=0;ai!=0,;i+)bi=ai;,printf,(,“,string a is:%sn,”,a);,printf,(,“,string b is :,”,);,for(j=0;ji;j+),printf,(,“,%c,”,bj);,10/3/2024,72,C,语言程序设计教程,用指针变量:,main(),char a=,”,i am a boy.,”,b,*p1,*p2;,int,i;,p1=a;p2=b;,for(;*p1!=,0,;p1+,P2+)*p2=*p1;,*p2=,0,;,printf,(,“,string a is:%sn,”,a);,printf,(,“,string b is :,”,);,for(i=0;bi!=,0,;i+),printf,(,“,%c,”,bi);,10/3/2024,73,C,语言程序设计教程,综合练习:,1、写出下列程序的输出结果,#,include,void string(char *s),static,int,n=0;,int,k;,k=*s-,0,;n+=k;,printf,(,“,n=%d,*s=%c,s=%sn,”,n,*s,s);,void main(void),char a=,”,123,”,;,int,k;,for(k=0;k=,A,&*s=,z,)+n;,return n;,10/3/2024,75,C,语言程序设计教程,3、以下程序运行后,输出结果是,main(),static char a=ABCDEFGH,b=,abCDefFh,;,char *p1,*p2;,int,k;,p1=a; p2=b;,for(k=0;k=7;k+),if (*(p1+k)=*(p2+k),printf,(%c,*(p1+k);,printf,(n);,10/3/2024,76,C,语言程序设计教程,8.5 指针数组与命令行参数,8.5.1 指针数组,指针数组:是指针变量的集合。即它的每一个元素都是指针变量,且都具有相同的存储类别和指向相同的数据类型。,指针数组的定义形式为:,类型标识符 *数组名数组长度说明;,例如:,int,*p10;,由于 比*的优先级高,因此,p,先与 10结合成,p10,,而,p10,正是数组的定义形式,共有10个元素。最后,p10,与*结合,表示它的各元素可以指向一个整型变量。,10/3/2024,77,C,语言程序设计教程,指针数组广泛应用于对字符串的处理,例如有定义:,char *p3;,定义了一个具有三个元素,p0,p1,p2,的指针数组。每个元素都可以指向一个字符数组,或字符串。,若利用数组初始化,则:,char *p3= “Basic”, “c+”, “,pascal,”;,P0,指向字符串“,Basic”;,P0,指向字符串,“,c+”;,P0,指向字符串,“,pascal,” ;,10/3/2024,78,C,语言程序设计教程,例8.9 字符指针数组的赋值,#,define NULL 0,main( ),static char a =“Fortran”;,static char b =“COBOL”;,static char c =“Pascal”;,int,i;,char *p4,;,p0=a; p1=b; p2=c; p3=NULL;,for (i=0;pi!=NULL;i+),printf,(“Language %d is %sn”,i+1,pi);,10/3/2024,79,C,语言程序设计教程,例8.10 有若干本书,将书名按字典顺序排序,#,include,#include,main(), char *,bname,=Programming in ANSI C,BASIC,Visual C+ 6.0 Programming ,TRUBO C 2.0;,int,i,m;,void sort(char *name,int,);,m=,sizeof,(,bname,)/,sizeof,(char *); /*,字符串个数*/,sort(,bname,m); /*,排序,改变指针的连接关系*/,printf,(n);,for (i=0;im;i+) /*,输出排序结果*/,printf,(%8s,bname,i);,10/3/2024,80,C,语言程序设计教程,void sort(char *name,int,n) /*,选择排序*/,char *t;,int,i,j,k;,/* k,记录每趟最小值下标 */,for (i=0;in-1;i+) k=i;,for (j=i+1;j0) k=j; /*,第,j,个元素更小*/,if (k!=i) /*,最小元素是该趟的第一个元素 则不需交换 */ ,t=namei;namei=namek;namek=t; ,输出结果为:,BASIC Programming in ANSI C TRUBO C 2.0 Visual C+ 6.0 Programming,10/3/2024,81,C,语言程序设计教程,注意,: (1)字符数组中每个元素可存放一个字符,而字符指针变量存放字符串首地址,而不是存放在字符指针变量中。 (2)对字符数组,与普通数组一样,不能对其进行整体赋值,只能给各个元素赋值,而字符指针变量可以直接用字符串常量赋值。例如,若有如下定义:,char a10;,char *p;,则语句,a=,”computer”,;,是非法的,因为数组名,a,是一个常量指针,不能对其赋值。只能对各个元素分别赋值:,a0=c;a1=o;a2=m;a3=p;a7=r;,但语句:,p=,”computer”;,是合法的。,10/3/2024,82,C,语言程序设计教程,8.5.2 指针数组与命令行参数,在操作系统命令状态下,可以输入程序或命令使其运行,称,命令行状态,。输入的命令(或运行程序)及该命令(或程序)所需的参数称为,命令行参数,。,如:,copy,fd fs,copy,是文件拷贝命令,,fd,、,fs,是命令行参数。,main,函数是可以有参数的,但与普通函数不同。,带形参的,main( ),函数的一般形式是:,main,(,int argc, char *,argv, ), ,形参,argc,记录命令行中字符串的个数,,argv,是一个字符型指针数组,每一个元素顺序指向命令行中的一个字符串。,10/3/2024,83,C,语言程序设计教程,1.,main(),函数的形参与实参,main(),函数由系统自动调用,而不是被程序内部的其它函数调用,,main(),函数所需的实参不可能由程序内部得到,而是由系统传送。,main(),函数所需的实参与形参的传递方式也与一般函数的参数传递不同,实参是在命令行与程序名一同输入,程序名和各实际参数之间都用空格分隔。,格式为:执行程序名 参数1 参数2 参数,n,形参,argc,为命令行中参数的个数,(包括执行程序名),其值大于或等于1,而不是象普通,C,语言函数一样接受第一个实参。,形参,argv,是一个指针数组,其元素依次指向命令行中以空格分开的各字符串。,即:第一个指针,argv,0,指向的是程序名字符串,argv,1,指向参数1,,argv,2,指向参数2,,argv,n,指向参数,n。,10/3/2024,84,C,语言程序设计教程,2.命令行参数的传递示例,例,8.11,分析下列程序,指出其执行结果,该程序命名为,exam.c,经编译连接后生成的可执行程序为,exam.exe,#,include ,stdio,.
展开阅读全文