C语言程序设计课件:指针_第1页
C语言程序设计课件:指针_第2页
C语言程序设计课件:指针_第3页
C语言程序设计课件:指针_第4页
C语言程序设计课件:指针_第5页
已阅读5页,还剩48页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C语言程序设计

指针10.1指针概念

10.1.1指针定义

10.1.2指针初始化

10.1.3指针运算符

10.2指针变量运算

10.2.1指针变量赋值运算

10.2.2指针变量的算术运算

10.2.3指针变量间的关系运算

10.3指针和数组

10.3.1数组指针变量

10.3.2指针与一维数组

10.3.3指针与二维数组

10.3.4指针数组

10.4指针和函数

10.4.1指针作为函数参数

10.4.2指针作为函数返回值

10.4.3指针型函数

10.4.4函数指针变量

10.5指针与字符串

10.5.1字符串表示方法

10.5.2字符串处理函数的实现

10.6多重指针

10.6.1指向指针的指针

10.6.2命令行参数

内存单元的编号也叫做地址。根据内存单元的编号即地址就可以找到所需的内存单元,通常也把这个地址称为指针。2.变量的“直接访问”方式10.1指针概念

直接访问:按变量地址存取变量值间接访问:通过存放变量地址的变量去访问变量例

i=3;-----直接访问指针变量…...…...2000200420062005整型变量i10变量i_pointer20012002200320003例*i_pointer=20;-----间接访问20指针变量…...…...2000200420062005整型变量i10变量i_pointer2001200220032000整型变量k例

k=i;--直接访问

k=*i_pointer;--间接访问10例

k=i;k=*i_pointer;与简单变量一样,指针变量也必须先定义后使用.指针变量定义的一般格式:类型名*变量名;例如:

int*pa;(pa是指向整型变量的指针变量)

char*pb;(pb是指向字符型变量的指针变量)

定义了名字为pa、pb的两个指向不同类型数据的指针变量。

10.1.1指针定义

指针变量的初始化的一般形式为数据类型*指针变量名=初始地址值;例如:

int*pa=&i;在指针变量初始化中,通常用“&变量名”来表示一个基本类型变量的地址。在定义指针变量pa的同时,把变量i的地址作为初值来初始化pa。应注意的是,初始化中的“*pa=&i”不是运算表达式,而是一个说明语句。在这里将变量i的地址值赋给指针变量pa,而不是*pa。10.1.2指针初始化

注意:(1)指针目标变量的数据类型必须与指针的数据类型相一致。类型不一致将引起致命错误。例如,下面的初始化方式就是错误的,导致错误的原因就是类型不一致。

doublea:

int*pa=&a;(2)当把一个变量的地址作为初值赋给指针变量时,这个变量必须在这个指针初始化之前定义过。注意:(3)可以将一个指针的值赋给另一个指针变量。例如:

intb;

int*pb=&b;

int*q=pb;(4)可以把一个指针初的化为一个空指针。例如:

int*px=NULL;/*px是指针变量,初值为NULL,不指向任何目标*/(1)取地址运算符&取地址运算符&是单目运算符,其结合性为自右至左,其功能是取变量所占用的存储单元的首地址。例如,

inti,*i_pointer;

i_pointer=&i;将变量i的地址(注意不是i的值)赋给i_pointer。这个赋值语句可以理解为i_pointer接受i的地址。如果给i分配的地址是2000开始的单元,则赋值后i_pointer的值是200010.1.3指针运算符

(2)取内容运算符*取内容运算符*是单目运算符,其结合性为自右至左,它的作用是通过指针变量来访问它所指向的变量(存数据或取数据)。故在*运算符之后跟的变量必须是指针变量。i_pointer中存放i的地址,现赋值i=5;i_pointer=&i;j=*i_pointer;这个赋值语句可以理解为把i_pointer中存放的值当做地址,然后取那个地址(i的地址)中的值赋给变量j,结果是把“5”赋给j。常见的指针赋值运算有以下几种形式。(1)把一个变量的地址赋给指向相同数据类型的指针变量。例如:

inta,*pa;

pa=&a;(2)相同数据类型的指针变量间可以相互赋值。例如:

int*p,*q;

q=p;(3)把数组的地址赋给指向相同数据类型的指针变量。例如:

doublex[10],*pa,*pb;

pa=x;

pb=&x[0];10.2指针变量运算

10.2.1指针变量赋值运算

(4)把数组的首地址赋予指向数组元素的指针变量。例如:

inta[5],*pa;

pa=a;数组名表示数组的首地址,故可赋予指向数组元素的指针变量pa。(5)把字符串的首地址赋予指向字符类型的指针变量。例如:

char*pc;

pc="clanguage";或用初始化赋值的方法写为:char*pc="CLanguage";(6)把函数的入口地址赋予指向函数的指针变量。例如:int(*pf)();

