C语言程序设计 课件 9利用指针优化项目_第1页
C语言程序设计 课件 9利用指针优化项目_第2页
C语言程序设计 课件 9利用指针优化项目_第3页
C语言程序设计 课件 9利用指针优化项目_第4页
C语言程序设计 课件 9利用指针优化项目_第5页
已阅读5页,还剩79页未读 继续免费阅读

下载本文档

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

文档简介

C语言程序设计创建第一个C语言程序项目1“学生成绩管理系统”中相关数据设计及简单处理项目2项目中学生成绩的等级判定项目3项目中的设计数据处理及封面与菜单的初步项目4学生成绩的分组汇总程序项目5利用数组完善项目中数据的处理项目6利用函数进行项目的整体框架设计项目7利用结构体实现项目项目8利用指针优化项目项目9利用文件完善项目项目10项目9利用指针优化项目目标TARGET知识目标掌握指针的定义与使用。掌握指针的运算。掌握指向数组的指针。掌握指向结构体的指针。掌握指向函数的指针。目标TARGET技能目标能够熟练使用数组指针解决多个数据处理问题。能够利用指针操作结构体,对结构体成员进行访问。能够使用指针解决函数相关问题,提高执行效率。用指针实现学生最高、最低成绩查找任务9.1用指针实现学生成绩排序任务9.2任务9.1用指针实现学生最高、最低成绩查找

任务描述

改进学生成绩管理系统,用指针来实现学生成绩管理系统中的最值的查找,提高程序执行效率。任务分析

项目8中开发的学生成绩管理系统,对数据的操作是通过结构成员访问实现的,显然执行效率低,处理批量数据速度太慢。本任务将利用指针知识优化程序主要功能模块—最值查找,用指针来访问结构成员,处理批量数据,以提高系统的访问效率。

本任务的要点是:用指向结构的指针作为函数的参数。1认识指针Part◎指针与数组◎指针的概念指针的概念

在内存中,每个内存单元都有一个地址,如在一个32位计算机的内存中,内存地址的编号按十六进制从00000000-FFFFFFFF,共有232个内存单元(字节),如果一个整型变量占据4个字节,那么4个字节中编号最小的字节的地址即是该整型变量所占存储单元的地址。通常我们把指向内存存储单元的地址叫指针。如果一个整型变量占据4个字节,那么4个字节中编号最小的字节的地址即是该整型变量所占存储单元的地址。通常我们把指向内存存储单元的地址叫指针。如一个整型变量inta=247,在内存中占据4个字节,存储的内容是247,假如所占据的4个字节从地址为0012FF7C开始,则变量a的地址就是0012FF7C,该地址也叫整型变量所占存储单元的首地址,也是变量a的指针,记作&a。一个变量的地址称为该变量的“指针”。如果有一个变量专门用来存放其他变量的地址(指针),这个变量被称为“指针变量”。指针的概念

(1)指针变量的定义、初始化和使用指针变量在使用前首先需要定义,定义指针变量的语法格式如下所示:

类型标识符*指针变量名;一般指针变量初始化格式如下所示:类型标识符*指针变量名=&变量名;指针的概念

指针变量的初始化方式:1)定义指针变量,由系统进行初始化操作,或者不进行初始化。如:inta,*p;2)定义指针变量的同时进行初始化。如:inta,*p=&a;或者inta;int*p=&a;3)指针变量初始化为空值。如:inta,*p=NULL;指针的概念

指针变量的引用:指引用指针变量指向的变量,就是根据指针变量中存放的地址,访问该地址对应的变量。访问指针变量指向变量的方式非常简单,只需在指针变量前加一个“*”(取值运算符)即可,访问指针变量的语法格式如下所示:*指针表达式;指针的概念

(2)指针变量作为函数参数指针变量作为变量,它具有变量的一切特征,它也可以作为函数的形参,接受在函数调用时实参传过来的值,那么指针变量作为函数的参数时,实参必须是指针变量、变量的地址、地址常量等。指针的概念

