模块5-指针及应用ppt课件

上传人:文**** 文档编号:240767561 上传时间:2024-05-06 格式:PPT 页数:183 大小:1.13MB
返回 下载 相关 举报
模块5-指针及应用ppt课件_第1页
第1页 / 共183页
模块5-指针及应用ppt课件_第2页
第2页 / 共183页
模块5-指针及应用ppt课件_第3页
第3页 / 共183页
点击查看更多>>
资源描述
实用实用C C语言程序设计教程语言程序设计教程李金祥李金祥 顾小晶顾小晶 主编主编实用C语言程序设计教程李金祥 顾小晶 主编Visual模块模块5 5 指针及应用指针及应用任务任务1 1 地址与指针地址与指针 学习目标学习目标 了解指针与地址的概念、掌握指针变量的定义、初始化及指针的运算。模块5 指针及应用案例一 指针与地址 1.1.问题描述问题描述 程序在计算机中运行的时候,所有数据都存放在内存中。而内存以字节为存储单元存放数据,不同的数据类型所占用的单元数不等。如整型占用2个单元,字符占用1个单元等。请编程验证计算机是如何存取需要的数据的。5.1.15.1.1案例讲解案例讲解5.1.1案例讲解2.2.编程分析编程分析 为了正确访问内存单元,计算机系统为每个内存单元进行编号,然后根据一个内存单元的编号准确地找到该内存单元。内存单元的编号也叫做地址。既然根据内存单元的地址就可以找到所需的内存单元,因此通常也把这个地址称为指针。要解决上面的问题,最好的办法是定义一组连续存储的变量,然后列出各变量的存储地址和值,从而得到它们的存储空间。2.编程分析 程序描述如下:main()定义字符型变量charA 定义整型变量intB 定义长整型变量longC,longD 输出charA的地址和值 输出intB的地址和值 输出longC、longD的地址和值 程序描述如下:3.3.编写源程序编写源程序 /*EX5_1.C*/#include main()char charA=A;int intB=1;long longC=2,longD=4;printf(charA的地址:%X,&charA);/*以十六进制形式输出charA的地址*/3.编写源程序 printf(charA的值:%cn,charA);printf(intB的地址:%X,&intB);printf(intB的值:%dn,intB);printf(longC的地址:%X,&longC);printf(longC的值:%dn,longC);printf(longD的地址:%X,&longD);printf(longD的值:%dn,longD);printf(charA的值:%cn,cha4.4.运行结果如图运行结果如图5-15-1所示。所示。图5-1案例1运行结果4.运行结果如图5-1所示。5.5.归纳分析归纳分析(1)系统根据变量的数据类型,分别为charA、intB、longC和longD分配1个、2个、4个和4个字节的存储单元,此时变量所占存储单元的第一个字节的地址就是该变量的地址。在图5-1中,变量charA的地址是12FF7C,intB的地址是12FF78,longC的地址是12FF74,longD的地址是12FF70。图5-2给出了案例1一次运行的内存存储示意。5.归纳分析图5-2 案例1内存存储示意图模块5-指针及应用ppt课件 (2)在C语言中通过“&”获得数据的地址,“&”称为取地址运算符。因此,案例1中的语句 printf(charA的地址:%x,&charA);的作用就是输出变量charA的地址。(3)通过变量名访问数据时,系统自动完成变量名与存储地址的转换,这种访问形式称为“直接访问”。此外,C语言中还有一种称为“间接访问”的形式。它首先将变量的存储地址存入另一个变量中,这个存放地址的变量称为指针变量,然后通过指针变量去访问先前的变量。这时,我们可以说指针变量指向那个变量。这种访问形式类似于打电话时的呼叫转移。printf(charA的地址:%x,&cha案例二 指针变量 1 1问题描述问题描述 从键盘输入a和b两个整数,按先大后小的顺序输出a和b。案例二 指针变量 2 2编程分析编程分析 从键盘输入a和b两个整数后最好不要改变它们本身的值,因为其它程序中可能还会使用到这些原始数据。比较好的做法是根据我们的需要给原始数据做上“标志”:将较大的数标识为pMax,较小的数标识为pMin。这样在输出时可以根据做好的标志来输出。这种形式类似于给别人取外号。程序描述如下:2编程分析 main()定义变量a、b 定义指针变量pMax、pMin、pTemp 从键盘输入两个整数给a、b 令pMax指向a、pMin指向b 如果pMax指向的值小于pMin指向的值,利用pTemp将pMax、pMin交换 输出a、b的值 输出pMax指向的值、pMin指向的值 main()3 3编写源程序编写源程序 /*EX5_2.C*/#include main()int a,b;int*pMax,*pMin,*pTemp;printf(请输入两个整数a,b:);scanf(%d,%d,&a,&b);pMax=&a;pMin=&b;if(*pMax*pMin)3编写源程序 pTemp=pMax;pMax=pMin;pMin=pTemp;printf(na=%d,b=%dn,a,b);printf(max=%d,min=%dn,*pMax,*pMin);pTemp=pMax;pMax=pMin4 4运行结果如图运行结果如图5-35-3所示。所示。图5-3案例2运行结果4运行结果如图5-3所示。5 5归纳分析归纳分析(1)严格地说,指针是一个地址,是一个常量。而用来存放地址的指针变量却可以被赋予不同的指针值,是变量。但有时也会把指针变量简称为指针。为了避免混淆,本书约定:“指针”是指地址,是常量,“指针变量”是指取值为地址的变量。定义指针变量的目的是为了通过指针变量去访问它所指向的内存单元。5归纳分析(2)定义指针变量包括三个内容:类型说明符、指针表识符和指针变量名。其中,类型说明符表示指针变量所指向数据的数据类型,指针表识符用“*”表示。其一般形式为:类型说明符*变量名;例如,案例2中语句“int*pMax,*pMin,*pTemp;”就表示定义三个指针:pMax,pMin和pTemp,它们的类型都是int类型,也就是说它们可以指向其他int类型的变量。(2)定义指针变量包括三个内容:类型说明符、指针表识符和指 再如:int*p1;/*p1是指向整型变量的指针变量*/float*p2;/*p2是指向浮点变量的指针变量*/char*p3;/*p3是指向字符变量的指针变量*/应该注意的是,一个指针变量只能指向同类型的变量,如p2 只能指向浮点变量,不能时而指向一个浮点型变量,时而又指向一个字符型变量。再如:(3)指针变量定义后要给它们赋值,使其指向某个变量。赋值的方式有两种:一种是通过取地址符将变量的地址赋给指针变量,如语句“pMax=&a;”就是将变量a的地址赋值给指针变量pMax;另一种赋值方式是把其他同类型的指针变量的值赋值过来,如语句“pTemp=pMax;”表示把pMax的值赋值给pTemp。此后,pMax、pTemp指向同一个存储地址。(3)指针变量定义后要给它们赋值,使其指向某个变量。赋值的(4)当一个指针变量指向某变量时,指针变量的值和指针变量的内容是两个不同的含义。指针变量的值表示它所指向的变量的地址,而指针变量的内容则表示所指向的变量的值。例如语句“pMax=&a;”执行后,pMax的值就是变量a的存储地址,pMax的内容就是变量a本身。C语言中通过“*”指针运算符来获得指针变量的内容。因此,要获得pMax的内容可以使用*pMax来得到。案例2中的“*pMax*pMin”语句就是判断pMax的内容是否小于pMin的内容。(4)当一个指针变量指向某变量时,指针变量的值和指针变量的 同样,程序最后的输出语句“printf(max=%d,min=%dn,*pMax,*pMin);”表示输出pMax和pMin的内容(指向的变量)。案例2执行时的内存存储示意图如图5-4所示。(a)程序初始化 (b)输入3,6后 同样,程序最后的输出语句“printf(max (c)执行完pMax=&a;(d)执行完p=pMax;pMax=pMin;pMin=&b;语句后 pMin=pTemp;语句后图5-4 案例2执行时内存存储示意图模块5-指针及应用ppt课件(5)ANSI新标准增加了一种“void”指针类型,即可以定义一个指针变量,但不指定它是指向哪一种类型数据。(6)当一个指针变量的值为0(或记为NULL)时,表示所指向的是空指针。(5)ANSI新标准增加了一种“void”指针类型,即可以1 1基本概念基本概念 变量的指针就是变量的地址。存放变量地址的变量是指针变量。即在语言中,允许用一个变量来存放指针,这种变量称为指针变量。因此,一个指针变量的值就是某个变量的地址或称为某变量的指针。定义5.1:数据所占存储单元的第一个字节的地址称为指针。5.1.2 5.1.2 基础理论基础理论5.1.2 基础理论 定义5.2:用来存放数据存储首地址的变量称为指针变量,指针变量的类型决定了每次存取的字节数 定义5.3:指针变量的值就是它所指向的变量的地址。定义5.4:指针变量的内容表示它所指向的变量。定义指针变量的一般形式为:类型说明符*变量名;定义5.2:用来存放数据存储首地址的变量称为指针 2.2.指针、指针变量的运算指针、指针变量的运算 指针变量可以进行某些运算,但其运算的种类是有限的。它只能进行赋值运算和部分算术运算及关系运算。(1)指针运算符 取地址运算符&取地址运算符&是单目运算符,其结合性为自右至左,功能是取变量的地址。在scanf函数及前面介绍指针变量赋值中,我们已经了解并使用了&运算符。2.指针、指针变量的运算 取内容运算符*取内容运算符*是单目运算符,其结合性为自右至左,用来表示指针变量所指的变量。在*运算符之后跟的变量必须是指针变量。需要注意的是指针运算符“*”和指针变量说明中的指针说明符“*”不是一回事。在指针变量说明中,“*”是类型说明符,表示其后的变量是指针类型。而表达式中出现的“*”则是一个运算符用以表示指针变量所指向的变量。取内容运算符*(2)指针变量的赋值运算 通过取地址符将变量的地址赋给指针变量。例如:int a,*pA;pA=&a;/*把整型变量a的地址赋予整型指针变量pA*/把一个指针变量的值赋予同类型的另一个指针变量。例如:int a,*pA=&a,*pB;(2)指针变量的赋值运算 pB=pA;/*把a的地址赋予指针变量pB*/由于pA、pB均为指向整型变量的指针变量,因此可以相互赋值。把数组的首地址赋予指向数组的指针变量。例如:int a5,*pA;pA=a;数组名表示数组的首地址,故可赋予指向数组的指针变量pA。由于数组第一个元素的地址也是整个数组的首地址,因此,也可写为:pB=pA;/*把a的地址赋予指针变量pB*pA=&a0;把字符串的首地址赋予指向字符类型的指针变量。例如:char*pc;pc=C Language;这里应说明的是并不是把整个字符串装入指针变量,而是把存放该字符串的字符数组的首地址装入指针变量。在后面还将详细介绍。把函数的入口地址赋予指向函数的指针变量。例如:int(*pf)();pf=f;/*f为函数名*/pA=&a0;(3)指针变量的加减算术运算 对于指向数组的指针变量,可以加上或减去一个整数n。设pA是指向数组a的指针变量(即pA指向a0),则pA+n表示把指针指向的当前位置(指向某数组元素)向后移动n个位置(即指向an)。指针变量的加减运算只能对数组指针变量进行,对指向其它类型变量的指针变量作加减运算是毫无意义的。注意:不能把一个数字直接赋值给指针变量。(3)指针变量的加减算术运算 例如下面的语句是错误的:int*p=2000;程序中给指针变量赋值时,前面不要加上“*”说明符。例如下面的语句是错误的:int a=1;int*p;*p=&a;取地址运算符&和取内容运算符*是一对逆操作,同时出现时可以相互抵消。例如:&*p就等同于p。因为p是指针变量,*p表示其指向的变量,&*p表示其指向的变量的地址,也就是p的值。例如下面的语句是错误的:【实验5.1.1】阅读下面的程序,然后思考问题。/*EX5_3.C*/#include main()int a,b;int*pointer_1,*pointer_2;a=100;b=10;pointer_1=&a;pointer_2=&b;5.1.3 5.1.3 技能训练技能训练 【实验5.1.1】阅读下面的程序,然后思考问题。printf(%d,%dn,a,b);printf(%d,%dn,*pointer_1,*pointer_2);问题1:程序中有两处出现*pointer_1和*pointer_2,请区分它们的不同含义。问题2:程序第5、6行的“pointer_1=&a;”和“pointer_2=&b;”能否写成“*pointer_1=&a;”和“*pointer_2=&b;”?问题3:如果已经执行了“pointer_1=&a;”语句,那么“&*pointer_1”的含义是什么?问题4:*&a的含义是什么?printf(%d,%dn,a,b)问题3:&*pointer_1可以写为&(*pointer_1),即取指针变量pointer_1指向变量的地址,等同于pointer_1。问题4:*&a可以写为*(&a),&a表示取变量a的地址,*(&a)表示取该地址中变量的值,等同于a。问题3:&*pointer_1可以写为&(*(2)在VC+集成环境中输入上述程序,文件存成EX5_3.C,如图5-5所示。图5-5 运行结果(2)在VC+集成环境中输入上述程序,文件存成EX5_3 【实验5.1.2】执行以下程序,写出运行结果。/*EX5_4.C*/#include main()int a,b,k=4,m=6,*p1=&k,*p2=&m;a=p1=&m;b=(*p1)/(*p2)+7;printf(a=%dn,a);printf(b=%dn,b);【实验5.1.2】执行以下程序,写出运行结果。(1)编程分析 程序执行完“int a,b,k=4,m=6,*p1=&k,*p2=&m;”语句后,为变量a、b、k、m,指针变量p1、p2分配内存空间,并赋初值4、6给变量k、m,使p1指向k,p2指向m。如图5-6。(1)编程分析图5-6 内存存储示意图模块5-指针及应用ppt课件 语句“a=p1=&m;”可以写为“a=(p1=&m);”,即取出变量m的地址与p1比较是否相等(也就是判断p1是否指向变量m),将比较结果(0或1)赋值给变量a。由于p1指向的是变量k而不是变量m,因此a的值为0。语句“b=(*p1)/(*p2)+7;”表示将指针变量p1指向的变量除以p2指向的变量后与7求和,结果存入变量b。该语句等同于“b=k/m+7;”,因此B的值为7。语句“a=p1=&m;”可以写为“a=(p1=(2)在VC+集成环境中输入上述程序,文件存成EX5_4.C,如图5-7所示。图5-7 运行结果(2)在VC+集成环境中输入上述程序,文件存成EX5_41编程规范编程规范 (1)定义指针变量时,*号既可以紧接类型,也可以在变量名之前。例如:int*pnsize;或 int*pnsize;但不要写做:int*pnSize;建议采用第二种形式。5.1.5 5.1.5 编程规范与常见错误编程规范与常见错误5.1.5 编程规范与常见错误(2)指针变量名必须具有一定的实际意义,形式为pxAbcFgh。p表示指针变量,x表示指针变量类型,Abc、Fgh表示连续有意义字符串,如int*pnSize;p表示是指针变量,n表示该指针变量可以指向整型数据,Size表示该指针变量的含义。(3)一般一次只声明一个变量和指针变量,否则就会让人混淆。比如:int*a,b;看起来b好像也是个指针,其实不是。(2)指针变量名必须具有一定的实际意义,形式为pxAbcF2.2.常见错误常见错误 (1)使用未初始化的指针 指针是C 语言中的一个重要概念,也是比较难掌握的一个概念。C 语言中指针是用于存放变量地址的。指针变量是C 语言中的一个特殊类型的变量。指针变量定义后应确定其指向。在没有确定指针的具体指向前,指针变量的内容是随机的地址,盲目地引用将十分危险。2.常见错误(2)指针变量所指向的变量类型与其定义的类型不符 定义指针变量的一般格式为:类型说明符*指针变量名;其中类型说明符规定的是指针变量所指向的变量的类型。C 语言规定一个指针变量只能指向同一类型的变量。(3)指针的错误赋值 指针变量的值是某个数据对象的地址,只允许取正的整数值。然而,千万不能将它与整数类型变量相混淆。指针赋值,在赋值号右边的应是变量地址且是所指变量的地址。(2)指针变量所指向的变量类型与其定义的类型不符任务任务2 2 指针与数组指针与数组 学习目标学习目标 掌握指针访问数组的方法,领会指针处理字符串的方法,了解指针数组、多级指针等概念。任务2 指针与数组 案例一 通过指针变量访问数组元素通过指针变量访问数组元素1.1.问题描述问题描述 已知2010年1月至12月的星期因子分别是4、0、0、3、5、1、3、6、2、4、0、2。通过2010年的日期与相应星期因子计算后可以得到当天是星期几。计算方法如下:week=(monthSet+day)%7,其中week表示星期数:0表示星期天、1表示星期一,;monthSet表示该月的星期因子;day表示第几天。5.2.1 5.2.1 案例讲解案例讲解案例一 通过指针变量访问数组元素5.2.1 案例讲解 例如,要知道2010年4月5日是星期几,只要将4月的星期因子3加上日期5,再与7取模,得1,表示该天是星期一。要求编写C语言程序,从键盘输入2010年的月份和日期,输出星期几。例如,要知道2010年4月5日是星期几,只要将4月2.2.编程分析编程分析 对于十二个月的星期因子,我们可以存放在一个一维数组中,然后根据用户输入的月份到数组中取出相应的星期因子进行计算。在C语言中,指针和数组之间的关系非常密切。如果使用数组下标形式访问数组元素,每次都要进行地址计算。例如,要访问a3,就要通过数组地址a加上3倍的数组元素大小得到a3地址才能访问。因此,可以考虑使用指针变量的形式来提高数组访问效率和程序灵活性。2.编程分析 程序描述如下:int main()定义数组保存12个月的星期因子 定义指针变量,并使指针变量指向数组 从键盘输入月份和日期,分别存入变量month和day 通过公式week=(monthSet+day)%7计算星期数 程序描述如下:3.3.编写源程序编写源程序 /*文件名:Ex5_5.C 根据星期因子计算2010年某天的星期数 程序暂不考虑用户输入日期的有效性*/#include main()int monthSet12=4,0,0,3,5,1,3,6,2,4,0,2;int month=0,day=0,week=0;int*pMonthSet=monthSet;3.编写源程序 printf(请输入月份1-12:);scanf(%d,&month);printf(n请输入日期1-31:);scanf(%d,&day);printf(n);week=(*(pMonthSet+month-1)+day)%7;if(week=0)printf(星期天n);else printf(星期%dn,week);printf(请输入月份1-12:);4.4.运行结果如图运行结果如图5-85-8所示。所示。图5-8 案例1运行结果4.运行结果如图5-8所示。图5-9 案例1数组存储示意图模块5-指针及应用ppt课件图5-10 指针变量指向数组模块5-指针及应用ppt课件案例二案例二 指向数组元素的指针变量指向数组元素的指针变量 1 1问题描述问题描述 要求使用指针实现将键盘输入的一维数组的元素打印出来。案例二 指向数组元素的指针变量 2.2.编程分析编程分析 定义数组后用一个指针变量指向数组首元素,然后通过循环接收键盘输入,存放在指针变量表示的地址中,每次循环指针变量下移一格。待输入完成后,再利用指针变量循环输出数组元素。程序描述如下:int main()定义数组及计数器 定义指针变量,并使指针变量指向数组2.编程分析 通过记数器控制循环:输入数据到指针变量 指向下一个数组元素 恢复指针变量使其重新指向数组 通过记数器控制循环:输出指针变量指向的元素 指向下一个数组元素 通过记数器控制循环:3.3.编写源程序编写源程序 /*文件名:Ex5_6.C*/#include main()int a10,i;int*p=a;printf(请输入十个整数:n);for(i=0;i10;i+)scanf(%d,p+);printf(输出:n);3.编写源程序 p=a;for(i=0;i10;i+)printf(%2d,*p+);printf(n);4.4.运行结果如图运行结果如图5-115-11所示。所示。图5-11 案例2运行结果 p=a;5.5.归纳分析归纳分析(1)由于p是指针变量,本身就表示地址,因此在使用scanf输入时可以直接使用。例如:“scanf(%d,p);”。案例2中采用了“scanf(%d,p+);”语句,表示将输入的数据存入p表示的地址中,然后将p指向下一个数组元素。在这里,“scanf(%d,p+);”语句也可以使用“scanf(%d,&ai+);”代替。5.归纳分析(2)使用指针变量时要注意它的当前值。例如,通过“scanf(%d,p+);”语句循环为数组赋值后,p已经超出了数组的存储范围,因此再次使用p输出数组元素时需要再次执行“p=a;”,使其重新指向数组首地址。(2)使用指针变量时要注意它的当前值。例如,通过“scan案例三案例三 使用指针变量访问二维数组使用指针变量访问二维数组 1 1问题描述问题描述 如果已知2010年至2015年的星期因子,同样可以利用公式week=(monthSet+day)%7求解。请编程实现。案例三 使用指针变量访问二维数组 表5-2 2010年至2015年的星期因子模块5-指针及应用ppt课件2.2.编程分析编程分析 在案例1中,对于2010年一年的星期因子,我们使用了一维数组来存储。在本例中我们可以使用二维数组来表示数据:每年的星期因子占一行,每行12列,共6行。这样,我们可以在程序中定义一个6行12列的数组monthSets612,对其初始化后,由用户输入年份数据转入相应行查找对应的星期因子,进行计算。程序描述如下:2.编程分析 main()定义数组monthSets612保存每年的星期因子 定义指针变量pMonthSets 从键盘输入年份、月份和日期,分别存入变量year、month和day 根据year移动指针 通过公式week=(monthSet+day)%7计算星期数 main()3.3.编写源程序编写源程序 /*文件名:Ex5_7.C 根据星期因子计算2010-2015年某天的星期数 程序暂不考虑用户输入日期的有效性*/#include main()int monthSets612=4,0,0,3,5,1,3,6,2,4,0,2,/*2010年星期因子*/5,1,1,4,6,2,4,0,3,5,1,3,/*2011年星期因子*/3.编写源程序 6,2,3,6,1,4,6,2,5,0,3,5,/*2012年星期因子*/1,4,4,0,2,5,0,3,6,1,4,6,/*2013年星期因子*/2,5,5,1,3,6,1,4,0,2,5,0,/*2014年星期因子*/3,6,6,2,4,0,2,5,1,3,6,1;/*2015年星期因子*/int year=0,month=0,day=0,week=0;int*pMonthSets;printf(请输入年份2010-2015:);scanf(%d,&year);printf(请输入月份1-12:);scanf(%d,&month);6,2,3,6,1,4,6,2,5,0,3,5,/*printf(n请输入日期1-31:);scanf(%d,&day);printf(n);pMonthSets=monthSets+year-2010;week=(*(pMonthSets+month-1)+day)%7;if(week=0)printf(星期天n);else printf(星期%dn,week);printf(n请输入日期1-31:);4.4.运行结果如图运行结果如图5-125-12所示。所示。图5-12 案例3运行结果4.运行结果如图5-12所示。5.5.归纳分析归纳分析(1)语言把一个二维数组看作是一维数组的集合,即二维数组是一个特殊的一维数组它的元素也是一个一维数组。因此数组monthSets可分解为六个一维数组,即monthSets 0,monthSets 1,monthSets 5。每一个一维数组又含有12个元素:monthSets 00monthSets 011,monthSets 10monthSets 111等。因此,程序中“int*pMonthSets=monthSets0;”语句表示指针变量pMonthSets指向数组的第0行。5.归纳分析(2)图5-13是该程序运行时数组monthSets的存储示意图,从图中我们可以看出:数组的名字表示数组monthSets的首地址,如果对其加1,则表示它的下一个元素地址,也就是monthSets1,即二维数组的第1行。程序中“pMonthSets=monthSets+year-2010;”语句将用户输入的年份减去2010得到偏移量,然后将数组首地址monthSets加上偏移量,使指针变量pMonthSets指向相应的行数组。例如,用户输入2012作为年份,2012减去2010得2,pMonthSets加上2表示第2行,因此pMonthSets=monthSets 2。(2)图5-13是该程序运行时数组monthSets的存储图5-13 案例3数组monthSets的存储示意图(3)对于二维数组monthSets的某一行,monthSetsi就是它所表示的一维数组的数组名,也就是这行一维数组的首地址(如图5-13)。如果对其加1,则表示这个一维数组的下一个元素模块5-指针及应用ppt课件 地址,也就是monthSetsi1。语句“week=(*(pMonthSets+month-1)+day)%7;”将用户输入的月份减去1得到星期因子的偏移量,然后与pMonthSets相加,得到相应元素的地址,通过“*”取出该地址的数据后进行计算。例如用户输入2012作为年份,2作为月份时,由前面的描述可知pMonthSets=monthSets 2,pMonthSets+2-1得到monthSets21元素的地址。因此*(pMonthSets+2-1)得到的就是数组monthSets21元素的值:2。地址,也就是monthSetsi1。语句“wee案例四 指向多维数组的指针变量 1 1问题描述问题描述 在C语言里,有一种指针变量是专门用来指向多维数组的,称为“指向多维数组的指针变量”。请使用这种指针变量来实现案例3。案例四 指向多维数组的指针变量 2.2.编程分析编程分析 我们可以通过 类型说明符(*指针变量名)指向的一维数组的个数的形式来定义一个指向二维数组的指针变量。这样,在对指针变量进行加减操作时,指针将在二维数组的行上移动。程序描述如下:2.编程分析 main()定义数组monthSets612保存每年的星期因子 定义指向二维数组的指针变量pMonthSets 从键盘输入年份、月份和日期,分别存入变量 year、month和day 根据year移动pMonthSets 通过公式week=(monthSet+day)%7计算星期数 main()3.3.编写源程序编写源程序 /*文件名:Ex5_8.C 通过指向二维数组的指针变量实现:根据星期因子计算2010-2015年某天的星期数 程序暂不考虑用户输入日期的有效性*/#include main()int monthSets612=4,0,0,3,5,1,3,6,2,4,0,2,/*2010年星期因子*/3.编写源程序 5,1,1,4,6,2,4,0,3,5,1,3,/*2011年星期因子*/6,2,3,6,1,4,6,2,5,0,3,5,/*2012年星期因子*/1,4,4,0,2,5,0,3,6,1,4,6,/*2013年星期因子*/2,5,5,1,3,6,1,4,0,2,5,0,/*2014年星期因子*/3,6,6,2,4,0,2,5,1,3,6,1;/*2015年星期因子*/int year=0,month=0,day=1,week=0;int(*pMonthSets)12;/*定义指向二维数组的指针变量*/pMonthSets=monthSets;printf(请输入年份2010-2015:);scanf(%d,&year);5,1,1,4,6,2,4,0,3,5,1,3,/*printf(请输入月份1-12:);scanf(%d,&month);printf(n请输入日期1-31:);scanf(%d,&day);printf(n);pMonthSets+=year-2010;week=(*(*pMonthSets+month-1)+day)%7;if(week=0)printf(星期天n);else printf(星期%dn,week);printf(请输入月份1-12:);4.4.运行结果如图运行结果如图5-145-14所示。所示。图5-14 案例4运行结果4.运行结果如图5-14所示。5.5.归纳分析归纳分析(1)指向二维数组的指针变量定义方法为:类型说明符(*指针变量名)指向的一维数组的个数;程序中通过“int(*pMonthSets)12;”语句定义了一个可以指向二维数组的指针变量pMonthSets,这个二维数组每行拥有12列数据。5.归纳分析(2)语句“pMonthSets=monthSets;”使指针变量pMonthSets指向二维数组monthSets的首行。以后对pMonthSets加1就是下移一行,减1就是上移一行。(3)如果要访问指针变量所指向的一维数组的内容时,要先用“*指针变量名”得到该行的首地址,然后加减偏移量得到元素所在地址,最后再通过“*”取出内容。因此语句一般类似于:“*(*指针变量名 偏移量)”。例如,程序中的“*(*pMonthSets+month-1)”。(2)语句“pMonthSets=monthSets;”使案例五 指针数组 1 1问题描述问题描述 指针变量也是一种数据类型。因此可以将一组同一类型的指针变量放在一起,定义为数组。这种由指针变量构成的数组称为指针数组。请使用指针数组实现案例3。案例五 指针数组 2.2.编程分析编程分析 前面的描述中,我们知道二维数组是由一组一维数组组成的,每个一维数组都有其首地址,也就是二维数组每行的行地址。因此,我们可以定义一个指针数组来分别指向二维数组中的行地址,实现对数组元素的访问。程序描述如下:main()定义数组monthSets612保存每年的星期因子2.编程分析 定义指针数组的变量monthSetsRow 将monthSets每行的行地址赋值给指针数组monthSetsRow的元素 从键盘输入年份、月份和日期,分别存入变量year、month和day 根据year获得monthSetsRow中对应行的地址 通过公式week=(monthSet+day)%7计算星期数 定义指针数组的变量monthSetsRow3.3.编写源程序编写源程序 /*文件名:Ex5_9.C 通过指针数组实现:根据星期因子计算2010-2015年某天的星期数 程序暂不考虑用户输入日期的有效性*/#include main()int monthSets612=4,0,0,3,5,1,3,6,2,4,0,2,/*2010年星期因子*/3.编写源程序 5,1,1,4,6,2,4,0,3,5,1,3,/*2011年星期因子*/6,2,3,6,1,4,6,2,5,0,3,5,/*2012年星期因子*/1,4,4,0,2,5,0,3,6,1,4,6,/*2013年星期因子*/2,5,5,1,3,6,1,4,0,2,5,0,/*2014年星期因子*/3,6,6,2,4,0,2,5,1,3,6,1;/*2015年星期因子*/int year=2012,month=2,day=1,week=0,i;int*monthSetsRow6;for(i=0;i6;i+)monthSetsRowi=monthSetsi;printf(请输入年份2010-2015:);scanf(%d,&year);5,1,1,4,6,2,4,0,3,5,1,3,/*printf(请输入月份1-12:);scanf(%d,&month);printf(n请输入日期1-31:);scanf(%d,&day);printf(n);week=(*(monthSetsRowyear-2010+month-1)+day)%7;if(week=0)printf(星期天n);else printf(星期%dn,week);printf(请输入月份1-12:);4.4.运行结果如图运行结果如图5-155-15所示。所示。图5-15 案例5运行结果4.运行结果如图5-15所示。5.5.归纳分析归纳分析(1)指针数组是一组有序的指针的集合。指针数组的所有元素都必须是具有相同存储类型和指向相同数据类型的指针变量。定义指针数组的一般形式为:类型说明符*数组名数组长度;其中类型说明符为指针值所指向的变量的类型。例如:int*monthSetsRow6;表示monthSetsRow是一个指针数组,它有6个数组元素,每个元素值都是一个指针,指向整型变量。5.归纳分析(2)应该注意指针数组和二维数组指针变量的区别。这两者虽然都可用来表示二维数组,但是其表示方法和意义是不同的。例如:int(*p)3;表示一个指向二维数组的指针变量。该二维数组的列数为3,或者说分解为一维数组的长度为3。int*p3;表示p是一个指针数组,有三个下标变量p0,p1,p2均为指针变量。(2)应该注意指针数组和二维数组指针变量的区别。这两者虽然案例六 使用指针变量处理字符串 1 1问题描述问题描述 用户在输入用户名和密码时,如果输入一些特殊符号可能会影响系统安全。因此需要将用户输入的用户名和密码进行字符替换,将危险字符替换掉。请编写程序实现将字符串中的“”全部替换为字母“A”。案例六 使用指针变量处理字符串 2.2.编程分析编程分析 C语言中字符串是通过一维字符数组来存储的,它的结束符为0。因此我们可以使用指针变量指向字符串(一维字符数组),循环检测每个字符直道结束(等于0)为止。程序描述如下:2.编程分析 main()用户输入字符串存入字符数组str 定义指向字符的指针变量pStr,并使pStr指向数组str 如果pStr的内容不等于0做循环:如果pStr的内容等于,替换为A pStr下移一个元素 输出替换后的字符串 main()3.3.编写源程序编写源程序 /*文件名:Ex5_10.C 将字符串中的全部替换为字母A。*/#include main()char str20;char*pStr=str;puts(请输入字符串:);gets(str);3.编写源程序 while(*pStr!=0)if(*pStr=)*pStr=A;pStr+;puts(str);while(*pStr!=0)4.4.运行结果如图运行结果如图5-165-16所示。所示。图5-16 案例6运行结果4.运行结果如图5-16所示。5.5.归纳分析归纳分析(1)C语言中字符串是通过一维字符数组来存储的,它的结束符为0。因此对字符串中字符的引用也可以用指针来表示。(2)如果定义字符串时采用char*str=”hello”;语句时,虽然没用显式地定义字符数组,但实际上还是在内存中开辟了一个连续区域存放字符串。5.归纳分析(3)虽然字符串是通过一维字符数组来存储的,但是定义时不能写为:char st20;st=C Language;而只能对字符数组的各元素逐个赋值。这也可看出使用指针变量更加方便。(3)虽然字符串是通过一维字符数组来存储的,但是定义时不能案例七 main函数的参数 1 1问题描述问题描述 语言规定main函数的参数只能有两个,习惯上这两个参数写为argc和argv。请使用main函数参数实现案例6的功能。案例七 main函数的参数 2.2.编程分析编程分析 语言规定argc必须是整型变量,argv必须是指向字符串的指针数组。加上形参说明后,main函数的函数头应写为:main(int argc,char*argv)main函数的参数值是从操作系统命令行上获得的。当我们要运行一个可执行文件时,在DOS提示符下键入文件名,再输入实际参数即可把这些实参传送到main的形参中去。2.编程分析 DOS提示符下命令行的一般形式为:C:可执行文件名 参数1 参数2 命令执行时,会将可执行文件名、参数1、参数2等作为字符串,并将其地址按次序传递给argv指针数组,将字符串的个数传递给argc。因此,程序可以描述为:main()定义指向字符的指针变量pStr DOS提示符下命令行的一般形式为:检测命令行参数是否存在 使pStr指向命令行参数 如果pStr的内容不等于0做循环:如果pStr的内容等于,替换为A pStr下移一个元素 输出替换后的字符串 检测命令行参数是否存在3.3.编写源程序编写源程序 /*文件名:Ex5_11.C 使用main参数实现:将字符串中的全部替换为字母A。*/#include main(int argc,char*argv)char*pStr;if(argc!=2)printf(使用方法:输入程序名 字符串n);3.编写源程序 pStr=argv1;while(*pStr!=0)if(*pStr=)*pStr=A;pStr+;printf(%sn,argv1);4.4.程序运行方法程序运行方法在VC环境中右键单击项目名,选择“settings”图5-17 案例7步骤一4.程序运行方法在弹出的窗口中选择“Debug”,在“program arguments”中输入命令行参数,例如“asdfgh123”,点击“OK”:在弹出的窗口中选择“Debug”,在“program ar程序输出结果如图5-19所示。图5-19 案例7运行结果模块5-指针及应用ppt课件5.5.归纳分析归纳分析 程序执行时输入Ex5_2_7 12345678后,argc等于2,argv0指向字符串“Ex5_2_7”,argv0 指向字符串“12345678”。5.归纳分析1 1通过指针变量访问一维数组元素通过指针变量访问一维数组元素 一维数组的数组名表示该数组的首地址,它是一个常量。如果在其基础上加上一个偏移量i,就表示向下第i个元素的地址。因此,在程序中定义一个指针变量使其指向数组首地址,然后对该指针变量进行加减运算,使其指向需要的数组元素,进行读写访问。根据以上叙述,引用一个数组元素可以用:5.2.2 5.2.2 基础理论基础理论5.2.2 基础理论(1)下标法,即用ai形式访问数组元素。在前面介绍数组时都是采用这种方法。(2)指针法,即采用*(p+i)形式,用间接访问的方法来访问数组元素,其中p是指向数组的指针变量,其初值p=a。定义指向数组元素的指针变量形式与定义指向变量的指针变量相同,如:int a10;int*p;p=a;/*或 p=&a0;*/(1)下标法,即用ai形式访问数组元素。在前面介绍数组 这里应当注意指向数组元素的指针变量的类型必须要和数组类型保持一致。其中p和a有相同作用,只是a是常量,p是变量。执行了p=a后:(1)p+i和a+i就是ai的地址;(2)*(p+i)或*(a+i)都表示指向ai;这里应当注意指向数组元素的指针变量的类型必须要和2.2.使用指针变量访问二维数组使用指针变量访问二维数组 二维数组是若干个相同大小的一维数组的集合。二维数组的每一行都表示一个一维数组。因此二维数组中存在三类地址:数组首地址a、行地址ai和元素地址&aij。特别的,对于数组首行地址a0,它的值与数组首地址相同,但含义不同,对它们进行加减运算的结果也不相同。例如:int a34;int*p1=a+1;int*p2=a0+1;2.使用指针变量访问二维数组 执行后,p1指向数组a1行,而p2指向元素a01。因为对于a来说,它是由a0、a1、a2三个行地址组成的一维数组的首地址,因此a+1表示在这个一维数组中下移一个元素:由指向a0变为指向a1。而a0是二维数组首行指向的一维数组的首地址,因此对它加1表示在这个行数组中下移一个元素:由指向a00变为指向a01。执行后,p1指向数组a1行,而p2指向元素a3.3.指向多维数组的指针变量指向多维数组的指针变量 在C语言里,有一种指针变量是专门用来指向多维数组的,称为“指向多维数组的指针变量”。我们可以通过“类型说明符(*指针变量名)指向的一维数组的个数”的形式来定义一个指向二维数组的指针变量。这样,在对指针变量进行加减操作时,指针将在二维数组的行上移动。3.指向多维数组的指针变量 4.4.指针数组指针数组 数组元素是同一类型指针变量的数组称为指针数组。与二维字符数组相比,指针数组用于处理多个字符串更方便。如果使用二维字符数组处理多个字符串,由于数组的列数是相同的,因此会造成存储空间的浪费,而用指针数组就不存在这样的问题。如图5-20:4.指针数组 (a)二维字符数组表示模块5-指针及应用ppt课件(b)指针数组表示图5-20 多字符串表示形式比较模块5-指针及应用ppt课件 学习时要注意“指向多维数组的指针变量”和“指针数组”的差别:“指向多维数组的指针变量”是一个指针变量,它能够指向数组,而“指针数组”是一个数组,它的元素是某一类型的指针。因此它们在定义、使用时都不一样。学习时要注意“指向多维数组的指针变量”和“指针数5.5.使用指针变量处理字符串使用指针变量处理字符串 字符串在内存中是以字符数组的形式存储的,因此所有对数组适用的技术都可以应用到字符串上。使用时要注意两点:(1)字符串可以看作是一个字符数组,因此使用指针变量处理字符串的时候,指针变量的类型要定义为char型;(2)字符串以0结尾。因此可以通过当前指针变量的内容是否等于0来判断字符串是否结束。5.使用指针变量处理字符串 6.main6.main函数的参数函数的参数 main函数的参数值是从操作系统命令行上获得的。它的参数有两个:整型的argc和指针数组argv。argc记录了argv数组的元素个数,argv以指向字符串的指针数组形式保存了命令行中输入的文件名和参数列表。在输入命令时文件名、参数列表都以空格作为分隔符。argv0指向文件名,argv1至argvargc-1分别指向参数1至参数n。6.main函数的参数 7.7.指向指针的指针指向指针的指针 由于指针变量也有地址,因此它也可以被其他指针变量指向。如果一个指针变量存放的是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量。定义一个指向指针的指针变量的语法为:类型说明符*指针变量名;在前面已经介绍过,通过指针访问变量称为间接访问。由于指针变量直接指向变量,所以称为“单级间址”。而如果通过指向指针的指针7.指向指针的指针 变量来访问变量则构成“二级间址”。例如:int a=4;int*p1=&a;int*p2=&p1;p1是一个指向整形变量a的指针变量,p2是一个指向p1的指针变量,如图5-21所示:变量来访问变量则构成“二级间址”。例如:图5-21 内存示意图模块5-指针及应用ppt课件1使用指针变量访问数组元素可以提高程序使用指针变量访问数组元素可以提高程序效率和灵活性,但是使用时要注意两点:效率和灵活性,但是使用时要注意两点:(1)要注意当前指针变量的值。指针变量的值是一个动态值,需要根据程序运行来分析。(2)要注意不能超过数组范围。指针在移动时,如果不注意限制条件,可能会超出数组的存储范围,从而访问到程序其他的数据或指令,这是非常危险的。在软件中有一种漏洞称为“缓冲区溢出”就是利用指针变量改写了数组以外的数据。5.2.5 5.2.5 编程规范与常见错误编程规范与常见错误1使用指针变量访问数组元素可以提高程序效率和灵活性,但是使2 2数组名是一个地址常量,不能自增自减,也数组名是一个地址常量,不能自增自减,也不能在赋值语句中作左值。不能在赋值语句中作左值。2数组名是一个地址常量,不能自增自减,也不能在赋值语句中作任务任务3 3 指针与函数指针与函数 学习目标学习目标 了解指针与函数的概念、掌握指针作为函数参数的应用。任务3 指针与函数 案例一 指针作为函数参数函数参数 1.1.问题描述问题描述 将两个整数放到变量a、b中,编写函数交换这两个变量。5.3.1 5.3.1 案例讲解案例讲解5.3.1 案例讲解2.2.编程分析编程分析 如果我们直接使用普通的变量传递形式来编写如下代码:int swap(int p,int q)int temp=p;p=q;q=temp;2.编程分析 函数写到这里就没法写下去了,因为C语言的函数只能有一个返回值,我们返回了p,就不能返回q,同样,返回了q就不能返回p。而如果不返回,函数执行后p、q的值是不会变化的。如:void swap(int p,int q)int temp=p;p=q;q=temp;函数写到这里就没法写下去了,因为C语言的函数只能 main()int a=4,b=6;swap(a,b);printf(a=%d,b=%d,a,b);执行后输出:a=4,b=6 这是因为C语言中函数参数的传递是值传递,形参和实参存放在不同的内存空间,形参的变化不会影响实参的值,如图5-25所示。main()图5-25 形参和实参存储示意图模块5-指针及应用ppt课件 可以看到,问题的关键在于形参和实参的存储空间不同。形参只不过是实参的一个影子。所以解决问题的一个方法就是使它们的数据的存储空间一致。很自然地,我们可以想到指针变量保存的是变量的地址,如果我们将变量的地址传给形参,使形参也指向变量存储的空间,那么问题就迎刃而解了。所以我们需要定义一个使用指针变量作为参数的方法,然后将变量地址传递给函数。可以看到,问题的关键在于形参和实参的存储空间不同3.3.编写源程序编写源程序 /*文件名:Ex5_17.C*/void swap(int*p,int*q)int temp=*p;*p=*q;*q=temp;main()int a=4,b=6;swap(&a,&b);printf(a=%d,b=%dn,a,b);3.编写源程序4.4.程序运行结果如图程序运行结果如图5-265-26所示。所示。图5-26 案例1运行结果4.程序运行结果如图5-26所示。5.5.归纳分析归纳分析(1)程序使用“swap(&a,&b);”将变量a的地址传递给形参p,使其也指向变量a。如图5-27(a)所示。(2)在函数swap中,通过临时变量temp实现p所指向的内容与q所指向的内容互换。如图5-27(b)所示。(3)函数swap结束后,形参被释放,但是此时变量a、b的值已经是修改过的了。如图5-27(c)所示。5.归纳分析(a)(b)(c)图5-27案例1程序执行示意图模块5-指针及应用ppt课件案例二 数组作为函数参数函数参数1 1问题描述问题描述 试编写函数将一维数组元素反置。2.2.编程分析编程分析 将数组作为函数参数传入,将a0与an-1对换,再a1与an-2 对换,直到将a(n-1/2)与an-int(n-1)/2)对换。程序描述如下:void inv(int a,int n)/*形参a是数组名*/定义指针变量p1指向数组首地址案例二 数组作为函数参数 定义指针变量p2指向数组末地址 循环执行:p1、p2的内容互换 p1下移一格 p2上移一格 直到数组长度的1/2为止 定义指针变量p2指向数组末地址3.3.编写源程序编写源程序 /*文件名:
展开阅读全文
相关资源
  • (通用版)高考地理一轮复习 第一部分 地理基础必备 课时跟踪检测(二)等高线地形图和地形剖面图-人教版高三地理试题(通用版)高考地理一轮复习 第一部分 地理基础必备 课时跟踪检测(二)等高线地形图和地形剖面图-人教版高三地理试题
  • (通用版)高考地理一轮复习 第一部分 地理基础必备 课时跟踪检测(一)经纬网与地图-人教版高三地理试题(通用版)高考地理一轮复习 第一部分 地理基础必备 课时跟踪检测(一)经纬网与地图-人教版高三地理试题
  • (通用版)高考化学二轮复习 第1部分 核心突破 专题1 基本概念 第2讲 化学常用计量对点规范训练-人教版高三化学试题(通用版)高考化学二轮复习 第1部分 核心突破 专题1 基本概念 第2讲 化学常用计量对点规范训练-人教版高三化学试题
  • (通用版)高三语文一轮复习 特色训练110 常考易错成语分类练(易褒贬误用Ⅰ)-人教版高三语文试题(通用版)高三语文一轮复习 特色训练110 常考易错成语分类练(易褒贬误用Ⅰ)-人教版高三语文试题
  • (通用版)高考历史大一轮复习 第十单元 世界资本主义经济政策的调整和苏联的社会主义建设单元过关检测(含解析)-人教版高三历史试题(通用版)高考历史大一轮复习 第十单元 世界资本主义经济政策的调整和苏联的社会主义建设单元过关检测(含解析)-人教版高三历史试题
  • (通用版)高二语文 第1章 1.4《老子》选读暑假作业(含解析)-人教版高二语文试题(通用版)高二语文 第1章 1.4《老子》选读暑假作业(含解析)-人教版高二语文试题
  • (通用版)高考历史二轮复习 板块四 从地中海沿岸的早期辉煌到开放扩张中的工业文明 课时达标检测(十)工业文明的曙光——近代前期的世界-人教版高三历史试题(通用版)高考历史二轮复习 板块四 从地中海沿岸的早期辉煌到开放扩张中的工业文明 课时达标检测(十)工业文明的曙光——近代前期的世界-人教版高三历史试题
  • (通用版)高三语文一轮复习 特色训练32 120个文言实词归纳串记练(少、涉、胜、识、使、是)-人教版高三语文试题(通用版)高三语文一轮复习 特色训练32 120个文言实词归纳串记练(少、涉、胜、识、使、是)-人教版高三语文试题
  • (通用版)高考化学一轮复习 跟踪检测(七)镁、铝及其化合物(含解析)-人教版高三化学试题(通用版)高考化学一轮复习 跟踪检测(七)镁、铝及其化合物(含解析)-人教版高三化学试题
  • (通用版)高考化学二轮复习 第二部分 策略一 考题研究 突破6种热考题型 4 以无机化工生产流程为情景的综合应用规范训练-人教版高三化学试题(通用版)高考化学二轮复习 第二部分 策略一 考题研究 突破6种热考题型 4 以无机化工生产流程为情景的综合应用规范训练-人教版高三化学试题
  • 相关搜索

    最新文档


    当前位置:首页 > 办公文档 > 教学培训


    copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

    备案号:ICP2024067431-1 川公网安备51140202000466号


    本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!