pf=f;/*f为函数名*/在使用赋值运算时,不要将一个整数(整数0除外)或其他类型的数是不合法的。

inta,*p1;

float*p;

p1=100;

p1=a;另外,赋值语句p=p1;也是错误的。p和p1虽然都是指针变量,但分别指向不同类型的目标变量。可以将整数0赋予一个指针变量例如:pa=0;这时指针变量pa的值为0,表示该指针为空指针。空指针并不是指针的存储空间为空。而是有着特定的值---0,它表示指针的一种状态,即该指针不指向任何目标变量。

注意:在程序中使用指针变量之前,一定要给该指针赋予确定的地址值。一个没有赋值的指针其指向是不定的。在使用指向不定的指针处理数据时,常常会破坏内存中其他领域的内容,严重时会造成系统失控。因此在程序中不要使用指向不定的指针。加减算术运算指针变量作为地址量加上或减去一个整数n,表示指针变量当前位置前移或后移n个存储单元。例如:int*pn;不妨设pn=0x0000,那么pn+n=pn+n*sizeof(int)=0x0000+n*2。一般说来,对于“type*pn;”来说,“pn+n”表示的地址是“pn+n*sizeof(type)”,其中Type是某种数据类型,如整型、实型或字符型等。10.2.2指针变量的算术运算

指针变指针变量自增(++)、自减(--)运算指针变量自增(++)和自减(--)运算也是地址运算,指针变量自增(++)运算后就指向内存中下一个数据位置,指针变量自减(--)运算后就指向内存中上一个数据位置。运算后指针变量地址值也取决于它所指向的数据类型。指针变量的“++”、“--”运算也分为前置运算和后置运算,当它们和其他运算符出现在—个表达式中的时候,要注意它们之间的结合规则和运算顺序。例如:y=*p++;

y=*++p;y=(*p)++;

y=++(*p);设指针变量p1和p2指向同类型的数据,则“p2-p1”运算的结果是两个指针变量所指向的地址位置之间的数据个数。例如:type*p1,*p2;则p2-p1=(p2-p1)/sizeof(type)两个指针变量相减也是地址计算,但结果值不是地址量,是按公式计算得到的一个整数。其中,“sizeof(type)”是表示指针变量的数据类型所占的字节数。10.2.3指针变量间的关系运算

指向相同数据类型的指针变量之间可以进行各种关系运算。两个指针变量之间的关系运算表示它们的目标变量的地址位置之间的关系。假设数据在内存中的存储逻辑是由前向后,则指向后方的指针变量大于前方的指针变量。例如:p<qp=q指向不同数据类型的指针变量之间的关系运算是没有意义的。指针变量与一般整数变量之间的关系运算也是没有意义的。但是指针变量可以和整数0之间进行等于或不等于的关系运算,用以判断指针变量是否为空指针,即无效指针。例如:p==0或p!=010.3指针和数组

10.3.1数组指针变量定义一个指向数组元素的指针变量的方法,与以前介绍的指向变量的指针变量相同。inta[10];/*定义a为包含10个整型数据的数组*/int*p;/*定义p为指向整型变量的指针变量*/p=&a[0];/*把a[0]素的地址赋给指针变量p*/注意:

因为数组为int型,所以指针变量也应为指向int型的指针变量。通过指针引用数组元素C语言规定:如果指针变量p指向数组中的一个元素,则p+1指向同一数组中的下一个元素。例如,若p的初值为&a[0],则:

①p+i和a+i就是a[i]的地址,或者说它们指向a数组的第i个元素。

②*(p+i)或*(a+i)就是p+i或a+i所指向的数组元素,即a[i]。例如,*(p+5)或*(a+5)就是a[5]。

③指向数组的指针变量也可以带下标,如p[i]与*(p+i)等价。

引用一个数组元素方法:

①下标法,即用a[i]形式访问数组元素。在前面介绍数组时都是采用这种方法。

②指针法,即采用*(a+i)或*(p+i)形式,用间接访问的方法来访问数组元素,其中a是数组名,p是指向数组的指针变量,其初值p=a。用3种方法比较如下:(1)第①和②两种方法执行效率相同。C编译系统将a[i]转换成*(a+i)进行处理。即先计算元素地址。因此用这两种方法找出数组元素比较费时。(2)用第③种方法比第①、第②方法快,用指针变量直接指向元素,不需要每次都重新计算地址,像p++这样的自加是比较快的,能大大提高执行效率。(3)用下标法比较直观,能直接知道是第几个元素。例如,a[5]是数组中的第6个元素。用地址法或指针变量的方法不直观,难以很快判断出当前处理的是哪个元素。例10-2用指针访问数组元素。voidmain(){inta[10],i,*p;p=a;for(i=0;i<10;i++){*p=i;p++;}}注意:(1)指针变量可以实现本身的值的改变。如p++是合法的;而a++是错误的。(2)要注意指针变量的当前值。(3)虽然定义数组时,指定它包含10个元素,但指针变量可以指到数组以后的内存单元,系统并不认为非法。(4)*p++,由于++和*同优先级,结合方向自右而左,等价于*(p++)(5)*(p++)与*(++p)作用不同。若p的初值为a,则*(p++)等价于a[0],*(++p)等价a[1]。(6)(*p)++表示p所指向的元素值加1。(7)如果p当前指向a数组中的第i个元素,则:

