c语言综合程序设计小结,C语言程序设计综合实验

一、题目与运行说明

(1)    题目描述

在当前目录中存在文件名为"case1.in"(其中case后为数字1,不是字母l,写错提交后会判错)的文本文件,其内容为一篇英文文章(以EOF作为结束标志)。现要求读取该文本文件内容,统计文章中每个单词出现的次数,并输出出现次数最多的前5个单词及其出现次数(按出现次数由多到少的顺序输出,次数相同时按字典顺序输出,不足5个单词时,按序输出全部单词)。程序中注意如下细节:

(1)       空格、标点符号与回车符起到分隔单词的作用。

(2)       文章一行的末尾可能有连字符,出现连字符时,该行最末的字符串与下行最先出现的字符串构一个单词;

(3)       名词缩写算一个单词;

(4)       数字不算单词;

(5)       单词不区分大小写;

(6)       输出时单词全使用小写;

(2)    数据输入的形式和输入值的范围

以单个字符逐个录入的方式,在录入字符的同时处理好每个单词,记录在ws[10010][22]。

(3)    数据输出的形式

以printf(“%s %d\n”,单词,计数)的形式输出。

(4)    程序中所使用的主要变量

全局变量:

char ws[10010][22];//录入的单词

int wn=0,cn=0;//wn是录入的单词总数,cn是不同单词的数量(即有cn个互异的单词)

CNT cnt[10001];//CNT结构体{int cnt;char *cp;}用于计数,即单词cp出现了cnt次

函数void read()://按题意格式录入单词

FILE *fp;//FILE结构体,打开文件以便录入

intpre=0,cur,n=0;//pre和cur分别是上一次和当前录入的字符,定义为int是为了处理

fgetc()函数返回的EOF(-1),n表示当前正在录入的单词已经录入了n个字符。

函数void count()://统计不同单词的出现次数(无重要变量)

函数int main()://主函数,无重要变量

(5)    程序所能达到的功能以及出错处理

较好地处理字符以按题意格式录入单词,按字典序排序并计数,最后输出次数最多的5个。

int类型接收fgetc()的返回值,以正常接收EOF。

读入单词后的排序都只交换指针,提高效率。

二、程序设计思路

详见代码注释。

程序流程图如下图所示,

0818b9ca8b590ca3270a3433284dd417.png

三、程序清单

#include

#include

#include

typedef struct {int cnt;char *cp;}CNT;//用于计数,即单词cp出现了cnt次

int IsLt(int c){return ('a'<=c&&c<='z')||('A'<=c&&c<='Z');}//判断是否字母

int IsUp(int c){return 'A'<=c&&c<='Z';}//判断是否大写字母

int ToLw(int c){return IsUp(c)?c+32:c;}//转换为小写

int cmp(const void *a,const void *b){return strcmp(*(char**)a,*(char**)b);}//按字典序比较函数,用于qsort所有单词

int cntcmp(const void *a,const void *b)//将计数排序,先按计数,后按字典序

{

if(((CNT*)b)->cnt!=((CNT*)a)->cnt)return ((CNT*)b)->cnt-((CNT*)a)->cnt;//计数不等

else return strcmp(((CNT*)a)->cp,((CNT*)b)->cp);//计数相同,按字典序比较

}

char ws[10010][22];//录入的单词

char* wp[10010];//记录单词,排序时只交换指针,效率更高

int wn=0,cn=0;//wn是录入的单词总数,cn是不同单词的数量(即有cn个互异的单词)

CNT cnt[10001];//用于计数

void read()//按题意格式录入单词

{

FILE *fp;//FILE结构体,打开文件以便录入

if(!(fp=fopen("case1.in","r")))exit(-1);//打开文件

int pre=0,cur,n=0,i;//pre和cur分别是上一次和当前录入的字符,定义为int是为了处理fgetc()函数返回的EOF(-1),n表示当前正在录入的单词已经录入了n个字符。i是循环变量。

while((cur=fgetc(fp)))//读入一个字符

{

//if(cur=='-'||(pre=='-'&&cur=='\n')){pre=cur;continue;} //如果行中的'-'也算连字符而不是分隔单词

if(cur=='-') //如果行中的'-'不是连字符,而是分隔单词的作用

{

if((cur=fgetc(fp))=='\n')continue;//'-'和'\n'连续在一起,整体忽略

else if(IsLt(cur)){ws[wn][n++]=0;++wn;ws[wn][0]=ToLw(cur);n=1;cur=fgetc(fp);}//'-'后是字母,则是一个新单词的开始(上一个单词结束)

}

if(IsLt(pre)&&!IsLt(cur)){ws[wn][n++]=0;++wn;n=0;}//如果上一个是字母而当前不是字母,则这个单词录入结束(注意EOF我也当成一个读入的用于分隔单词的字符处理,可省去最后一个单词的特判)

if(IsLt(cur))ws[wn][n++]=ToLw(cur);//如果当前是字母,将其转换为小写并插入到单词的待录入位置。

if(cur<0)break;//如果到达文件结束,退出循环

pre=cur;//cur转移到pre

}

fclose(fp);//关闭文件

//把读入的单词的指针记录

for(i=0;i

}

void count()//统计不同单词的出现次数

{

int i;

//预计数一个单词

cn=1;

cnt[0].cnt=1;

cnt[0].cp=wp[0];

for(i=1;i

{

if(!strcmp(cnt[cn-1].cp,wp[i]))++cnt[cn-1].cnt;//如果当前单词未计数完毕(和上一个单词相同),其计数加一

else//和上一个单词不同,则上一个单词计数完毕,开始新单词的计数

{

cnt[cn].cnt=1;

cnt[cn].cp=wp[i];

++cn;

}

}

}

int main()//主函数

{

int i;

read();//按题意格式录入单词到ws[10010][22]

qsort(wp,wn,sizeof(wp[0]),cmp);//按字典顺序排序

count();//计数

qsort(cnt,cn,sizeof(cnt[0]),cntcmp);//把记有不同单词计数信息的cnt数组排序

for(i=0;i

return 0;

}

四、小结(收获和体会)

1、题目难度不大,但是有一点比较“坑”,题目只说“在行末可能有连字符”,而对于行中的‘-’只字未提。如果按照“常理”,行中的’-‘应该也是连字符才对,但是如果严格按照题目,行中的’-‘并不算连字符,而是起分隔单词的作用。

2、分模块编程有助于快速查错,且便于统计与修改。

3、代码风格爽朗,可读性高,算法实现简单高效。

4、计数信息结构体只记录单词指针而不是整个字符串,使排序更高效        5、代码简单简短而可读性高且效率高。(比标程代码长度短、易看懂、耗时短)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值