#include<stdio.h>voidmain(){intnum=1;int*ptr=#//定义一个指针变量,指针printf("\nnum的值=%dnum地址=%p",num,&num);//显示num的地址printf("\nptr的地址是%pptr存放的值是地址为%pptr指向的值=%d",&ptr,ptr,*ptr);getchar();}例9-1写一个程序,获取一个int变量num的地址,并显示到终端,将num的地址赋给指针ptr,并通过ptr去修改num的值。指针的概念

执行结果说明:(1)int*表示类型为指针类型,变量名称为ptr,ptr就是一个int*类型,ptr指向了一个int类型的变量的地址。(2)如果要输出一个变量的地址,使用格式是%p,&num表示取出num这个变量的对应地址。(3)指针变量,本身也有地址,ptr的地址为&ptr;ptr表示指针变量存放的地址,通过*ptr获取指针指向的值。注意:(1)指针和指针变量是两个完全不同的概念,指针是一个地址,而指针变量是存放地址(指针)的变量。(2)基本数据类型都有对应的指针类型,形式为数据类型*,比如int的对应的指针就是int*,float对应的指针类型就是float*,依次类推。指针与数组

(1)数组的指针和指向数组的指针变量

数组的指针是指数组在内存中的起始地址,数组元素的指针是数组元素在内存中的起始地址。

类似于指向简单变量的指针,指向数组的指针变量只要将数组的首地址(或数组名)赋给指针变量即可。例如:intiData[5];/*定义iData为整型数据的数组*/int*p;/*定义p为指向整型变量的指针*/则语句:p=&iData[0];(或p=iData;)/*p指向iData数组的第0号元素*/称为p指针为指向数组iData的指针变量。指针与数组

(2)数组元素的引用假设指针变量p指向了数组iData,若想引用数组中的元素,可以通过下列两种方式。1)下标法iData[i] //①数组名下标法p[i] //②指针变量下标法2)指针法*(iData+i) //①数组名指针法*(p+i) //②指针变量指针法指针与数组

(3)数组名作为函数参数当数组名作为函数参数时,在函数调用时,实际传递给函数的是该数组的起始地址,即指针值。所以,实参可以是数组名或指向数组的指针变量。而被调函数的形参,既可以说明为数组,也可以说明为指针。指针与数组

(4)字符串与指针访问一个字符串可以通过两种方式,第一种就是前面学习过的使用字符数组来存放一个字符串,从而实现对字符串的操作;另一种方法就是下面要介绍的使用字符指针指向一个字符串,此时可以不定义数组。例如:char*p="IloveC";指针与数组

(5)指针数组如果一个数组的每个元素都是指针类型的数据,则这种数组称指针数组。指针数组定义的一般形式为:类型标识符*数组名[常量表达式];比如:int*ptr[3];ptr声明为一个指针数组,由3个整数指针组成。因此,ptr中的每个元素,都是一个指向int值的指针。指针与数组

#include<stdio.h>voidmain(){intarray[10]={1,2,3,4,5,6,7,8,9,10};inti,*p;p=array;for(i=0;i<10;p++,i++){printf("%d",*p);}printf("\n");}例9-2定义一个一维数组,并用指针依次访问数组元素。指针与数组

执行结果说明:(1)在第7行for语句中,int类型的指针变量p指向数组array,第7~10行,通过for循环移动指针p,依次指向数组中的每个元素,并输出。(2)指针是一个用数值表示的地址,可以对指针执行四种算术运算:++、--、+、-。当对指针进行++时,指针会按照它指向的数据类型字节数大小增加,例如int*指针,每++,就增加4个字节,指向了下一个数组元素。注意:(1)数组名并不代表整个数组,只代表数组首元素的地址。(2)和指针变量不同的是,数组名array中的地址是不可变的,而指针p中的地址是可变的。指针与数组