*(p--)相当于a[i--];

*(++p)相当于a[++i];

*(--p)相当于a[--i]。10.3.2指针与一维数组一维数组和指针定义如下:inta[4]={1,2,3,4};int*p=a; /*p是指向一维数组元素的指针*/应用指针运算符+、*、[]建立指针与一维数组的关系,如图10-4所示。a[i]、*(a+i)、*(p+i)、p[i]是等价表达式,均表示数组元素。a+i、p+i也是等价表达式,均表示数组元素的地址。要特别注意,p[i]表达式中的p不是数组名,是指针;这是一种下标表示法。10.3.3指针与二维数组1.指向二维数组元素的指针变量例10-4用指针变量输出二维数组元素的值#include<stdio.h>voidmain(){inta[3][4]={1,2,,3,4,5,6,7,8,9,10,11,12};int*p;for(p=a[0];p<a[0]+12;p++){if((p-a[0])%4==0)printf(“\n”);printf(“%4d”,*p);}}

二维数组元素在内存中是以一维方式存储。应用指向二维数组元素的指针,可以很方便地对二维数组实现一维运算从上图可以看到有两个方向的控制:①a、a+i、&a[i]控制的是行,或者说它们是行控制。②*(a+i)+j或a[i]+j控制的是列,即列控制。③虽然a+1和a[1]的值均是1020,但含义(属性)是不一样的。a+1指向a[1],是向纵向移动;a[1]指向a[1][0],是向横向移动。

10.3.4指针数组

一个数组的元素为指针则是指针数组。指针数组是一组有序的指针的集合。指针数组的所有元素都必须是具有相同存储类型和指向相同数据类型的指针变量。数组的元素是指针类型的,指针数组定义的一般格式:

类型*数组名[常量表达式];其中类型说明符为指针值所指向的变量的类型。例如:int*pa[3];表示pa是一个指针数组,它有三个数组元素,每个元素值都是一个指针,指向整型变量。10.4指针和函数

例10-7交换两个整数—指针与函数。#include<stdio.h>/*形参不是指针,无法修改实参,达不到交换两个整数的目的*/voidswapa(intx,inty);/*形参是指针,由于是修改指针本身,也达不到交换两个整数的目的*/voidswapb(int*px,int*py);/*形参是指针,由于是修改指针所指向的目标,能达到交换两个整数的目的*/

10.4.1指针作为函数参数

voidswapc(int*px,int*py);voidmain() {intx=10,y=20;printf("源数据(地址和值):\n");printf("x:%x%d\n",&x,x);printf("y:%x%d\n",&y,y);printf("调用swap1:\n");swapa(x,y);printf("在main函数内x=%dy=%d\n",x,y);printf("调用swapb:\n");swapb(&x,&y);printf("在main函数内x=%dy=%d\n",x,y);printf("调用swapc:\n");swapc(&x,&y);printf("在main函数内x=%dy=%d\n",x,y);}/*交换两个整数--交换形参值*/voidswapa(intx,inty){ inttemp;temp=x;x=y;y=temp; printf("在swap1函数内x=%dy=%d\n",x,y);}/*交换两个整数--交换形参值(地址)*/voidswapb(int*px,int*py){ int*temp;temp=px;px=py;py=temp; printf("在swapb函数内x=%dy=%d\n",*px,*py);}/*交换两个整数--交换实参值*/voidswapc(int*px,int*py){ inttemp; temp=*px;*px=*py;*py=temp; printf("在swapc函数内x=%dy=%d\n",*px,*py);}

指针可作为函数的返回值类型。在处理动态数据结构时,经常遇到返回指针的函数。必须十分明确,数组不可作为函数的返回值类型。返回指针类型函数的一般格式:类型名*函数名(形参表); (有参函数)类型名*函数名(); (无参函数)return语句中,返回局部变量的地址是不允许的。因为函数返回,局部变量自动撤消。动态变量的地址、全局变量的地址和静态变量的地址都可作为函数的返回值。

返回指针的函数,在字符串一小节和结构一章可看到实用的例题。这里借用一个无意义的例题说明概念。10.4.2指针作为函数返回值

