C语言程序设计 课件 第9章-进阶内容_第1页
C语言程序设计 课件 第9章-进阶内容_第2页
C语言程序设计 课件 第9章-进阶内容_第3页
C语言程序设计 课件 第9章-进阶内容_第4页
C语言程序设计 课件 第9章-进阶内容_第5页
已阅读5页,还剩55页未读 继续免费阅读

下载本文档

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

文档简介

第9章

进阶内容理解C语言共用体、枚举、位运算、复杂函数递归、编译预处理等概念方法了解使用命令执行参数和回调函数的一般步骤使用递归函数和指针处理复杂问题使用特殊编程技术的能力本章目标9.1.1共用体共用体定义的一般形式为:union共用体名{类型名成员名1;类型名成员名2;...类型名成员名n;};共同体中所有的成员共同使用一片内存空间,所有成员的内存空间相互重叠9.1使用共用体、枚举类型【例9-1】几所学校要联合统计学生的成绩,但是一个问题难住了统计人员,不同学校相同的课程计分方式不一样,有的学校使用百分制,有的学校使用五级制,如何设计数据的存储结构才能正确数据保存呢?本应用中,五级制和百分制成绩二选一,所以使用共用体来存储共用体字段在使用中需要使用一个标记来确定使用的是哪个字段本例中,五级制和百分制需要根据情况分别讨论共用体共用体示例#include<stdio.h>#include<string.h>#defineM10structStuScore{ intid; charname[20]; charflag;/*成绩标记'm'为百分制,'g'为五级制*/

union{ intmark; chargrade[12]; }score;};voidDisplayStuScore(structStuScores){ printf("%s\t%d\t",,s.id); if(s.flag=='m'||s.flag=='M') printf("%d\n",s.score.mark); elseif(s.flag=='g'||s.flag=='G') printf("%s\n",s.score.grade);}intReadStuScore(structStuScore*s){ intflagInputError=1; charc; scanf("%s%d%c",s->name,&s->id,&s->flag); switch(s->flag) { case'm': case'M': printf("请输入百分制成绩:"); scanf("%d",&s->score.mark); return1; case'g':case'G': printf("请选择五分制成绩:A.优秀;B.良好;C.中等;D.及格;E.不及格:"); /*while语句将输入缓冲区数据清空,保证后续正确读入字符*/ while((c=getchar())!='\n'&&c!=EOF); scanf("%c",&c); switch(c) { case'A':case'a':strcpy(s->score.grade,"Distinction");break; case'B':case'b':strcpy(s->score.grade,"Merit");break; case'C':case'c':strcpy(s->score.grade,"Medium");break; case'D':case'd':strcpy(s->score.grade,"Passed");break; case'E':case'e':strcpy(s->score.grade,"Failed");break; default:flagInputError=0;break; } break; default:flagInputError=0;break; } if(flagInputError==0)printf("输入成绩有误,请重新输入这条数据!\n"); returnflagInputError;}共用体示例intmain(intargc,char*argv[]){ structStuScoress[M]; intn,i,r; printf("请输入学生人数:"); scanf("%d",&n); printf("请输入学生姓名、学号、成绩类别(m百分制,g五级制):\n"); for(i=0;i<n;i++){ printf("请输入第%d条学生信息:\n",i+1); /*数据读入到结构体数组元素ss[i]中*/ r=ReadStuScore(&ss[i]); /*返回0值表示读入数据有误,不记录*/ if(r==0) i--; } printf("**********************\n显示学生成绩信息:\n"); for(i=0;i<n;i++) DisplayStuScore(ss[i]); return0;}

运行结果示例:请输入学生人数:3请输入学生姓名、学号、成绩类别(m百分制,g五级制):请输入第1条学生信息:李白101m请输入百分制成绩:98请输入第2条学生信息:杜甫102g请选择五分制成绩:A.优秀;B.良好;C.中等;D.及格;E.不及格:F输入成绩有误,请重新输入这条数据!请输入第2条学生信息:杜甫102g请选择五分制成绩:A.优秀;B.良好;C.中等;D.及格;E.不及格:A请输入第3条学生信息:白居易103g请选择五分制成绩:A.优秀;B.良好;C.中等;D.及格;E.不及格:B**********************显示学生成绩信息:李白10198杜甫102Distinction白居易103Merit