#include<stdio.h>voidfunc(int*p){*p=20;}voidmain(){intnum=10;printf("num=%d\n",num);func(&num);printf("num=%d\n",num);getchar();}例9-3指针作为函数参数应用。指针与数组

执行结果说明:在程序中第2行代码定义一个func()函数,该函数的参数类型为指针类型。在main()函数中调用该函数时传入变量num的地址,对其取值运算后赋新的值。注意:func()函数必须写在main()函数的前面,否则需要在main()函数前声明func()函数。指针与数组

#include<stdio.h>voidmain(){//定义一个指针数组,该数组的每个元素,指向的是一个字符串char*books[]={"三国演义","西游记","红楼梦","水浒传"};inti,len=4;//遍历for(i=0;i<len;i++){printf("\nbooks[%d]指向字符串是=%s",i,books[i]);}getchar();}例9-4请编写程序,定义一个指向字符的指针数组来存储字符串列表(四大名著书名),并通过遍历该指针数组,显示字符串信息。指针与数组

执行结果说明:1)本例中定义了一个指针数组,该数组的每个元素,指向的是一个字符串。2)使用循环依次输出指针数组指向字符串的值,格式控制为%s。注意:数组指针和指针数组不是同一个概念,数组指针是指一个指向数组的指针,指针数组是指数组中的元素类型都是指针类型。任务9.2用指针实现学生成绩排序

任务描述改进学生成绩管理系统,用指针来实现学生成绩管理系统中的学生成绩的排序,提高程序执行效率。任务分析我们将利用指针知识优化程序主要功能模块--学生成绩的排序,用指针来访问结构成员,处理批量数据,达到提高系统的访问效率。本任务的要点是:在函数体内直接用指针访问结构成员。2指针的更多应用Part◎指针与函数◎指针与结构体指针与结构体

(1)指向结构体变量的指针指向结构体变量的指针称为结构体指针,其定义格式和基本数据类型的指针变量定义一样。一般形式为:struct结构类型名*指针变量名当结构体指针指向一个结构体变量时,该指针变量的值就是该结构体变量的起始地址。用取地址运算符“&”就可获得结构变量的指针。一般形式为:指针变量名=&结构体变量名;指针与结构体

