1、 课程设计说明书 课程名称: 数据结构课程设计 专 业: 电子信息科学与技术 班级: 2012-1 设 计 人: 山 东 科 技 大 学 2015年 7 月 11 日 山 东 科 技 大 学 课 程 设 计 任 务 书 一、 课程设计题目: 简易文本编辑器
2、 二、 设计原始资料: [1] 严蔚敏、吴伟民,数据结构(C语言版)清华大学出版社 2012,05 [2] 孙承爱、赵卫东,程序设计基础—基于C语言 科学出版社 2010,10 三、 设计应解决下列各主要问题: ____1、 具有菜单图形界面; 2、 具有查找、替换、插入、块移动、删除等功能; 3、 可正确存盘、取盘;
3、 4、 正确显示总行数 四、 设计说明书应附有下列图纸: 1、 模块调用图 2、 程序流程图 五、 小组分工说明:
4、 六、命题发出日期: 2015/7/4 _设计完成日期: 2015/7/11 指导教师评语 成绩: 指导教师(签章): 年 月 日 24 山东科技大学学生课程设计 目录 1需求分析说明 2 1.1主函数模块 2 1.2菜单显示及输出子模块
5、2 1.3查找功能子模块 2 1.4替换功能子模块 2 1.5插入功能子模块 3 1.6块移动功能模块 3 1.7删除功能模块 3 1.8读盘功能模块 3 1.9存盘功能模块 3 1.10测试数据 3 2概要设计说明 4 2.1设计思想 4 2.2模块调用图 4 2.3程序代码简介 4 3详细设计说明 7 3.1主函数模块 7 3.2菜单显示及输出子模块 7 3.3查找功能子模块 7 3.4替换子模块 9 3.5插入子模块 10 3.6块移动模块 11 3.7删除模块 12 3.8读盘功能模块 13 3.9存盘功能模块 15 3.10流程图 16
6、 4调试分析 17 4.1遇到的问题 17 4.2测试结果 18 5用户使用说明 22 6课程设计总结 24 1需求分析说明 简易文本编辑器的总体目标:在Visual Studio的开发环境下,利用所学C语言和数据结构的相关知识,开发一个具有良好人机界面的简易文本编辑器,实现对文本的简单修改,从而达到编辑文本以及查看文本信息的目的。 基本功能如下: (1)界面友好,易与操作。采用菜单或其它人机对话方式进行选择。 (2)能正确打开所键入的文本路径,并能够读取相应文本信息。 (3)能对打开的文本进行文本信息显示、替换、查找、块移动、删除等基本操作。 (4)能够正确对修改后
7、的文本内容存盘。 (5)正确显示文本总行数。 以下是各功能模块的功能描述: 1.1主函数模块 主函数模块的主要功能是初始化菜单界面,功能按键选择并调用相关模块,实现软件功能。 1.2菜单显示及输出子模块 菜单显示模块的主要功能是将菜单进行显示,内容包括本设计的主要功能及相关代号。 文本显示模块的主要功能是将所要显示的文本信息通过传入的参量传入本模块进行显示。 输出模块主要功能是输出文本所有信息。 1.3查找功能子模块 本模块的主要功能是通过输入想要查找的文本信息,返回文本中所要查找的文本信息的所处起始位置。 1.4替换功能子模块 本模块的主要功能是将输入的被替换的文本替
8、换为替换的文本信息,并能够显示文本信息。 1.5插入功能子模块 本模块的主要功能是将需要插入的文本信息插入到指定的位置,并能够显示修改后的文本信息。 1.6块移动功能模块 本模块的主要功能是将所要移动的模块移动到指定的相应位置,并能够显示修改后的文本信息。 1.7删除功能模块 本模块的主要功能是删除指定的文本。 1.8读盘功能模块 本模块的主要功能是将存于磁盘内的文件读取,以便后续操作过程中使用。 1.9存盘功能模块 本模块的主要功能是将改变后的文件存于磁盘,以便下次使用。 1.10测试数据: 存于磁盘下的.txt文件(可自己定义)。
9、 2概要设计说明 2.1设计思想 本次设计主要是运用在主模块中的switch,case语句进行调用相关函数实现文本编辑器的基本功能,运用链式存储结构,链式存储结构能够通过结点指针的next值的改变实现插入、替换、移动、删除等一系列操作;通过KMP算法实现查找功能;通过C语言自带的文件操作函数实现文件的读取与存盘等功能。 2.2模块调用图 主模块 块移动模块 插入模块 替换模块 查找模块 删除模块 取盘模块 输出模块 菜单模块 存盘模块 2.3程序代码简介 #define STRING_MAXSIZE
10、256 //定义串的长度 #define ERR_NOMEMORY -1 char source_str[STRING_MAXSIZE]; //将文件内资源以字符串存于此变量 int len; //存储原始字符串的长度 //定义数据存储的结构,以链结构存储 typedef struct LNode{ char data; struct LNode *next; }LNode,*LinkList; LinkList L = 0; //定义全局变量字符串的起始指针 void
11、 menu() //菜单显示函数,显示菜单,无传递参数, //接调用 LinkList Init(char Init_str); //初始化函数,将资源转化为所定义的连//式结构,传入参数为所要初始化的文本,//返回值为LinkList类型的头指针。 int Input(char input_string[]); //插入函数,在默认在文本末尾插入文本,//传入参量为所要插入的文本信息,返回//值为修改后的文本信息。 void Output(); //输出函数,输出文本所包含的信息,无//传入参量,无返回值 int
12、 Search(char search_str[]); //查找函数,查找相应的字符串函数传入//参量为指定的查找文本信息,返回查找//到的参数。 void Replace(char bereplaced_str[],char replace_str[]); //替换函数,替换相应文本信息,传入参//量为被替换的文本信息,以及替换的文//本信息。 void Insert(char insert_str[],int location); //插入函数,在指定位置插入指定信息,//传入参量为需要插入的文本信息,以及//插入的相关位置。 voi
13、d Move(char bemoved_str[],int location); //块移动函数,将文本信息中的指定信息//移动到指定位置,传入参量为需要移动//的文本块以及指定的移动位置。 void Delete(char delete_str[]); //删除函数,删除相应的文本信息,传入//参数为指定的被删除的文本 void Display(int len_dis); //显示函数,传入参量为所要显示的文本//长度。 void save(); //存盘函数,将所改变的文本存入到磁盘//中,无传入参数,无返回参数 void delay(
14、); //延时函数 int StringLength( LinkList S ); //求串长函数,传入参数为要求的串的长//度,返回参数为文本的长度 void statistics(); //统计行数,无传入参数,无返回值。 void KMPGetNext(char *T,int n2,int nextval[]); int KMPIndex(char *S,int n1,char *T,int n2); //KMP算法,求文本的位置 3详细设计说明 3.1主函数模块 主函数模块的主要功能是调用men
15、u函数初始化菜单界面,并调用Openfile函数将存于本地磁盘内的文件读出到source_str[]数组中以备后续调用,并在将字符数组初始化为链表之后进入功能按键选择,通过switch 语句进行相应的功能操作并调用相关模块,实现软件功能。 3.2菜单显示及输出子模块 菜单显示模块的主要功能是将菜单进行显示,本模块调用menu函数,menu函数由printf函数进行格式的输出,并通过system()函数进行颜色的改变,以及清屏等操作,主要输出内容包括本设计的介绍、小组信息、主要功能及相关代号。 输出模块主要功能是输出文本内容以及总行数,主要是调用Output函数和statistics函数将
16、文本基本信息进行打印。Output函数主要是将changed_source_str字符数组进行输出打印,changed_source_str字符数组是存储操作后的source_str字符数组;statistics函数主要是统计文本中换行和结束符的个数,并输出打印count。 3.3查找功能子模块 本模块的主要功能是通过调用Search函数实现基本功能,Search函数通过读入用户输入的想要查找的文本信息,通过调用KMP算法函数返回文本中所要查找的文本信息的所处起始位置search_loc,若找不到子串,则返回-1。 获取子串的next函数如下: void KMPGetNext(char
17、 *T,int n2,int nextval[])
//求子串T的next函数修正值并存入数组nextval
{
int j=1,k=0;
nextval[0]=-1;
while(j 18、KMP算法如下:
int KMPIndex(char *S,int n1,char *T,int n2)
//利用子串T的next函数求T在主串S中的位置
{
int i=0,j=0;
int *next=(int *)malloc(n2*sizeof(int));
if(!next) return ERR_NOMEMORY ;
KMPGetNext(T,n2,next);
while(i 19、
j++;
}
else //模式串向右移动
j=next[j];
}
free(next);
return (j>=n2?i-n2:-1);
}
Search函数的描述如下:
int Search(char search_str[])
{
char s[STRING_MAXSIZE];
int i=0;
int search_loc,search_len,s_len;
LNode *p;
p=L->next;
while(p) //获取修改后的文 20、本信息
{
s[i++]=p->data;
p=p->next;
}
s_len=strlen(s);
search_len=strlen(search_str);
if(search_len <= s_len)
{
search_loc = KMPIndex(s,s_len,search_str,search_len); //利用KMP算法获取查找的位置
return search_loc;
}
else
{
return -1; //未找到
}
}
3.4替换子模块
本模块的主要调用Replace函将 21、输入的被替换的文本转换为替换的文本信息,并显示文本信息。Replace函数通过调用for循环得到被替换的文本的前一节点的指针*p,以及被替换文本的后一节点的指针*s,调用Init函数使替换文本初始化为连式存储并返回此链的头节点指针存于*w,for循环得到替换文本最后一位节点的指针*w。通过指针的操作将被替换的文本卸下,并连接替换文本组成新链。最终打印输出此链。
具体的实现函数如下:
int Replace(char replaced_str[],char replace_str[])
{
int j=0;
int replaced_str_loc,replaced_str_len 22、reped_len,source_str_len;
LNode *p,*s,*z,*w;
replaced_str_len = strlen(replaced_str); //被替换的字符的长度
reped_len = strlen(replace_str); //需要替换的字符的长度
source_str_len = strlen(source_str); //主串字符的长度
replaced_str_loc = Search(replaced_str); //被替换的字符的位置
if(replaced_str_loc != -1)
{
23、 LTmp = Init(replace_str);
p = L;
s = L;
z = LTmp->next;
w = LTmp;
for(j = 0; j < replaced_str_loc;j++)
p = p->next;
for(j = 0; j < (replaced_str_loc + replaced_str_len);j++)
s = s->next;
for(j = 0; j < reped_len;j++)
w = w->next;
p->next = z;
w->next = s->next 24、
Display();
return 0;
}
else
{
printf("**************************************\n");
printf("* 主银!!您所被替换的文本不存在哦~~*\n");
printf("**************************************\n");
}
}
3.5插入子模块
本模块的主要通过调用Insert函数实现基本功能。Insert函数是将需要插入的文本信息插入到指定的位置,并显示修改后的文本信息。此函数采用边生成新节点边插入的方式完成,通过w 25、hile循环得到插入位置的指针*p,将插入文本的第i位赋值给新生成的结点s->data,p的next指向新生成的结点s,依次循环直到将整个文本插入完成。
具体的实现函数如下:
void Insert(char insert_str[],int location)
{
int i,j,len_ins,source_str_len;
LNode *p,*s;
len_ins = strlen(insert_str);
source_str_len = strlen(source_str);
if((location <= source_str_len)&&(locatio 26、n >= 0))
{
p=L;
j=0;
for(i=0;i 27、ns;
Display();
}
else
{
……
}
}
3.6块移动模块
本模块的主要通过调用Move函数实现基本功能,Move函数将所要移动的模块移动到指定的相应位置,并显示修改后的文本信息。Move函数通过改变next值来实现移动的目的。思想类似于Replace函数,首先得到块的前一位结点的指针*p,块最后一位节点的指针,要移动位置的指针*w,通过结点的next值得改变得到新链,打印输出。
具体函数如下:
void Move(char bemoved_str[],int location)
{
int j,bemoved_str_loc 28、 = 0,bemoved_str_len = 0,source_str_len;
LNode *p,*s,*w,*temp;
bemoved_str_loc = Search(bemoved_str) + 1;
bemoved_str_len = strlen(bemoved_str);
source_str_len = strlen(source_str);
if((bemoved_str_loc) > 0)
{
if((location <= source_str_len)&&(location >= 0))
{
p = L;
s = L 29、
w = L;
for(j = 0; j < bemoved_str_loc-1;j++)
{
p = p->next;
}
temp = p->next;
for(j = 0; j < (bemoved_str_loc + bemoved_str_len-1);j++)
s = s->next;
for(j = 0; j < location;j++)
w = w->next;
p->next = s->next;
s->next = w->next;
w->next = 30、temp;
Display();
}
else
{
……;
}
}
else
{
……;
}
}
3.7删除模块
本模块的主要通过调用Delete函数实现基本功能,Delete函数是删除指定的文本。并输出打印操作完成后的结果。Delete函数通过调用Search函数得到待删除文本的位置,并通过while循环得到待删除文本的前一个结点的位置指针*q和待删除文本的后一个结点的位置指针*p(如遇到换行符则将*p指针向后移动一位。),将*q的next值指向*p即得到删除后的文本。最后打印输出。
具体实现函数如下:
void D 31、elete(char delete_str[])
{
int loc; //记录要删除的文本的位置
int i,j=0;
int len_del;
LNode *p,*q;
p=L;
len_del=strlen(delete_str);
loc=Search(delete_str)+1;
if((loc - 1) >= 0)
{
for(i=0;i 32、next;
j++;
}
q=p->next; //删除结点
if(q->next->data== 10)
q=q->next;
p->next=q->next;
}
len=strlen(source_str)-len_del;
Display();
}
else
{
……;
}
}
3.8读盘功能模块
本模块的主要通过调用OpenFile函数实现基本功能,OpenFile函数主要实现将存于磁盘内的文件读取,以便后续操作过程中使用。OpenFile函数以只读的方式调用fopen函数读取文 33、本内容并存于字符数组source_str中,存储完后通过fclose函数将其关闭。
函数实现如下
void OpenFile()
{
char ch,meng[33];
int i = 0,flag = 1,copy_num;
FILE *fp1;
printf("你猜你要输入什么样儿滴文本路径(我看这个不错f:\\1.txt) \n");
scanf("%s",way);
if( (fp1 = fopen(way,"r")) == NULL)
{
while(flag)
{
printf("总统大人,您的文件不在磁盘里呢,是不是在U盘 34、再¨来一遍!\n");
scanf("%s",way);
fp1 = fopen(way,"r");
if(fp1 != NULL)
flag = 0;
else
flag = 1;
}
}
if( (fp1 = fopen(way,"r")) != NULL)
{
while(!feof(fp1))
{
ch = fgetc(fp1);
source_str[i++] = ch;
}
source_str[i] = '\0';
for(i = 0;i < strlen(sou 35、rce_str)-1;i++)
source_str[i] = source_str[i];
source_str[i] = '\0';
for(copy_num = 0;copy_num < STRING_MAXSIZE;copy_num ++)
changed_source_str[copy_num] = source_str[copy_num];
printf("我已经把他印在脑海里了!给你看下一个画面,不要捉急...\n");
delay();
fclose(fp1);
system( "cls" ) ;
menu();
} 36、
}
void delay()
{
int i,j;
for(i = 0;i < 55000;i++)
for(j = 0;j < 11000;j++);
}
3.9存盘功能模块
本模块的主要通过调用save函数实现基本功能,save函数是将改变后的文件存于磁盘,以便下次使用。Save函数以写的方式调用fopen函数打开源文件,并调用fprintf函数将改变的字符数组changed_source_str写入到其中。最后,调用fclose函数关闭本文件。
函数实现如下
void save()
{
FILE * fp2;
fp2=fopen(way, 37、"w");
fprintf (fp2,"%s",changed_source_str);
fclose (fp2);
}
3.10流程图
4调试分析
4.1遇到的问题
l 文本在改变后不能输出功能不能正确执行
打印的还是没有编辑过的前文本内容。分析发现在供打印输出的字符数组没有被及时的更新,因此每次都是显示原始的信息,这就会使退出时不能将编辑过的文本正确保存。
解决方法:在Display函数里将编辑过的文本重新赋值到全局变量的字符数组changed_source_str中,此问题得到解决。
l 执行查找功能时,输出错误信息
如在含有 38、abcdefgh”字符的文本中查找“a”输出为“第一位”;而在查找“ad”时理论上应输出“无此文本”而输出“第一位”。分析可知,原来的编程思想是不对的,原本的方法只是匹配第一个字符,便输出。以至于其他功能调用Search函数时导致功能缺失。
解决方法:换用KMP算法进行模式匹配,最终得到正确结果。
l 块移动时不能正确替换
块移动时,会出现多移动一个字符的情况。讨论发现在使用strlen函数时多加了1,导致指针向后移了一个节点。
解决方法:将多加的1去掉。
l 替换时乱码
执行替换功能时替换文本第一位不能正确显示,出现乱码。分析发现,调用Init函数时返回替换文本转化为链式存储时 39、第一个指针*LTmp为头指针,无data,所以乱码。
解决方法:将指向替换文本的第一个节点的指针z = LTmp->next,
即可解决问题。
l 在输入功能前代号时不小心输入为字符时,程序乱飞。
当提示输入功能代号时,不小心输入成了字符‘p’此时程序跑飞,且不能停止。分析发现case语句中定义了num为int类型,当输入字符时,导致程序不能正确执行。
解决方法:将num定义为字符数组类型,在case中判断case[0]位是否为字符‘1’‘2’等。
4.2测试结果
打开文件功能测试如下:
输出功能及查找功能测试如下:
替换功能测试如下:
插入功能测试如下 40、
块移动功能测试如下:
删除功能测试如下:
退出前是否保存功能测试如下:
5用户使用说明
打开可执行程序后进入打开磁盘源文件的窗口,输入正确的文件位置,回车等待2秒进入功能选择窗口。
进入编辑功能菜单,如需操作键入相应的功能前代号即可。
编辑功能使用示例:
请注意在使用本软件时遇到“继续XXX ? 1/0”时,1表示继续,0表示停止使用此功能,并会自动清屏(本软件略萌,请谨慎使用)。
6课程设计总结
本次设计是由我和我的队友xxxx一块完成,由于平时对C的练习不是很多,所以花费了不少时间,一直到调试到周五。通过本次设计真正的认识了链式存储,以及KMP算法,越来越发现知识运用起来才有意思。虽然本设计还有些瑕疵,不过看着这650多行的代码,程序能按照自己的想法来运行。心里还是有些许成就感的。