例10-8返回局部变量的地址。#include<stdio.h>int*getint();/*指针函数*/voidmain() {int*p;p=getint();printf("p:%x(地址)%d(值)\n",p,*p);}/*返回局部变量的地址*/int*getint(){intvalue=20; /*局部变量*/printf("value:%x(地址)%d(值)\n",&value,value);return&value;/*警告错误!返回局部变量的地址*/}定义指针型函数的一般形式为:

类型说明符*函数名(形参表){……/*函数体*/}其中函数名之前加了“*”号表明这是一个指针型函数,即返回值是一个指针。类型说明符表示了返回的指针值所指向的数据类型。如:int*ap(intx,inty){…/*函数体*/}

10.4.3指针型函数

例10-9指针函数应用举例,输出对应的星期几。

voidmain(){inti;char*day_name(intn);printf("inputDayNo:\n");scanf("%d",&i);if(i<0)exit(1);printf("DayNo:%2d-->%s\n",i,day_name(i));}char*day_name(intn){staticchar*name[]={"Illegalday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};return((n<1||n>7)?name[0]:name[n]);}10.4.4函数指针变量指向函数的指针称为函数指针。函数指针是函数的入口地址。可用函数指针调用函数。函数指针也可作为函数的形参。函数指针的一般定义格式:类型名(*指针变量名)(); (无参数表)类型名(*指针变量名)(类型名表); (有参数表)类型名是指函数返回值的类型。调用函数的一般格式:(*指针变量名)(实参表);(*指针变量名)表示“*”后面的变量是定义的指针变量。最后的空括号表示指针变量所指的是一个函数。例如:int(*pf)();表示pf是一个指向函数入口的指针变量,该函数的返回值(函数值)是整型。

10.4.4函数指针变量例10-10求a和b中较大者,用函数指针实现。

#include<stdio.h>intmax(inta,intb){if(a>b)returna;elsereturnb;}voidmain(){intmax(inta,intb);int(*pmax)();intx,y,z;pmax=max;printf("inputtwonumbers:\n");scanf("%d%d",&x,&y);z=(*pmax)(x,y);printf("maxmum=%d",z);}10.5指针与字符串10.5.1

字符串表示方法字符指针初始化的方法有如下两种形式:在定义字符型指针时,可以用字符串常量初始化。例如:char*strp="VC++";字符串常量可以赋给字符型指针变量。例如:char*strp;strp="VC++";字符串表示方法例10-11通过字符指针输出一个字符串。#include<stdio.h>voidmain(){char*ps;ps="CLanguage";printf("%s",ps);}首先定义ps是一个字符指针变量,然后把字符串的首地址赋予ps(应写出整个字符串,以便编译系统把该串装入连续的一块内存单元),并把首地址送入ps。程序中的:char*ps;ps="CLanguage";等效于:char*ps="CLanguage";输出字符串中的所有字符。字符串表示方法例10-12在输入的字符串中查找有无'k'字符。#include<stdio.h>voidmain(){charst[20],*ps;inti;printf("inputastring:\n");ps=st;scanf("%s",ps);for(i=0;ps[i]!='\0';i++)if(ps[i]=='k'){printf("thereisa'k'inthestring\n");break;}if(ps[i]=='\0')printf("Thereisno'k'inthestring\n");}10.5.2字符串处理函数的实现1.求字符串长度函数原型unsignedintstrlen(constchar*s); unsignedintstrlen(constchar*s) { intlen=0; while(*s++)len++;

returnlen; }执行*s++表达式等价于:

*s 先取s指针所指向的字符。

s++ 再s指针加1,指向下一字符。2.字符串复制函数原型char*strcpy(char*dest,constchar*src);字符串复制是将原字符串src一个字符一个字符地复制到目标串dest,包含'\0'字符。最后返回指针temp,即返回dest原指针值。*dest++和*src++是左值表达式。执行*dest++=*src++表达式等价于:*dest=*src 先将指针src指向的字符复制到指针dest指向的存储单元。src++ src 指针加1,指向下一字符。dest++ des 指针加1,指向下一字符。注意,由于先执行赋值,然后src指针和des指针再加1,所以’\0’字符能复制。3.字符串连接

函数原型 char*strcat(char*dest,constchar*src);字符串连接是先将指针dest移到字符'\0'处,然后将src串复制到指针dest指向的存储单元。最后返回指针temp,即返回dest原指针。图7-12描述了字符串连接过程。

4.字符串比较

函数原型 int strcmp(constchar*s1,constchar*s2);两个字符串比较是对应字符一一比较。当两个字符不等或两个字符均为'\0'时,结束比较,返回*s1-*s2。当前两个字符的值决定了两个字符串比较关系与返回值:*s1==*s2,*s1=='\0',*s2=='\0' 串1==串2 返回值为0*s1>*s2

串1>串2 返回大于0*s1<*s2 串1<串2 返回小于0因此,函数strcmp的返回值能决定了两个字符串比

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论