共用体空间占用分析#include<stdio.h>intmain(intargc,char*argv[]){ union{ charch; shortshint; intloint; }number; printf("number占用空间%d字节\n",sizeof(number)); printf("number.ch占用空间%d字节\n",sizeof(number)); printf("number.shint占用空间%d字节\n",sizeof(number.shint)); printf("number.loint占用空间%d字节\n",sizeof(number.loint)); number.loint=0x12345678; printf("%x%x%x\n",number.ch,number.shint,number.loint); number.shint=0x5566; printf("%x%x%x\n",number.ch,number.shint,number.loint); number.ch=0x41; printf("%x%x%x\n",number.ch,number.shint,number.loint); return0;}输出结果:number占用空间4字节number.ch占用空间4字节number.shint占用空间2字节number.loint占用空间4字节785678123456786655661234556641554112345541共用体空间占用分析

number.loint=0x12345678;printf("%x%x%x\n",number.ch,number.shint,number.loint);number.shint=0x5566;printf("%x%x%x\n",number.ch,number.shint,number.loint);number.ch=0x41;printf("%x%x%x\n",number.ch,number.shint,number.loint);9.1.2枚举枚举类型定义格式:enum枚举类型名{枚举成员1,枚举成员2,...,枚举成员n};枚举的各成员对应的整型数值,可以在定义的同时指定值,也可以使用默认值。在不指定值的情况下,枚举成员1默认为0,枚举成员2默认为1,以此类推。9.1使用共用体、枚举类型【例9-3】几所学校要联合统计学生成绩,不同学校相同的课程计分方式不一样,有的使用的是百分制,而有的使用的却是五级制,如何对成绩进行平均分的统计呢?分析:使用枚举确定五级制转换为百分制成绩使用枚举类型

#include<stdio.h>#defineM10enumGrade{A=95,B=85,C=75,D=65,E=50};intmain(intargc,char*argv[]){ enumGradegrade[M]; inti,sum=0,ave,count=M; charch; printf("请输入%d个学生等级(不用使用分隔其他字符分隔)\n",M); printf("A.优秀;B.良好;C.中等;D.及格;E.不及格:\n"); for(i=0;i<M;i++){ scanf("%c",&ch); switch(ch){ case'A':case'a':grade[i]=A;break; case'B':case'b':grade[i]=B;break; case'C':case'c':grade[i]=C;break; case'D':case'd':grade[i]=D;break; case'E':case'e':grade[i]=E;break; default: printf("第%d个成绩有误,平均分没有计入\n",i+1); count--; break; } } for(i=0;i<M;i++){ sum+=grade[i]; } ave=sum/count; printf("共%d个有效成绩,平均分为%d\n",count,ave); return0;}【例9-4】微信某一个版本发布后,用户发现多了一个状态设置功能,大家纷纷玩起了状态设置,但是有个缺点,同一时刻只能有一个状态。现在假设由你来设计这个状态参数,允许用户同时设置多个状态,该如何实现呢?分析:使用枚举类型定义每个状态使用枚举类型

根据枚举值输出enumStatus{Sun,Zoning,Exhausted,Happy,Thinking,Broken,Fighting,Lucky,Emo,Studying,Busy,Shopping};voiddisplay(enumStatusc){switch(c){caseSun:printf("等天晴\t");break;caseZoning:printf("发呆\t");break;caseExhausted:printf("疲惫\t");break;caseHappy:printf("美滋滋\t");break;caseThinking:printf("胡思乱想\t");break;caseBroken:printf("裂开\t");break;caseFighting:printf("冲\t");break;caseLucky:printf("求锦鲤\t");break;caseEmo:printf("emo\t");break;caseStudying:printf("学习\t");break;caseBusy:printf("忙\t");break;caseShopping:printf("购物\t");break;}}