(1)指向结构体变量的指针例如:structStudent{charname[20];//姓名intid;//学号floatscore;//分数}stu;指向结构体student的指针变量定义并赋值为:structstudent*p=&stu;指针与结构体

(1)指向结构体变量的指针在定义了指向结构体类型变量的指针后,可以通过结构体指针操作结构体变量的成员,常用的访问方式是:结构体变量名.成员名(*结构体指针变量名).成员名结构体指针变量名->成员名例如:根据如上例子指针变量p指向了结构体变量stu,则三种访问方式分别为:stu.成员名、(*p).成员名、p->成员名。指针与结构体

(3)指向结构体数组的指针类似于用指向结构体变量的指针,间接访问结构体成员一样,也可以用指向结构体数组及其元素的指针来处理结构体数组。可以把结构体数组的数组名赋值给结构体指针,也就是把结构体数组的首地址赋值给结构体指针。指针与结构体

(3)指向结构体的指针作为函数参数类似于普通指针变量作为函数参数一样,用指向结构的指针变量作实参时,是属于“地址传递”方式。指针与结构体

(4)使用指针优化学生成绩的录入和浏览模块①使用typedef给学生信息类型定义别名typedefstructstudent //定义学生成绩结构体{intnum; //学号charname[16]; //姓名floatmath; //数学成绩floatyw; //语文成绩floateng; //英语成绩floatsum; //总分}STUDENT,*PSTUDENT;指针与结构体

(4)使用指针优化学生成绩的录入和浏览模块②修改成绩录入模块用指向结构体的指针作为函数参数,函数体内用指针法访问结构体成员。voidfnInputData(PSTUDENTs){inti;charch[2];PSTUDENTstu=s;stu+=m;//m已录入的记录总数PSTUDENTtemp;do{printf("\n\t请输入学生信息:\n\t\t学号:");scanf("%ld",&stu->num);for(temp=s,i=0;i<m;i++,temp++)if(temp->num==stu->num)指针与结构体

{printf("\n\t该学号已存在,请按任意键继续!");getchar();}printf("\t\t姓名:");//输入姓名、数学、英语、语文成绩scanf("%s",stu->name);printf("\t\t数学:");scanf("%f",stu->math);printf("\t\t英语:");scanf("%f",stu->eng);printf("\t\t语文:");scanf("%f",stu->yw);stu->sum=stu->math+stu->yw+stu->eng;//计算总成绩m++;stu++;printf("\t\t是否继续?(y/n):");scanf("%s",ch);}while(strcmp(ch,"y")==0||strcmp(ch,"Y")==0);}指针与结构体

(4)使用指针优化学生成绩的录入和浏览模块③修改成绩浏览模块voidfnMod(PSTUDENTs){inti;PSTUDENTstu=s;printf("\t学号\t姓名\t数学\t语文\t英语\t总分\n");if(m==0)printf("\n\n\t\t没有记录");for(i=0;i<m;i++,stu++)printf("\t%-8ld%-8s%-8.1f%-8.1f%-8.1f%-8.1f\n",stu->num,stu->name,stu->math,stu->yw,stu->eng,stu->sum);}指针与结构体

#include"stdio.h"structstudent{charchName[13];charchSex;intiAge;};structstudentstStu[3]={{"zhang",'M',17},{"Li",'F',18},{"Wang",'M',19}};voidmain(){ structstudent*pStr=stStu; for(;pStr<stStu+3;pStr++) printf("\n%-10s%2c,%4d",pStr->chName,pStr->chSex,pStr->iAge);Getchar();}例9-5已知3名学生的信息,包含姓名、性别和年龄,请自定义结构体类型,然后利用指向结构体数组的指针变量来访问学生的信息,并在屏幕上输出。指针与结构体

执行结果说明:1)构造结构体类型,包含姓名、性别、年龄三个成员。2)定义学生结构体数组并初始化。3)在main()函数中定义学生结构体类型指针变量,并指向结构体数组。4)构造循环,利用结构体指针变量访问结构体数组成员。注意:如果pStr指向结构体数组的一个元素,则pStr+1就指向同一结构体数组的下一个元素。指针与结构体

例9-6已知3名学生的信息,包含编号、姓名、性别和年龄,请自定义结构体类型,输出3名学生信息,输出过程通过函数实现。指针与结构体

#include<stdio.h>structstudent{intid;intage;charname[10];charsex;};voidshow(structstudent*stu,intcount){structstudent*p;for(p=stu;p<stu+count;p++){printf("id:%d,age:%d,name:%s,sex:%c\n",p->id,p->age,p->name,p->sex);}}voidmain(){structstudentstu[3]={{1001,18,"ZhangSan",'M'},{1002,16,"LiSi",'W'},{1003,19,"ZhaoLiu",'M'}}; show(stu,3); getchar();}指针与结构体

执行结果说明:1)声明show()函数并实现功能。2)声明main()函数,在main()函数中,定义并初始化结构体数组。3)调用show()函数,遍历结构体数组并输出其成员的值。4)在该案例中,由于无法通过数组直接获取到其长度,因此,在定义的show()函数中,需要传递两个参数,其中一个是结构体数组的首地址,另一个是数组的长度。show()函数接收到传递来的数组首地址和长度后,使用for循环,将结构体数组中的所有成员输出。注意:结构体指针变量用于存放结构体变量的首地址,所以将指针作为函数参数传递时,其实就是传递结构体变量的首地址。指针与函数

(1)函数的返回值是指针类型一个函数不仅可以返回int型、float型、char型和结构类型等数据类型,也可以返回指针类型的数据。返回指针类型的函数定义格式为:类型名*函数名([参数表]){

函数体;}指针与函数

