(19)--第09章C语言程序设计指针.ppt

上传人:奉*** 文档编号:96320845 上传时间:2023-11-02 格式:PPT 页数:85 大小:567.04KB
返回 下载 相关 举报
(19)--第09章C语言程序设计指针.ppt_第1页
第1页 / 共85页
(19)--第09章C语言程序设计指针.ppt_第2页
第2页 / 共85页
点击查看更多>>
资源描述

《(19)--第09章C语言程序设计指针.ppt》由会员分享,可在线阅读,更多相关《(19)--第09章C语言程序设计指针.ppt(85页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。

1、第9章 指针本章内容9.1 动态数组9.2 查找单科成绩状元9.3 查找班级成绩总分第一名9.4 演讲稿的保存9.5 函数指针和指针函数本章学习目标掌握指针的定义与引用掌握数组与指针的关系掌握参数为指针的函数的用法掌握动态内存分配和释放的方法了解多维数组的指针运算具有运用指针解决复杂问题的能力学习导引指针是语言中广泛使用的一种数据类型。运用指针编程是语言的重要手段之一。利用指针变量可以很方便地使用数组和字符串;指针能够使函数得到多个返回值;指针使C能象汇编语言一样处理内存地址,从而编出精练而高效的程序。能否正确理解和使用指针是精通语言的一个标志。9.1动态数组例9.1 从键盘输入数组的大小n,

2、并输入n个整数值,打印输出该n个数值的平均值。在C语言中,要想实现从键盘输入数组的大小n,创建数组,需要用到内存申请函数,从而设计出按照用户的需要来构建数组,这就是动态数组。库函数calloc:向系统申请存放n个元素的连续存储空间,如果成功则返回该存储空间的首地址,如果申请不成功,返回NULL值。申请成功后的存储空间可以当做一个数组使用。源程序9.1.1指针的概念 在上述例子中,定义了一个指针变量p,用来保存申请的内存首地址。int*p;指针是什么?指针就是地址,是一段内存空间的首地址。指针变量是什么?保存地址的变量。变量的三要素名字(不能变)值(能变)地址(不能变)怎么取变量 i 的地址?&

3、i怎么表示指针变量p中保存了整型变量i的首地址?int i,*p;p=&i;指针变量p指向i指针变量的三要素名字(不能变)地址(不能变)值(能变)指针变量的值是一个首地址,该要素能变,说明指针变量可以改变指向,可以在不同时刻指向不同的地址指针的分类:保存普通变量的地址:变量的指针保存另外一个指针变量的地址:指针变量的指针保存字符串的地址:字符串的指针保存数组元素的地址:数组元素的指针保存数组的地址:数组的指针保存结构体的地址:结构体的指针保存某个函数的地址:函数的指针9.1.2指针变量的定义指针变量的定义格式为:数据类型符 *变量名;数据类型符:指针变量所指向变量的数据类型,它决定了该指针指向

4、的内存单元有多少个字节,它给出了指针确切的含义。符号*表示其后定义的变量是一个指针变量,它可以与指针变量名连在一起,也可以分开,甚至连接到数据类型符后面。9.1.2指针变量的定义例如:int*p1;int*p2,i;float*p3,*p4;static char*p5;9.1.3指针变量的赋值 指针变量定义后,指针变量的值是不确定的,在早期的操作系统,如果使用可能造成系统的混乱,甚至系统的崩溃;现代的操作系统安全性更高,访问非法地址时会被操作系统中止。所以指针变量在使用之前必须赋值。1.指针变量使用前必须保证其指向了一个正确的地址#include int main()int*ip;/*未初始

5、化*/printf(%d,*ip);return 0;空指针NULL意义:指针变量赋值为0或NULL,表示指针不指向任何对象,经常称为空指针或零指针。NULL是在stdio.h中定义的符号常量。空指针通常有两种用途:一是避免指针变量的随意指向,二是在链表中表示空链或者已经到链表的尾部。但要记住:不能用空指针去访问内存。2.变量的地址赋值给指针变量 指针变量可以由变量的地址赋值,要求该变量的数据类型必须与指针变量的数据类型相同。3.相同数据类型的指针变量相互赋值例如:int i=10,j=20;int*p1,*p2;p1=&i;p2=&j;p2=p1;4.指针变量的强制类型转换 原则上,不要去使

6、用强制类型转化一个指针,除非你能确定内存中数据经过强制类型转化还是有意义的。在使用指针变量强制类型转换时,要注意以下两点:(1)强制类型转换的指针应该指向一个合法的地址。(2)强制类型转换后,要确定指针是指向内存中的一个有意义的数据。9.1.4指针变量的引用 当一个指针变量指向一个变量后,程序就可以通过这个指针变量间接引用指向变量的值,或者通过指针变量对指向的变量赋值。C语言提供了指针运算符 *,用来访问指针变量所指向的变量,指针运算符是单目运算符,具有右结合性,优先级与+、-相同。例9.2 指针变量的值与地址 源程序程序运行结果表明:(1)指针变量本身的地址在运行过程中是不变的。(2)指针变

7、量的值就是该指针指向的变量的地址,在运行过程中,指针变量的值是可以变的。(3)*指针运算符是求取指针指向的变量的值。(4)运算符&和*是相互反向,*&washinPrice就是washinPrice;&*p就是p,但此时p应该是指针,如果不是指针,则是语法错误。9.1.5指针变量作为函数参数 函数的参数不仅可以是整型、实型、字符型等数据类型,还可以是指针类型。当用指针做为函数的参数时,实参到形参传递的就是指针的值。例9.3 从键盘输入两个整数a和b,试设计一个函数实现a和b的值交换。C语言中,函数形参与实参之间是采用值传递的方式进行数据传送的,如果采用普通变量作为函数的参数,函数执行结束后,形

8、参改变而实参的值并不会发生改变,因为实参与形参占居不同的内存单元。要想在函数内部改变实参的值,就必须把实参的地址传送给形参,使实参与形参共享一段存储空间,故需要用地址作为参数才可以达到这个效果。#include void swap(int*pa,int*pb)int temp;temp=*pa;*pa=*pb;*pb=temp;int main()int a,b;int*pointer_1,*pointer_2;printf(请输入两个数a b:n);scanf(%d%d,&a,&b);pointer_1=&a;pointer_2=&b;swap(pointer_1,pointer_2);pr

9、intf(n%d,%dn,a,b);return 0;同一内存同一内存其他错误的SWAP函数设计(1)void swap(int*pa,int*pb)int*temp;*temp=*pa;/*temp没有初始化,那该赋值语句是对哪个内存单元赋值?*/*pa=*pb;*pb=*temp;其他错误的SWAP函数设计(2)如果swap不采用指针为参数:void swap(int x,int y)int temp;temp=x;x=y;y=temp;其他错误的SWAP函数设计(3)如果主函数不变,swap函数如下定义:void swap(int*pa,int*pb)int*p;p=pa;pa=pb;p

10、b=p;例9.4 某同学在设计学生成绩管理系统的时候,为了测试的方便,需要随机产生一个班的成绩。该同学设计一个数组用来存放成绩,每个班的学生人数为N。请你帮该同学设计一个函数produce(int*p,int n)实现随机产生n个成绩,存放在p指向的数组中。用当前时间作为随机种子,用rand()函数可以产生随机测试成绩。void produce(int*p,int n)int i,score;srand(unsigned)time(NULL);for(i=0;in;i+)score=rand()%61+40;/*产生40-100分的成绩*/pi=score;源程序9.1.6动态存储管理 动态存

11、储管理是指程序在执行过程中,根据程序的需要来分配一定大小的连续存储单元,用指针变量指向所分配存储单元的起始地址,并通过指针进行管理。常用的动态分配函数有两种calloc和malloc,另外还有释放指针指向的动态分配的存储单元free函数。这三个函数的函数原型都在stdlib.h头文件中。1.函数 calloccalloc函数用于给若干个同类型的数据项分配连续的存储空间,函数的原型为:void*calloc(unsigned int num,unsigned int size);如果函数能够成功申请到num项长度为size大小的连续存储空间,则函数的返回值为该存储空间的起始地址;如果申请失败,则

12、函数返回NULL空指针。例9.5 从键盘输入一个班的人数n,动态申请n个整数类型的存储空间用来存放n个同学的成绩,并显示其存储单元的缺省值。核心伪代码:读入 na=(int*)calloc(n,sizeof(int);if(a!=NULL)显示 a 为起始地址的 n 个int 型数据 free(a);else printf(内存不足n);return 1;源代码calloc函数的返回值类型为void指针类型,需要(int*)类型的转换。2.函数mallocmalloc函数用于向系统申请若干字节的存储空间,函数的原型为:void*malloc(unsigned int size);如果函数能够成

13、功申请到字节数为size大小的连续存储空间,则函数的返回值为该存储空间的起始地址;如果申请失败,则函数返回NULL空指针。用malloc函数重新实现例9.5。calloc和malloc函数的功能相同,区别是calloc动态申请的存储区域用0初始化,而malloc动态申请的存储空间的值是随机的。3.函数free 在C语言中,动态申请的存储空间,在程序执行结束后不会自动归还给系统。所以,C语言提供了一个free函数,用来释放动态申请的存储空间。free函数原型为:void free(void*ptr);函数free(ptr)调用结束后,ptr需要赋值为NULL,以防被误用。9.2 查找单科成绩状元

14、例9.6 编写函数实现某班一门课程的成绩输入,找出最高分并输出状元的学号和成绩分析:班级人数通常是不确定的,可以采用动态数组的方式来保存学号与分数。动态数组的地址分别保存在指针变量num和score中。同一个学生的学号和成绩分别存储在下标相同的两个数组中。(1)设计输入函数 为了避免在程序运行过程中手工输入大量数据,设计一个初始化函数init,专门用来自动填入该班所有学生的学号与成绩。(2)设计函数findmax,求出数组score中的最大值所在的下标。(3)设计函数display,依次显示每位同学的学号与成绩。(4)在主程序中打印出单科状元的学号与成绩。源程序 在本例中采用了findmax函

15、数采用数组做参数,display函数与init函数采用指针做参数。主函数调用时,实参向形参传递的是动态数组的首地址。调用函数后,形参的值是动态数组的首地址,即实参与形参共享了数组空间。在定义函数时,形参既可以用数组的方式,也可以用指针的方式,它们都是接收实参传给来的地址,效果是一样的。但要注意的是函数在声明时要与定义时采用的方式一致。9.2.1数组指针 数组名是该存储区域的首地址,也可以称为常指针。数组名也就是一维数组的第一个元素的地址。指针的数据类型就是数据元素的数据类型,数组指针就是数组第一个元素的地址。例如:int score=91,93,85,97,79;int*p;/*定义p为指向整

16、型变量的指针*/p=&score 0;p=score;等效 p和score都指向了数组所占存储区域的首地址,实际上为指向数组首元素的指针。通过指针p和score都可以访问数组的所有元素,常常称指向数组首个元素的指针为数组指针。9.2.2指针和地址运算1.指针变量的加、减运算 指针的加减运算,不是算术上的加减运算,而是针对地址的特殊运算。对于指针变量p和整数n的运算来讲,pn运算后的值为pn*sizeof(*p)的无符号整数的算术运算,其含义是指针指向的存储单元上下的第n个变量例9.7 利用指针运算的方式输出成绩数组中的所有成绩。#include#define N 5int main()int

17、scoreN=91,93,85,97,79;int*p,i;p=score;printf(成绩如下:n);for(i=0;ip2表示p1是否比p2地址大,如果在数组中,是否为高地址位置;(4)p1p2表示p1是否比p2地址小,如果在数组中,是否为低地址位置。9.2.3通过指针引用数组元素 对数组元素的访问是通过数组名和下标来实现的。引入数组指针变量后,可以用不同的方法来访问数组元素。如果p的初值为&score 0,则:p+i和score+i就是scorei的地址,或者说它们指向score数组的第i个元素。*(p+i)或*(score+i)就是p+i或score+i所指向的数组元素,即score

18、i。例如,*(p+3)或*(score+3)就是score3。指向数组的指针变量也可以带下标,如pi与*(p+i)等价。引用一个数组元素可以用两种方法来访问:(1)下标法,即用scorei或者pi的形式访问数组元素。(2)指针法,即采用*(score+i)或*(p+i)形式,用间接访问的方法访问数组元素。例9.8找出如下程序中的错误。#define N 5int main()int scoreN;int*p,i;p=score;srand(unsigned int)time(NULL);printf(成绩如下:n);for(i=0;iN;i+)*p=rand()%51+50;/*随机产生50-

19、100的分数*/p+;for(i=0;iN)/*课程号超出范围*/printf(课程号超出范围!);return;if(k100|k0)/*分数不合法*/printf(分数错误!);return;*(score+n-1)=k;源程序几个地方需要注意:函数形参数组的长度如何确定。在一维数组中,数组的首地址与第一个元素的地址是一样的。在使用指针变量作实际参数时,要确保指针变量具有合法初值。例9.10 将数组a中的n个元素按反序存放。源程序 如果想在函数中改变实参数组元素的值,实参与形参的对应关系有以下种:形参和实参都是数组名实参为数组,形参为指针变量实参和形参都为指针变量实参为指针变量,形参为数组

20、名总结成一句话:实参传给形参的值是一个地址。9.3查找班级总分第一名例9.11 设计函数,将某班全体学生的四门功课的成绩输入到二维数组中,求出该班总成绩最高的学生并输出该生4门功课的成绩。通常一个班的人数最多不超过40人,假定N表示该班的学生人数,则班级学生成绩表可用N4二维数组来存储,在二维数组中,一行就是某一个学生的成绩记录。由于二维数组中并没有总成绩,所以需要在二维数组中对每一行进行求和,比较所有的行才能找出总成绩最高的记录。设计下列函数:(1)初始化函数init。因为全体学生的多门功课数据涉及到较多数据,考虑可以用随机产生数据的方式产生所有学生的成绩。(2)显示一行数据函数displa

21、yOne。总成绩最高分的记录就是一行数据,并且在显示全部同学成绩的时候,也可以调用该函数依次显示所有行就可以了。(3)显示所有数据函数display。(4)在全班成绩中找到最高分的函数findmax。源程序9.3.1多维数组的地址用一个二维数组来表示,其定义为:int a34=1,2,3,4,5,6,7,8,9,10,11,12;假设数组a的首地址为1000,一个整型变量占有4个字节的存储空间,数组a在内存的分布如图所示:内存分布数组表示 二维数组是一个特殊的一维数组,特殊之处就是这个一维数组的每一个元素是一个“行数组”。即数组a有三个元素,即a0,a1,a2。而每一个元素是一个含有四个元素的

22、行数组。二维数组中的地址:例9.12 二维数组中的地址对比。为了更好的理解二维数组中的地址,设计一个程序将二维数组中的地址与值显示出来。源程序9.3.2指向多维数组的指针变量 把二维数组a34分解为一维数组a0,a1,a2之后,设p为指向二维数组的指针变量。可定义为:int(*p)4;它表示p是一个指针变量,它指向包含4个元素的一维数组。p+i则指向一维数组ai。二维数组指针变量说明的一般形式为:类型说明符 (*指针变量名)长度例9.13 请将例9.11的程序代码中的子函数参数改用指向二维数组的指针来实现。源代码9.4演讲稿的保存分析:姓名与发言内容都是字符串型数据,需要分配存储空间存储字符串

23、。可以考虑用字符数组来存放姓名。发言内容的大小变化大,如果也用字符数组来存放,将会造成很大的浪费,可以考虑采用动态存储分配。从而可以用一个二维数组存放每一个人的姓名与发言内容的地址。设计一个二维指针数组,该二维数组的每一行存放了两个指针,这两个指针分别指向发言者的名字与其发言稿。在输入函数input中,动态申请了两块存储区域,一块用来存放名字,另一块存放发言稿,采用这种方式可以灵活的分配存储空间。源程序9.4.1字符串指针 C语言中没有字符串数据类型,字符串存储在字符型数组中并以0结尾,这时数组指针就是称为字符串指针,可以定义一个字符指针指向字符串,其一般格式为:char*字符指针变量名;字符

24、串赋值问题:(1)定义指针变量的同时赋值 char*pstr=C Language;字符串常量C Language是存储在程序区,取其地址给指针变量pstr,此时可以引用字符串,但是不能对字符串修改某个字符,比如把字符数组下标2的元素L修改l:pstr2=l;错误9.4.1字符串指针(2)字符串赋值给指针变量char*pstr;pstr=C Language;字符串常量是存储在程序区,字符串赋值给指针变量,就是取字符串首地址赋值给字符指针变量,所以没有问题。如果定义字符数组,在运行时,用字符串赋值是错误的char str30;str=C Language;/*str为常量不能赋值*/应该采用s

25、trcpy函数实现字符串常量赋值到字符数组中,其代码如下:char str30;strcpy(str,C Language);str2=l;/*修改Language的第一个字母为小写*/(3)字符数组赋值给指针变量char str6;char*pstr;pstr=str;/*或者pstr=&str0;*/字符指针变量指向字符数组,但是该变量不一定是字符串指针,因为字符数组可能没有存储0结尾的字符。故这种方式存在隐患。例9.15 使用字符指针变量引用字符数组#include int main()char str120;char str220=Hello the world;char*pstr1,

26、*pstr2;int i;for(i=0;i20;i+)str1i=A+i;pstr1=str1;pstr2=str2;printf(string2=%sn,pstr2);printf(string1=%sn,pstr1);printf(string1=%.20sn,str1);return 0;运行结果9.4.2指针数组 一个指针数组是一组指针的集合,其中每个元素都是地址,指针数组的所有元素都是指向同一数据类型的指针变量。指针数组说明的一般形式为:类型说明符*数组名数组长度其中类型说明符为数组元素所指向的变量的类型。例如:int*pa3;注意和:int(*p)3;的差别例9.16 设计个菜单

27、,菜单显示内容存放在一个字符指针数组中,并设计一个显示菜单的函数menu。#include void menu(char*bar,int n)int i;for(i=0;in;i+)printf(t%sn,bari);int main()char*menubar=欢迎使用学生成绩管理系统,1.录入学生成绩,2.查询学生成绩,3.修改学生成绩,4.删除学生成绩,5.备份学生成绩,6.初始化系统,7.退出系统;menu(menubar,8);return 0;将字符串保存在一个字符串指针的数组之中,维护起来更方便。9.4.3 main函数的参数 main函数也可以有参数。main函数的实参是在命令

28、行状态下执行时由操作系统传递给main函数的。main函数的形参有两个,例如:int main(int argc,char*argv)argc,表示命令行中参数的个数(包括命 令名本身在内)argv,用来存放命令行中的各个参数(包 括命令名本身在内)例9.17main函数参数的显示#include int main(int argc,char*argv)int i;printf(argc=%dn,argc);for(i=0;iex0919 test file argc=3argv0=ex0919argv1=testargv2=file9.4.4指向指针的指针 如果一个指针变量存放的是另一个指针

29、变量的地址,则称这个指针变量为指向指针的指针变量。定义一个指向指针的指针变量的一般形式为:数据类型 *变量名;假如有name数组如图9-22所示,name是一个指针数组,它的每一个元素是一个指针型数据,其值为地址。P赋值为数组name的首地址,则p为指向指针的指针。例9.18三级指针变量的使用#include int main()int i;int*p1;int*p2;int*p3;p1=&i;p2=&p1;p3=&p2;*p3=100;printf(i=%dn,i);printf(i=%dn,*p1);printf(i=%dn,*p2);printf(i=%dn,*p3);return 0运

30、行结果:i=100i=100i=100i=1009.5 函数指针和指针函数9.5.1函数指针 一个函数占用一段连续的存储区域,函数名就是该函数所占存储区域的首地址。可以把函数的这个首地址(或称入口地址)赋予一个指针变量,使该指针变量指向该函数,通过该指针变量就可以找到并调用这个函数。C语言中把这种指向函数的指针称为函数指针。函数指针定义的一般形式为:函数类型 (*指针变量名)(参数列表);例如:int(*pf)(int,int);例9.19 通过指针实现对函数调用。#include int add(int a,int b)return a+b;int main()int(*pf)(int,in

31、t);int x,y,z;pf=add;printf(input two numbers:n);scanf(%d%d,&x,&y);z=(*pf)(x,y);printf(sum=%dn,z);return 0;使用函数指针变量还应注意以下两点:函数指针变量不能进行算术运算,这是与数组指针变量不同的。数组指针变量加减一个整数可使指针移动指向后面或前面的数组元素,而函数指针的移动是毫无意义的。函数调用中(*指针变量名)的两边的括号不可少,其中的*不应该理解为求值运算,在此处它只是一种表示符号。例9.20 设计一个小程序,给幼儿园的小朋友练习个位数的加法与减法,直到正确为止分析:幼儿园的小朋友的加

32、减法都是正整数的加减法。设计两个函数:add(int,int),sub(int,int)来实现正整数的加减法。设计一个函数指针pf,准备根据随机数来选择指向add 或者 sub函数,利用指针pf调用函数即可。源程序9.5.2指针函数 在C语言中允许一个函数的返回值是一个指针(即地址),这种返回指针值的函数称为指针型函数,简称指针函数。定义指针函数的一般形式为:函数类型*函数名(形参表)/*函数体*/其中函数名之前加了“*”号表明这是一个指针型函数,即返回值是一个指针。函数类型表示了返回的指针值所指向的数据类型。例9.21 输入一个日期例如2020-7-20,输出对应的星期名Monday。分析:要计算某一天是星期几,应该有应该基准点:1900-1-1是星期一。可以设计一个函数daysPass(int year,int month,int day)求出指定的日期距离基准点的天数。设一个char*weekday(int days)返回距离基准点days天是星期几的英文单词字符串。源程序谢谢第9章结束

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 教育专区 > 大学资料

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

工信部备案号:黑ICP备15003705号-8 |  经营许可证:黑B2-20190332号 |   黑公网安备:91230400333293403D

© 2020-2023 www.deliwenku.com 得利文库. All Rights Reserved 黑龙江转换宝科技有限公司 

黑龙江省互联网违法和不良信息举报
举报电话:0468-3380021 邮箱:hgswwxb@163.com