intmain(){intstatus[32]={0},choice;enumStatusc;printf("1.等天晴\t2.发呆\t3.疲惫\n");printf("4.美滋滋\t5.胡思乱想\t6.裂开\n");printf("7.冲\t8.求锦鲤\t9.emo\n");printf("10.学习\t11.忙\t12.购物\n");printf("请选择你的状态(以0结束):\n");scanf("%d",&choice);while(choice!=0){switch(choice){case1:status[Sun]=1;break;case2:status[Zoning]=1;break;case3:status[Exhausted]=1;break;case4:status[Happy]=1;break;case5:status[Thinking]=1;break;case6:status[Broken]=1;break;case7:status[Fighting]=1;break;case8:status[Lucky]=1;break;case9:status[Emo]=1;break;case10:status[Studying]=1;break;case11:status[Busy]=1;break;case12:status[Shopping]=1;break;}scanf("%d",&choice);}printf("你的状态是:");for(c=Sun;c<=Shopping;c++)if(status[c]==1)display(c);return0;}根据选择,设置状态对应值9.2.1位运算

9.2二进制的世界很简单运算符描述&按位与|按位或~按位取反^按位异或【例9-5】使用二进制记录例9-4微信状态,通过二进制运算实现个状态的设置。分析:状态只有0,1两个值,可以使用一位二进制数表示,使用二进制解决问题程序中使用数组intset[32]={1,2,4,8,16,32,64,128,256,512,1024,2048}辅助按位赋值运算,set的各元素分别对应了各状态对应二进制位为1而其他位为0的情况。想设置某位为1,而又不改变其他位的值,将status与对应set[i]按位求或(运算符为|)。voiddisplay(intstatus){intset[32]={1,2,4,8,16,32,64,128,256,512,1024,2048};intc,i;for(i=0;i<12;i++){

c=status&set[i];switch(c){case1:printf("等天晴\t");break;case2:printf("发呆\t");break;case4:printf("疲惫\t");break;case8:printf("美滋滋\t");break;case16:printf("胡思乱想\t");break;case32:printf("裂开\t");break;case64:printf("冲\t");break;case128:printf("求锦鲤\t");break;case256:printf("emo\t");break;case512:printf("学习\t");break;case1024:printf("忙\t");break;case2048:printf("购物\t");break;}}

}voidsetStatus(int*pst,intchoice){intset[32]={1,2,4,8,16,32,64,128,256,512,1024,2048};

*pst=*pst|set[choice];}intmain(){intstatus=0,choice;printf("1.等天晴\t2.发呆\t3.疲惫\n");printf("4.美滋滋\t5.胡思乱想\t6.裂开\n");printf("7.冲\t8.求锦鲤\t9.emo\n");printf("10.学习\t11.忙\t12.购物\n");printf("请选择你的状态(以0结束):\n");scanf("%d",&choice);while(choice!=0){setStatus(&status,choice-1);scanf("%d",&choice);}printf("你的状态是:");display(status);return0;}变量signal存放了16路信号的情况(每路信号一个二进制位)1)提取特定的二进制位。想检测signal变量第2、4、5路信号的情况(信号从0路开始计),使用signal&52(52是二进制数(110100)2对应的十进制数)。2)对特定位清0。要将signal变量高8路信号清零,则signal=signal&0xFF;这里0xFF为十六进制常量,对应的8位二进制位并且数据位全为1。(1)按位与&

应用变量signal存放了16路信号的情况(每路信号一个二进制位)按位求或,可以在保持其他位不变的情况下对特定为位赋1。前述变量signal,想要第0路和第15路信号为1,其余位保持不变,则

signal=signal|0x81;若想将其信号全部取反,则signal=~signal。(2)按位或|

及按位取反~应用变量signal存放了16路信号的情况(每路信号一个二进制位)按位异或可以实现对特定位进行翻转,0与1异或变为1,而1与1异或变为0。变量signal,若想对其高8路信号取反,其余不变,则

signal=signal^0xF000;异或运算除了满足交换律和结合律外,还有一个重要特性,就是自反性,即:A^B^B=A。使用异或运算交换两个变量的值。