(1)函数的返回值是指针类型例如:int*func(){int*p;.../*省略的其它操作语句*/return(p);}func()函数的返回值是一个指向整型变量的指针。指针与函数

(2)指向函数的指针变量①指向函数的指针变量的定义函数在内存中也占据一定的存储空间并有一个入口地址(函数开始运行的地址),这个地址就称为该函数的指针。可以用一个指针变量来存放函数的入口地址,这时称该指针指向这个函数,并称该指针变量为“指向函数的指针变量”,简称为“函数的指针变量”或“函数指针”,可以通过函数指针来调用函数,这是函数指针的主要用途。函数指针定义的一般形式为:类型标识符

(*指针变量名)(参数);指针与函数

(2)指向函数的指针变量②指向函数的指针变量的赋值与其它指针的定义一样,函数指针定义后,应给它赋一个函数的入口地址,即使它指向一个函数,才能使用这个指针。C语言中,函数名代表该函数的入口地址。因此,可用函数名给指向函数的指针变量赋值:指向函数的指针变量=函数名;指针与函数

(2)指向函数的指针变量③用函数指针变量调用函数通过函数指针来调用函数的一般格式是:(*函数指针)(实参表)指针与函数

(3)指向函数的指针变量作函数参数假设函数A在运行过程中要根据不同情况多次调用下列函数:B、C、D和E之一来协助它进行处理,按照以往的做法是,用条件选择语句将上述函数写在函数A的函数体中的多个位置上,这是一种笨拙的、灵活性较差的处理方法。现在,可以通过使用函数指针作为函数参数的方式向函数A传递其它函数的入口地址,从而灵活地调用其他函数。指针与函数

例9-7函数指针实例,声明add()函数和times()函数分别实现两个整数相加和相乘。在main()函数体内定义函数指针。用函数指针分别调用add()函数和times()函数计算两个数的和及乘积。指针与函数

#include<stdio.h>intadd(inta,intb){returna+b;}inttimes(inta,intb){returna*b;}intfunc(int(*p)(int,int),inta,intb){returnp(a,b);}voidmain(){inta,b,result;int(*p)(int,int);a=32;b=12;p=add;result=func(p,a,b);printf("%d+%d=%d\n",a,b,result);p=times;result=func(times,a,b);printf("%d*%d=%d\n",a,b,result);getchar();}指针与函数

执行结果说明:

在该案例中,第2~9行代码定义了add()函数和times()函数,分别用于对两个参数进行相加和相乘处理。第10~13行代码定义了一个func()函数接收一个函数指针p和两个int类型变量作为参数,在函数中通过函数指针p来决定用哪个函数处理这两个int类型的参数,最后将结果返回。第20~25行代码分别将函数指针p指向add()函数和times()函数,func()函数调用参数p,然后使用result变量来接收func()的返回值,并在控制台输出结果。注意:1)指针函数本质是一个函数,其返回值为指针。函数指针本质是一个指针,其指向一个函数。其写法分别为:指针函数:int*fun(intx,inty);函数指针:int(*fun)(intx,inty);2)指针函数的*是属于数据类型的,而函数指针的星号是属于函数名的。拓展案例案例9-1写出下面问题的算法问题描述请编写一个函数strlong(),返回两个字符串中较长的一个,通过指针函数实现。拓展案例

