1、23模块化程序设计步骤模块化程序设计步骤问题定义问题定义算法设计算法设计流程图设计流程图设计编写程序代码编写程序代码测试与调试测试与调试41 1 问题定义问题定义根据用户提出的问题,认真分析,并明确需要做什么,然后给出清晰、准确的问题描述根据用户提出的问题,认真分析,并明确需要做什么,然后给出清晰、准确的问题描述和功能要求。在问题描述中还需要给出解决问题中的输入、结果的输出等问题。和功能要求。在问题描述中还需要给出解决问题中的输入、结果的输出等问题。5问题定义问题定义本系统应具备以下功能:本系统应具备以下功能:创建通讯录创建通讯录显示通讯录内容显示通讯录内容按字段查询通讯录按字段查询通讯录修改
2、通讯录中的指定记录修改通讯录中的指定记录添加通讯录记录添加通讯录记录删除通讯录中的指定记录删除通讯录中的指定记录对通讯录中的记录按字段进行排序对通讯录中的记录按字段进行排序 (升序、降序)(升序、降序)62 2 算算 法法 设设 计计算法:为了解决某一个问题而建立的计算机求解的步骤。算法:为了解决某一个问题而建立的计算机求解的步骤。在设计一个较大问题的算法时,应采用模块化的程序设计方法,即将较大的任务按照一在设计一个较大问题的算法时,应采用模块化的程序设计方法,即将较大的任务按照一定的原则分为较小的任务,然后分别设计各个小任务。需要注意的是划分出来的模块应该相对独定的原则分为较小的任务,然后分
3、别设计各个小任务。需要注意的是划分出来的模块应该相对独立但又相关,而且容易理解。立但又相关,而且容易理解。7模块图一般从上到下进行,而且最上面一层的模块是主模块,下面的各层模块是其上一层模块模块图一般从上到下进行,而且最上面一层的模块是主模块,下面的各层模块是其上一层模块的逐步细化的逐步细化2.1 2.1 算算 法法 设设 计计-模块图模块图82.2 2.2 算法设计算法设计数据结构数据结构根据用户以及通讯录的一般情况,可以假定通讯录中每条记录包括以下三项:学号学号 姓名姓名 电话号码电话号码9算法设计算法设计为实现上述记录的存储,必须定义一种数据结构来完成任务。为实现上述记录的存储,必须定义
4、一种数据结构来完成任务。可以使用结构体数组来实现。可以使用结构体数组来实现。struct studentstruct student char num10;char num10;char name10;char name10;char tel10;char tel10;102.3 2.3 算法设计算法设计菜单设计菜单设计112.42.4算法设计算法设计各功能模块(函数)设计各功能模块(函数)设计创建通讯录函数创建通讯录函数mycreat()mycreat()算法步骤:算法步骤:输入学生的学号、姓名和电话,并将这些信息保存在结构体数组中。输入学生的学号、姓名和电话,并将这些信息保存在结构体数组中
5、。每输入一组数据,记录数加每输入一组数据,记录数加1 1。12算法设计算法设计各功能模块(函数)设计各功能模块(函数)设计根据实际记录条数,使用循环将结构体数组中的各个元素按照一定的格式依次输出到屏幕。根据实际记录条数,使用循环将结构体数组中的各个元素按照一定的格式依次输出到屏幕。显示通讯录函数显示通讯录函数mydisplay()mydisplay()13算法设计算法设计各功能模块(函数)设计各功能模块(函数)设计按学号查询按姓名查询if(按学号查询)调用按学号查询函数sch_num()else if(按姓名查询)调用按姓名查询函数sch_name()else 显示非法选项的信息查询通讯录函数
6、查询通讯录函数mysearch()mysearch()14输入需修改记录的学号;使用循环在结构体数组中查找到该学号的元素;将输入的新数据替代原有数据。算法设计算法设计各功能模块(函数)设计各功能模块(函数)设计修改通讯录函数修改通讯录函数mymodify()mymodify()15输入一个新学号及其它相关信息;判断输入的学号在数组中是否存在;若不存在,再将输入的信息添加到结构体数组中,记录数加1;若存在,则需重新输入学号。算法设计算法设计各功能模块(函数)设计各功能模块(函数)设计添加通讯记录函数添加通讯记录函数myadd()myadd()16按学号删除按学号删除按姓名删除按姓名删除if(按学
7、号删除按学号删除)调用按学号删除的调用按学号删除的del_num函数函数else if(按姓名删除按姓名删除)调用按姓名删除的调用按姓名删除的del_name函数函数else 显示非法选项的信息显示非法选项的信息算法设计算法设计各功能模块(函数)设计各功能模块(函数)设计删除通讯录记录函数删除通讯录记录函数mydelete()mydelete()17按学号排序按学号排序按姓名排序按姓名排序if(if(按学号排序按学号排序)调用按学号排序的调用按学号排序的sort_numsort_num函数函数else if(else if(按姓名排序按姓名排序)调用按姓名排序的调用按姓名排序的sort_nam
8、esort_name函数函数else else 显示非法选项的信息显示非法选项的信息算法设计算法设计各功能模块(函数)设计各功能模块(函数)设计通讯录记录排序函数通讯录记录排序函数mysort()mysort()183 3 流程图设计流程图设计流程图常用符号流程图常用符号19流程图设计流程图设计-主函数(主函数()20流程图设计流程图设计21流程图设计流程图设计-mycerat()-mycerat()与与mydisplay()mydisplay()函数函数22流程图设计流程图设计 -mysearch()-mysearch()函数函数23流程图设计流程图设计sch_numsch_num()的流程
9、()的流程sch_namsch_nam()的流程()的流程24流程图设计流程图设计 -mymodify()-mymodify()函数函数2526流程图设计流程图设计 -myadd()-myadd()函数函数27流程图设计流程图设计 -mydelete()-mydelete()函数函数28流程图设计流程图设计 del_num()del_num()函数函数29流程图设计流程图设计 mysort()mysort()函数函数30流程图设计流程图设计 sort_name()sort_name()函数函数314 4 编写程序代码编写程序代码使程序具有良好的程序设计风格。使程序具有良好的程序设计风格。合理安
10、排各成分的位置。一般合理安排各成分的位置。一般#include#include命令行在程序的最前面,接着依次为命令行在程序的最前面,接着依次为#define#define命令命令行、类型声明(如结构体类型声明)、函数原型、各函数等。行、类型声明(如结构体类型声明)、函数原型、各函数等。适当加注释。一般在程序的开头加注释解释本程序的功能和一些说明,在函数或程序段适当加注释。一般在程序的开头加注释解释本程序的功能和一些说明,在函数或程序段的开头加注释解释其要实现的功能、算法、参数等,在变量的定义行后面解释该变量的的开头加注释解释其要实现的功能、算法、参数等,在变量的定义行后面解释该变量的用途等。用
11、途等。程序中适当加上空行。在命令行和类型声明之间、类型声明和函数原型之间、函数原型程序中适当加上空行。在命令行和类型声明之间、类型声明和函数原型之间、函数原型与函数定义之间、函数内部变量定义与其下执行语句之间均空一行,有些地方视情况可与函数定义之间、函数内部变量定义与其下执行语句之间均空一行,有些地方视情况可空两行。空两行。32编写程序代码编写程序代码使程序具有良好的程序设计风格。使程序具有良好的程序设计风格。采用缩进格式。一般用采用缩进格式。一般用TabTab键将某些行向右缩格,这样可使程序的逻辑结构更加清晰,键将某些行向右缩格,这样可使程序的逻辑结构更加清晰,层次分明,显著提高程序的可读性
12、。层次分明,显著提高程序的可读性。标识符要见名知意。可用英文单词、拼音或缩写作为标识符的一部分。一般标识符的第标识符要见名知意。可用英文单词、拼音或缩写作为标识符的一部分。一般标识符的第一个字符用小写字母,其余的字符用小写字母、数字或下划线。一个字符用小写字母,其余的字符用小写字母、数字或下划线。一行写一条语句。一行写一条语句。算法简单明了。尽量采用简单易懂的算法,不使用过分复杂的算法。算法简单明了。尽量采用简单易懂的算法,不使用过分复杂的算法。33编写程序代码编写程序代码用户界面友好。一般使用计算机解决问题时,采用人机对话形式。当要求用户输入数据时,给出提示信息,而且输入格式要一致,如果用户
13、误操作,输入的数据有错误,则应进行相应的处理,保证软件不崩溃(即使程序具有健壮性)。输出数据时适当控制输出格式,使显示的数据清晰、美观,当然可以设计图形用户界面。风格好的程序清晰、易懂,对程序的调试和维护将带来很大方便。需要注意的是在编写代码时,风格好的程序清晰、易懂,对程序的调试和维护将带来很大方便。需要注意的是在编写代码时,应时刻注意程序设计风格。应时刻注意程序设计风格。34编写程序主函数编写程序主函数一般情况下,都是在主函数中调用其他功能函数。为了能够测试主函数,可在调用函数的一般情况下,都是在主函数中调用其他功能函数。为了能够测试主函数,可在调用函数的位置处先用空函数占位。每编写好一个
14、函数,再用相应的调用语句取代对应的空函数。位置处先用空函数占位。每编写好一个函数,再用相应的调用语句取代对应的空函数。35编写程序编写程序myprint()myprint()函数函数此函数不需要传递参数,也不需要再定义任何变量。此函数不需要传递参数,也不需要再定义任何变量。函数首部:函数首部:void myprint()void myprint()36编写程序编写程序mycreat()mycreat()函数函数该函数需要 个参数:2 2struct student类型的指针,指向存放学号、姓名、电话号码的数组;int型指针,用于统计记录个数。void mydisplay(struct stud
15、ent void mydisplay(struct student*p,int n)p,int n)37编写程序编写程序mydisplay()mydisplay()函数函数struct student struct student 类型的指针,指向存放学号、姓名、电话号码的数组。类型的指针,指向存放学号、姓名、电话号码的数组。intint型变量,用于接受实参传递的记录个数。型变量,用于接受实参传递的记录个数。该函数需要 个参数:2 238编写程序编写程序mysearch()mysearch()函数函数该函数需要 个参数:2 2struct student类型的指针,指向存放学号、姓名、电话号码
16、的数组;int型变量,用于接受实参传递的记录个数。void mysearch(struct student void mysearch(struct student*p,int n);p,int n);void sch_num(struct student void sch_num(struct student*p,int n);p,int n);void sch_name(struct student void sch_name(struct student*p,int n);p,int n);39编写程序编写程序mymodify()mymodify()函数函数该函数需要 个参数:2 2st
17、ruct student类型的指针,指向存放学号、姓名、电话号码的数组;int型变量,用于接受实参传递的记录个数。void mymodify(struct student void mymodify(struct student*p,int n);p,int n);40编写程序编写程序myadd()myadd()函数函数该函数需要 个参数:2 2struct student类型的指针,指向存放学号、姓名、电话号码的数组;int型指针,用于统计记录个数。void myadd(struct student void myadd(struct student*p,int p,int *n);n);4
18、1编写程序编写程序mydelete()mydelete()函数函数该函数需要 个参数:2 2struct student类型的指针,指向存放学号、姓名、电话号码的数组;int型指针,用于统计记录个数。void mydelete(struct student void mydelete(struct student*p,int p,int *n);n);void del_num(struct student void del_num(struct student*p,int p,int *n);n);void del_name(struct student void del_name(struc
19、t student*p,int p,int *n);n);42编写程序编写程序mysort()mysort()函数函数该函数需要 个参数:2 2struct student类型的指针,指向存放学号、姓名、电话号码的数组;int型变量,用于接受实参传递的记录个数。void mysort(struct student void mysort(struct student*p,int n);p,int n);void sort_num(struct student void sort_num(struct student*p,int n);p,int n);void sort_name(struct
20、 student void sort_name(struct student*p,int n);p,int n);435 5 测试与调试测试与调试测试是通过运行程序发现错误的过程,常见的错误有数据溢出、数组越界、进入死循环、语测试是通过运行程序发现错误的过程,常见的错误有数据溢出、数组越界、进入死循环、语句顺序颠倒、顺手多加句顺序颠倒、顺手多加“;”或粗心少加或粗心少加“”等,而调试则是确定测试中找到的错误性质,并改正错等,而调试则是确定测试中找到的错误性质,并改正错误的过程。测试与调试通常交替进行。误的过程。测试与调试通常交替进行。测试测试调试调试再测试再测试再调试。再调试。44测试与调试测
21、试与调试能暴露出尚未发现的、各种不同类型错误的测试才是成功的测试。测试程序需要测试用能暴露出尚未发现的、各种不同类型错误的测试才是成功的测试。测试程序需要测试用例,测试用例可用如下公式表示:例,测试用例可用如下公式表示:测试用例测试用例=测试数据测试数据+预期结果预期结果45测试与调试程序测试与调试程序 测试与调试的首要工作是,用合适的测试用例检查程序的正确性和完整性。按照题目的具体情况,在需要输入数据的地方,选定两大类的测试数据:一类为合法数据,用来测试程序的正确性和完整性。一类为非法数据,用来测试程序的容错能力和健壮性。46测试步骤测试步骤模块测试:就是分别对各个模块进行的测试的过程。在编
22、写一个模块后应立即对其进行测试,因为这时模块测试:就是分别对各个模块进行的测试的过程。在编写一个模块后应立即对其进行测试,因为这时对该模块记忆深刻,而且一个模块相对小,所以容易构造测试数据,能方便地检查和改正错误。对该模块记忆深刻,而且一个模块相对小,所以容易构造测试数据,能方便地检查和改正错误。组装测试:就是把所有模块(应该是已通过模块测试的模块)按预先制定的计划逐步组装和测试的过程。一般情况下,各模块之间要相互传递数据和控制信息,因此组装测试的主要任务是发现模块接口中的错误。确认测试:是测试的最后一个步骤,一般将软件交付用户之前,确认是否确实满足用户要求,通常使用确认测试:是测试的最后一个
23、步骤,一般将软件交付用户之前,确认是否确实满足用户要求,通常使用接近实际的用例。接近实际的用例。47通讯录程序中的菜单通讯录程序中的菜单需要输出主菜单选择界面;需要输出主菜单选择界面;菜单应根据用户的选择做出不同反应;菜单应根据用户的选择做出不同反应;具有重复选择主菜单选项的功能(使用循环结构);具有重复选择主菜单选项的功能(使用循环结构);为用户提供程序正常结束的出口。为用户提供程序正常结束的出口。48附:主菜单的制作方法附:主菜单的制作方法49主菜单的制作主菜单的制作本例需要输出主菜单界面,简单菜单的制作可使用本例需要输出主菜单界面,简单菜单的制作可使用printf函数实现。函数实现。用用
24、printf函数将菜单项逐一打印到屏幕上,界面中的边框可通过函数将菜单项逐一打印到屏幕上,界面中的边框可通过printf函数输出的函数输出的“|”|”和和“-”-”拼接起来。拼接起来。菜单应根据用户的选项做出不同的反应,因此,需要使用分支结构实现选择的功能。本菜单应根据用户的选项做出不同的反应,因此,需要使用分支结构实现选择的功能。本例使用例使用switch语句最为合适。语句最为合适。50主菜单的制作主菜单的制作因为本例具有重复选择主菜单选项的功能,所以一定要使用循环结构。因为本例具有重复选择主菜单选项的功能,所以一定要使用循环结构。由于主菜单至少要显示由于主菜单至少要显示1 1次,所以使用次
25、,所以使用do-whiledo-while循环较好。循环较好。菜单还要给用户一个正常的出口,即满足一定条件时退出循环。菜单还要给用户一个正常的出口,即满足一定条件时退出循环。当用户选择某一菜单后,系统立即完成相应的操作,然后询问是否需要继续,当用户选择某一菜单后,系统立即完成相应的操作,然后询问是否需要继续,并根据用户输入的信息(并根据用户输入的信息(Y/y,N/nY/y,N/n),使主菜单反复出现或退出主菜单。),使主菜单反复出现或退出主菜单。5152getchar()getchar()、getch()getch()与与getche()getche()调用调用getchar()时,用户输入的字符显示在屏幕上,而且要等待用户输入回车符后才运行。时,用户输入的字符显示在屏幕上,而且要等待用户输入回车符后才运行。调用调用getch()时,用户输入的字符不显示在屏幕上,而且不等待用户输入回车就运行。时,用户输入的字符不显示在屏幕上,而且不等待用户输入回车就运行。调用调用getche()时,用户输入的字符显示在屏幕上,也不等待用户输入回车就运行。时,用户输入的字符显示在屏幕上,也不等待用户输入回车就运行。53基本语句的使用基本语句的使用一般情况下,菜单都是分级嵌套在一起的。在菜单设计中除了要考虑怎样从主菜单进入子菜单,还要考虑如何从子菜单逐级返回主菜单。菜单的制作菜单的制作