inta=5,b=3;/*异或方法*/a=a^b;b=b^a;a=a^b;(3)按位异或^应用【例9-6】现在移动支付都需要支付密码,长时间不使用就会遗忘。小明为解决这个问题,在学习完位运算后,想到一个好主意,决定对自己的支付密码进行加密后记录下来,这样即使忘记了,也可以通过解密想起来。使用异或进行加密需要一个秘钥key,可以是容易记住的数据。一次与秘钥异或实现加密,密文与秘钥异或实现解密按位异或应用

使用异或进行加密解密#include<stdio.h>intCoding(intpw,intkey){returnpw^key;}intmain(){intpassword,key;printf("\n**************Encrypt*****************\n");printf("inputyourpassword:");scanf("%d",&password);printf("inputyourkey:");scanf("%d",&key);printf("Theencryptedpasswordis%d\n",Coding(password,key));printf("\n**************Decrypt*****************\n");printf("inputyourcode:");scanf("%d",&password);printf("inputyourkey:");scanf("%d",&key);printf("Thepasswordis%d\n",Coding(password,key));return0;}【例9-7】例9-6中需要使用set数组,依次记录2的幂次,小明在使用时是依次计算2的幂次得到,然而学过位运算的小亮告诉他完全不需要这么麻烦啦,二进制的世界很简单!2的幂次,通过二进制位左移即可实现9.2.2位移运算符描述<<向左位移>>向右位移

位移示例#include<stdio.h>voidpower2(intset[],intn);intmain(){ inti,set[20]; power2(set,20); for(i=0;i<20;i++) printf("%10d",set[i]); return0;}voidpower2(intset[],intn){ inti=1; set[0]=1; while(i<=n){

set[i]=set[i-1]<<1; i++; }}输出结果:12481632641282565121024204840968192163843276865536131072262144524288【例9-8】编写程序实现一个扑克自动洗牌发牌。使用位移运算,可以使用一个变量利用错位方式存储多个数据,例如一张扑克牌包括点数和花色信息,可以利用poker变量的低4位来存储花色,而高位存储点数。位移示例enumDecor{Spade,Heart,Diamond,Club};voidinitPorker(int*porker){enumDecoreDecor;intiPoints,c=0;for(iPoints=1;iPoints<=13;iPoints++)for(eDecor=Spade;eDecor<=Club;eDecor++)porker[c++]=(iPoints<<4)+eDecor;porker[52]=0;/*小王*/porker[53]=1;/*大王*/}定义花色扑克初始化voiddisplayPorker(intporker[],intindex){intiPoints;if(porker[index]==0)printf("小王\t");elseif(porker[index]==1)printf("大王\t");else{iPoints=porker[index]>>4;switch(porker[index]&0xf){caseSpade:printf("黑桃");break;caseHeart:printf("红桃");break;caseDiamond:printf("方块");break;caseClub:printf("梅花");break;}if(iPoints>=2&&iPoints<=10)printf("%d\t",iPoints);elseswitch(iPoints){case1:printf("A\t");break;case11:printf("J\t");break;case12:printf("Q\t");break;case13:printf("K\t");break;}}

}显示洗牌结果intmain(){/*porker存放每张牌,flag记录对应下标牌是否发出*/intporker[54],flag[54]={0};/*四个人每人牌面,方便起见在牌序号对应下标处标记*/charperson[4][54]={0};intiPoints,c=0,onePorker,j;initPorker(porker);/*设定随机数产生与系统时钟关联*/srand(time(NULL));for(c=0;c<54;c++){while(1){/*随机取到一张牌没有发出的牌*/onePorker=rand()%54;if(flag[onePorker]==0){flag[onePorker]=1;break;}}/*取到的牌分别发给4个人*/person[c%4][onePorker]=1;}for(c=0;c<4;c++){printf("\n第%d个人的牌为:\n",c+1);for(j=0;j<54;j++)if(person[c][j]==1){displayPorker(porker,j);}}return0;}9.3.1文件包含