#include<string.h>char*strlong(char*str1,char*str2){//函数返回的char*(指针)printf("\nstr1的长度%dstr2的长度%d",strlen(str1),strlen(str2));if(strlen(str1)>=strlen(str2)){returnstr1;}else{returnstr2;}}intmain(){charstr1[30],str2[30],*str;printf("\n请输入第1个字符串");gets(str1);printf("\n请输入第2个字符串");gets(str2);str=strlong(str1,str2);printf("\nLongerstring:%s\n",str);getchar();return0;}拓展案例案例1-2写出下面问题的算法问题描述本题是一个经典的数学问题。对于一个大于2的正整数,判断它是不是一个素数。。说明:1)本例中定义了一个返回类型为char*的strlong()指针函数,通过strlen()求出两个字符串的长度,将长度长的字符串返回。2)在main()函数中通过gets方法输入两个字符串,调用strlong()指针函数求出结果。注意:1)用指针作为函数返回值时需要注意,函数运行结束后会销毁在它内部定义的所有局部数据,包括局部变量、局部数组和形式参数,函数返回的指针不能指向这些数据。2)函数运行结束后会销毁该函数所有的局部数据,这里所谓的销毁并不是将局部数据所占用的内存全部清零,而是程序放弃对它的使用权限,后面的代码可以使用这块内存。拓展案例

执行结果拓展案例案例9-2写出下面问题的算法问题描述使用指针修改学生成绩管理系统的记录查找、修改、删除模块。拓展案例

voidfnDel(structstudentstu[]) //自定义删除函数{inti,j;longsnum;charch[2];structstudent*p;p=stu;if(m==0){printf("\n\t\t没有记录!\n");return;}printf("\n\t请输入你要删除的学号:");scanf("%ld",&snum);for(i=0,p=stu;i<m;i++,p++)if(snum==p->no)break;if(i==m){printf("\n\t\t没有你要删除的学号");getch();return;}printf("\t查找到,你确定要删除吗?(y/n)");scanf("%s",ch);if(strcmp(ch,"Y")==0||strcmp(ch,"y")==0)//判断是否要进行删除{for(j=i;j<m;j++,p++)*p=*(p+1);//将后一个记录移到前一个记录的位置m--; //记录的总个数减1printf("\t\t删除成功!\n");}}拓展案例

voidfnSearch(structstudentstu[]) //自定义查找函数{inti;longsnum;structstudent*p;p=stu;if(m==0){printf("没有记录!\n");return;}printf("\t\t请输入你要查找的学号:");scanf("%ld",&snum);for(i=0,p=stu;i<m;i++,p++) /*查找匹配*/if(snum==p->num) /*查找到,输出记录*/{printf("\n\t\t查找到的学生,信息如下:\n\n");printf("\t学号\t姓名\t数学\t语文\t英语\t总\n");printf("\t%-8ld%-8s%-8.1f%-8.1f%-8.1f%-8.1f\n",p->num,p->name,p->math,p->yw,p->eng,p->sum);//printf(FORMAT,DATA); //将查找出的结果按指定格式输出return;}if(i==m)printf("\t\t未找到要查找的学生息!\n");}

voidfnModify(structstudentstu[]) //自定义修改函数inti;longsnum;structstudent*p;p=stu;if(m==0)

{printf("没有记录!\n");

return;}拓展案例

printf("\t\t请输入你要修改的学号:");scanf("%ld",&snum); //输入待修改的学号for(i=0,p=stu;i<m;i++,p++) //检索记录中是否有该学号记录信息if(snum==p->num)break; if(i<m){printf("\t学号\t姓名\t数学\t语文\t英语\t总\n");//将查找出的结果按指定格式输出printf("\t%-8ld%-8s%-8.1f%-8.1f%-8.1f%-8.1f\n",p->num,p->name,p->math,p->yw,p->eng,p->sum);printf("\t\t找到了,输入修改信息!\n");printf("\t\t姓名:");

scanf("%s",p->name); //输入名字printf("\t\t数学:");scanf("%f",&p->math); //输入数学课成绩printf("\t\t语文:");scanf("%f",&p->yw); //输入语文课成绩printf("\t\t英语:");scanf("%f",&p->eng); //输入英语课成绩p->sum=p->math+p->yw+p->eng; }else{printf("\n\t\t没有找到!");getch();return;}}说明:1

温馨提示

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

评论

0/150

提交评论