系统文件包含9.3编译预处理头文件名描述stdio.h包含常用输入输出函数、文件操作等函数stdlib.h包含字符串转换、随机数生成、动态申请空间等函数math.h常用数学库函数string.h常用字符串函数time.h时间相关类函数多文件系统在开发项目过程中,若项目功能复杂,需要分别在多个程序文件中编写,可以通过include命令将多个源文件包含到一起,形成一个多文件系统。【例9-9】要对学校的班级进行管理,需要记录班级的名称、年级、管理班级的老师以及在这个班级的学生信息。文件包含整个系统包括学生信息模块包括student.h和studnt.c文件、教师信息模块包括teacher.h和teacher.c文件、班级信息模块包括class.h和class.c文件。其中.h文件中存放相关模块的函数声明,而.c文件中为对应函数的定义,main函数在使用时,仅将.h文件包含即可。多文件系统9.3.2条件编译条件编译的预编译指令有:#if、#elif、#else、#endif以及#ifdef、#else、#endif或#ifndef、#else、#endif。#if条件1代码段1#elif条件2代码段2.....#elif条件n代码段n#else代码段n+19.3编译预处理9.3.3带参数的宏带参数宏定义形式:#define宏名(形参表)字符串调用形式:宏名(实参表)宏定义时形参不占用内存空间,不需要定义类型;实参可以变量,也可以是表达式。宏定义时形参一般会加上括号,因为宏替换是直接原样替换,不会考虑运算符的优先级和结合性,避免了替换后改变运算的顺序。9.3编译预处理若有定义#defineSQRAREA(r)(r)*(r),则代码段:doubledR=5,dArea;dArea=SQRAREA(dR+3);printf("area=%.2lf\n",dArea);若定义改为#defineSQRAREA(r)r*r,则代码段:doubledR=5,dArea;dArea=SQRAREA(dR+3);printf("area=%.2lf\n",dArea);带参数宏输出结果为area=64.00。输出结果为area=23.00。【例9-10】格式调一调,完成了一段英文文章后,想将段落中所有单词首字母大写,其余小写,请编写程序实现。使用带参数的宏对大小写字母进行判断#defineISLOWERCASE(c)((c)>='a'&&(c)<='z')#defineISCAPITAL(c)((c)>='A'&&(c)<='Z')使用带参数宏

代码示例#include<stdio.h>#include<string.h>#defineM200#defineISLOWERCASE(c)((c)>='a'&&(c)<='z')#defineISCAPITAL(c)((c)>='A'&&(c)<='Z')intmain(){intflagNewWord=1,i;charstrPara[M];printf("请输入段落:\n");gets(strPara);for(i=0;strPara[i]!='\0';i++){if(flagNewWord==1){/*首字母情况*/if(ISLOWERCASE(strPara[i]))strPara[i]-=32;/*已经判断过首字母,将标记置为0*/flagNewWord=0;}

else{/*非首字母情况*/if(ISCAPITAL(strPara[i]))strPara[i]+=32;/*非大小写字母时,将标记置1*/elseif(!ISLOWERCASE(strPara[i]))flagNewWord=1;}}printf("调整后的段落为:\n");puts(strPara);return0;}【例9-11】九连环是中国传统民间智力玩具,以金属丝制成9个圆环,将圆环套装在横板或各式框架上,并贯以环柄,如图所示。玩时按照一定的程序反复操作,可使9个圆环分别解开,或合二为一。请编写程序模拟解环和安装的步骤。9.4.1函数递归9.4案例项目1——一起来解九连环(1)问题分析使用计算机思维,使用自顶向下的思路来解决。使用自顶向下的计算机思维,关键在于考虑问题时,从大问题入手,而不是细节,在这里不是考虑解开或卸下1、2个环的方法,而是从考虑安装或卸下n个环开始。(2)算法设计九连环解环和安装算法有如下基本原则:若想解下或安装第i环,需要借助单独的第i-1环。这样安装n个环的问题就转化为如下步骤,如图9.6所示:1)安装n-1个环2)卸下n-2个环(杆上只剩下第n-1环)3)借助第n-1环将第n环安装(第n-1环和第n环安装成功)4)安装n-2个环(完成!)安装环

安装环而卸下n个环的步骤就转化为如下步骤,如图9.7所示:a)卸下n-2个环(杆上只剩第n-1环和第n环)b)借助第n-1环卸下第n环(杆上只剩第n-1环)c)安装n-2个环(杆上共有前n-1个环)d)卸下n-1个环(全部卸下)卸下环#include<stdio.h>voidNineRingIn(intn);/*安装n个环*/voidNineRingOut(intn);/*卸下n个环*/intmain(){NineRingIn(5);return0;}/*安装n个环*/voidNineRingIn(intn){/*递归出口*/if(n==1)/*安装1个环时*/printf("安装第1环\n");elseif(n==2){/*安装2个环时*/printf("安装第1环\n");printf("借助第1环安装第2环\n");}/*递归调用*/else{NineRingIn(n-1);/*安装n-1个环*/NineRingOut(n-2);/*卸下n-2个环*/printf("借助第%d环安装第%d环\n",n-1,n);NineRingIn(n-2);/*安装n-2个环*/}}/*卸下n个环*/voidNineRingOut(intn){if(n==1)/*卸下1个环*/printf("卸下第1环\n");elseif(n==2){/*卸下2个环*/printf("借助第1环卸下第2环\n");printf("卸下第1环\n");}/*递归调用*/else{NineRingOut(n-2);/*卸下n-2个环*/printf("借助第%d环卸下第%d环\n",n-1,n);NineRingIn(n-2);/*安装n-2个环*/NineRingOut(n-1);/*卸下n-1个环*/}}当n=5时,程序运行时函数调用树如下图所示。运行时函数调用树【例9-12】在解九连环的过程中,一次安装或解环记为1次操作,请编写程序统计要完成将九个环安装,需要做多少次操作。(1)问题分析统计操作次数,需要在每次安装或是卸下的时候进行计数,而安装或卸下又在安装卸下函数内部,若使用局部变量,计数不会保留,因此也无法得到总的操作次数。(2)算法设计结合全局变量+递归和九连环算法解决上述问题。9.4.2外部变量与静态变量9.4案例项目1——一起来解九连环#include<stdio.h>intcount;/*全局变量,记录操作次数*/voidNineRingIn(intn);/*安装n个环*/voidNineRingOut(intn);/*卸下n个环*/intmain(){NineRingIn(9);printf("安装九连环进行操作%d次\n",count);return0;}/*安装n个环*/voidNineRingIn(intn){if(n==1)count++;/*安装1个环,操作数加1*/elseif(n==2)count+=2;/*安装2个环,操作数加2*/else{NineRingIn(n-1);NineRingOut(n-2);count++;/*借助第n-1环将第n环安装,操作次数加1*/NineRingIn(n-2);}}/*卸下n个环*/voidNineRingOut(intn){if(n==1)count++;/*卸下1个环,操作数加1*/elseif(n==2)count+=2;/*卸下2个环,操作数加2*/else{NineRingOut(n-2);count++;/*借助第n-1环卸下第n环,操作次数加1*/NineRingIn(n-2);NineRingOut(n-1);}}【例9-13】在解九连环的过程中,一次安装或解环记为1次操作,请编写程序将安装和解环函数分别写在不同源文件中,统计要完成将九个环安装,需要进行多少次操作。(1)问题分析多文件型程序的设计问题。(2)算法设计结合编译预处理+文件包含+全局变量+递归和九连环算法。使用外部变量【例9-14】若在统计九连环操作中,想在每个步骤精确知道是第几次安装环和第几次解环,又该如何实现呢?(1)问题分析当然,借助之前例子,安装次数和解环次数都使用全局变量定义,各自统计可以完成要求,请读者自行编写程序完成。然而,分析程序可以发现安装次数仅与NineRingIn函数有关,而解环次数仅与NineRingOut函数有关,可以使用静态局部变量完成程序。(2)算法设计结合static变量+递归和九连环算法。使用静态变量#include<stdio.h>voidNineRingIn(intn);voidNineRingOut(intn);voidNineRingIn(intn){

staticintcountIn;/*静态局部变量countIn累计记录安装环的次数*/if(n==1){countIn++;printf("第%d次安装:安装第1环\n",countIn);}elseif(n==2){countIn++;printf("第%d次安装:安装第1环\n",countIn);countIn++;printf("第%d次安装:借助第1环安装第2环\n",countIn);}else{NineRingIn(n-1);NineRingOut(n-2);countIn++;printf("第%d次安装:借助第%d环安装第%d环\n",countIn,n-1,n);NineRingIn(n-2);}}voidNineRingOut(intn){

staticintcountOut;/*静态局部变量countOut累计记录卸下环的次数*/if(n==1){countOut++;printf("第%d次解环:卸下第1环\n",countOut);}elseif(n==2){countOut++;printf("第%d次解环:借助第1环卸下第2环\n",countOut);countOut++;printf("第%d次解环:卸下第1环\n",countOut);}else{NineRingOut(n-2);countOut++;printf("第%d次解环:借助第%d环卸下第%d环\n",countOut,n-1,n);NineRingIn(n-2);NineRingOut(n-1);}}intmain(){NineRingOut(5);return0;}9.5.1指针数组【例9-15】小明总是记不住诗人的生平简介,于是他便写了一个程序实现诗人生平的快速查询。(1)问题分析该问题本身属于字符串检索问题,由于在C语言中并没有提供字符串类型,因此对于大批量字符串处理,可采用指针数组实现,以提高程序效率。(2)算法设计指针数组+顺序查询算法。(3)代码编写程序需要记录诗人的姓名和生平,定义了两个指针数组poet和intro来分别记录诗人姓名和诗人的生平,通过遍历poet数组找到诗人姓名对应的下标,然后输出下标对应的诗人生平简介。9.5案例项目2——考考你的文学常识

使用指针数组#defineM4intmain(){inti;charpoetin[7];char*poet[M]={"李白","杜甫","白居易","王维"};char*intr[M]={"字太白,号青莲居士,浪漫主义诗人,诗仙。","字子美,一生颠沛流离,见证了唐王朝的由盛转衰,诗圣。","字乐天,诗歌体裁广泛,形式多样,语言平易通俗。","字摩诘,崇信佛教,诗中有画,画中有诗,诗佛。"};printf("请输入你要查询的诗人(输入不要有空格):");scanf("%s",poetin);for(i=0;i<M;i++)if(strcmp(poet[i],poetin)==0){printf("%s\n",intr[i]);break;}if(i==M)printf("对不起,你要查询的诗人不在我的记忆中……");return0;}9.5.2命令行参数【例9-16】控制台命令代码实现诗人查询(1)问题分析在编写main函数时,加入命令行参数一般形式为:intmain(intargc,char*argv[])参数argc,整型参数,记录命令行运行时输入的参数个数。参数argv,指针数组参数,记录每个参数的内容。(2)算法设计命令行参数+指针数组+顺序查询算法。(3)代码编写9.5案例项目2——考考你的文学常识

使用命令行参数#include<stdio.h>#include<stdlib.h>#defineM4intmain(intargc,char*argv[]){inti,j;charpoetin[7];char*poet[M]={"李白","杜甫","白居易","王维"};char*intr[M]={"字太白,号青莲居士,浪漫主义诗人,诗仙。","字子美,一生颠沛流离,见证了唐王朝的由盛转衰,诗圣。","字乐天,诗歌体裁广泛,形式多样,语言平易通俗。","字摩诘,崇信佛教,诗中有画,画中有诗,诗佛。",};for(j=1;j<argc;j++){for(i=0;i<M;i++)if(strcmp(poet[i],argv[j])==0){printf("%s:%s\n",poet[i],intr[i]);break;}if(i==M)printf("对不起,你要查询的诗人%s不在我的记忆中……\n");}return0;}9.5.3回调函数【例9-17】要设计一个通用的考试函数,考试的内容并不确定,需要根据情况进行实时扩充,而且扩充考试内容时不需要修改考试函数,该如何设计这个考试系统呢?(1)问题分析主调函数在设计时(本例中exam函数)并不确定需要调用的函数(考试内容函数)内容,将回调函数使用函数指针的形式作为形式参数传递,主调函数编写时,直接调用形参形式的回调函数,而不关心具体调用内容。在使用主调函数时,将需要进一步确定的回调函数以实参形式传入,实现函数回调。9.5案例项目2——考考你的文学常识#include<stdio.h>#include<stdlib.h>voidexam(void(*qz)(void));voidpoem();voidprose();voidci();intmai

温馨提示

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

评论

0/150

提交评论