软件工程(C编码实践篇)学习总结
来源:互联网 发布:淘宝店怎么经营管理 编辑:程序博客网 时间:2024/06/18 09:38
刘思琪 + 原创作品转载请注明出处 + 《软件工程(C编码实践篇)》MOOC课程 http://mooc.study.163.com/course/USTC-1000002006
一、《软件工程(C编码实践篇)》学习心得
学习软件工程可以少走弯路,可以了解一个专业的程序员的工作模式,并且理解学习四个代码质量层次:
1)代码风格规范,易于阅读;
2)封装接口简洁独立;
3)可重用代码;
4)可重入函数和线程安全
(PS:课程的实验环境是网易云课堂的实验楼环境,便于像我这样的git和Linux新手入手学习。不过代码量大时,建议先本地编辑好,再复制到剪切板或直接git到代码库,然后运行--git push。另外,代码规范是评分的重要标准,应严格遵守,可以参考这篇文章《代码规范》https://wenku.baidu.com/view/f76ee2c3b9d528ea81c77969.html)
C编码实践篇主要是从这几个代码质量层次方面入手,以一个menu小程序为切入点,从通用结构,到封装,信息隐藏,接口设计,到回调函数,可重用性和线程安全,抽象等,一步步了解程序模块化设计的过程,在整个实验的过程中,理解了软件工程是对如何构建和开发软件的科学指导性,软件工程设计思想是设计好的程序的坚实的基础。不应仅仅局限于功能的实现。软件 = 程序 + 软件工程 = 数据结构 + 算法
二、《C编码实践篇》六次课程实验报告
该课程一共有七次实验和一次考试,其中第六次实验是测试,不用写实验报告,因此在下面把六次课程实验要求及报告放在下面:
实验一:写一个hello world小程序
实验要求:写一个hello world小程序
- 在实验楼Linux环境使用C语言编写,编译后执行输出”Hello,World!”;
- 实验和实验报告务必在实验楼linux下完成,课程视频是在本地虚拟机上操作的,除了目录环境和作业提交方式不同外,基本的命令和编辑操作方式是一致的。
实验报告:https://www.shiyanlou.com/courses/reports/1270492
实验代码:
#include <stdio.h>int main(){printf("Hello World!\n");}
实验二:命令行菜单小程序V1.0
实验要求:
- 实现一个命令行的菜单小程序,执行某个命令时调用一个特定的函数作- 为执行动作,实现的命令个数不少于8个;
- 类似ftp的help目录或者bash的help目录;
- 程序循环、接收用户的命令,如help、others等命令;
- 可以广泛通用的命令行菜单子系统组件,可方便地定制而嵌入到其他系统;
实验报告:https://www.shiyanlou.com/courses/reports/1271950
实验代码:
#include<stdio.h>#include<stdlib.h>void show();int main(){ char cmd[128]; while(1) { scanf("%s",cmd); if(strcmp(cmd,"hello")==0) { printf("Welcome to my menu ^.^"); } if(strcmp(cmd,"help")==0) { printf("What can I do for you O.O ?"); } if(strcmp(cmd,"show")==0) { show(); } if(strcmp(cmd,"1")==0) { printf("First emoji TAT"); } if(strcmp(cmd,"2")==0) { printf("Second emoji $.$"); } if(strcmp(cmd,"3")==0) { printf("Third emoji >o<"); } if(strcmp(cmd,"4")==0) { printf("Forth emoji ^o^"); } if(strcmp(cmd,"exit")==0) { exit(0); } }}void show(){ printf("***************************\n"); printf("hello:Just welcome\n"); printf("help:Ask for help\n"); printf("show:Show all menu cmd\n"); printf("1:the 1st emoji\n"); printf("2:the 2nd emoji\n"); printf("3:the 3rd emoji\n"); printf("4:the 4th emoji\n"); printf("exit:exit the menu\n"); printf("****************************\n");}
实验三:内部模块化的命令行菜单小程序
实验要求:
- 注意代码的业务逻辑和数据存储之间的分离,即将系统抽象为两个层级:菜单业务逻辑和菜单数据存储
- 要求:1)遵守代码风格规范,参考借鉴代码设计规范的一些方法;2)代码的业务逻辑和数据存储使用不同的源文件实现,即应该有2个.c和一个.h作为接口文件。
实验报告:https://www.shiyanlou.com/courses/reports/1273109
实验代码:
引入链表,实现代码的业务逻辑和数据存储之间的分离1)menu_list.h
#ifndef LINKLIST_H#define LINKLIST_Htypedef struct DataNode{ char* cmd; char* desc; void (*handler)(); struct DataNode* next;}tDataNode;tDataNode* FindCmd(tDataNode* head,char* cmd);void ShowAllCmd(tDataNode* head);#endif
2) menu_list.c
#include<stdio.h>#include<stdlib.h>#include<string.h>#include "menu_list.h"tDataNode* FindCmd(tDataNode* head,char*cmd){ tDataNode* p = head; while((p!=NULL)&&(strcmp(cmd,p->cmd)!=0)) { p=p->next; } return p;}void ShowAllCmd(tDataNode* head){ tDataNode* p=head; while(p) { printf("%s:%s\n",p->cmd,p->desc); p=p->next; }}
3) menu.c
#include<stdio.h>#include<stdlib.h>#include "menu_list.h"void hello();void help();void show();void emoji_1();void emoji_2();void emoji_3();void emoji_4();void quit();tDataNode head[]={ {"hello","Welcome to my menu 2.0",hello,&head[1]}, {"help","What can I do for you O.O ?",help,&head[2]}, {"show","Show all menu cmd",show,&head[3]}, {"emoji_1","the first emoji cmd",emoji_1,&head[4]}, {"emoji_2","the second emoji cmd",emoji_2,&head[5]}, {"emoji_3","the third emoji cmd",emoji_3,&head[6]}, {"emoji_4","the forth emoji cmd",emoji_4,&head[7]}, {"quit","exit the menu cmd",quit,NULL}};int main(){ char cmd[128]; while(1) { scanf("%s",cmd); tDataNode* p=FindCmd(head,cmd); if(p) { p->handler(); } else { printf("the menu doesn't include this cmd!\n"); } } return 0;}void hello(){ printf("Welcome to my menu 2.0 ^.^!\n");}void show(){ ShowAllCmd(head);}void help(){ printf("What can I do for you O.O ? you can press show to find what you want cmd!\n");}void emoji_1(){ printf("First emoji TAT !\n");}void emoji_2(){ printf("Second emoji $.$ !\n");}void emoji_3(){ printf("The third emoji >o< !\n");}void emoji_4(){ printf("The forth emoji ~^o^~ !\n");}void quit(){ exit(0);}
实验四:用可重用的链表模块来实现命令行菜单小程序
实验要求:
- 用可重用的链表模块来实现命令行菜单小程序,执行某个命令时调用一个特定的函数作为执行动作;
- 链表模块的接口设计要足够通用,命令行菜单小程序的功能保持不变;
- 可以将通用的Linktable模块集成到我们的menu程序中;
- 接口规范;
实验报告:https://www.shiyanlou.com/courses/reports/1275007
实验代码:
1)linkable.h
#ifndef _LINK_TABLE_H_#define _LINK_TABLE_H_typedef struct LinkTableNode{ struct LinkTableNode *pNext;}tLinkTableNode;typedef struct LinkTable{ tLinkTableNode *pHead; tLinkTableNode *pTail; int SumOfNode;}tLinkTable;//Create a linktabletLinkTable * CreateLinkTable();//Delete linktableint DeleteLinkTable(tLinkTable * pLinkTable);//Add a linktable nodevoid AddLinkTableNode(tLinkTable * pLinkTable, tLinkTableNode * pNode);//Delete a linktable nodeint DeleteLinkTableNode(tLinkTable * pLinkTable, tLinkTableNode * pNode);//Get link table headtLinkTableNode * GetLinkTableHead(tLinkTable * pLinkTable);//Get next link table nodetLinkTableNode * GetNextLinkTableNode(tLinkTable * pLinkTable, tLinkTableNode * pNode);#endif
2) linkable.c
#include <stdio.h>#include <stdlib.h>#include "linktable.h"tLinkTable * CreateLinkTable(){ tLinkTable * pLinkTable = ( tLinkTable *)malloc(sizeof (tLinkTable)); pLinkTable->pHead = NULL; pLinkTable->pTail = NULL; pLinkTable->SumOfNode = 0; return pLinkTable;}int DeleteLinkTable ( tLinkTable * pLinkTable ){ tLinkTableNode * p; while ( pLinkTable->pHead != pLinkTable->pTail ) { p=pLinkTable->pHead; pLinkTable->pHead = pLinkTable->pHead->pNext; free (p); } free (pLinkTable->pHead); free (pLinkTable);}void AddLinkTableNode ( tLinkTable * pLinkTable , tLinkTableNode * pNode){ if(pLinkTable->pHead == NULL) { pLinkTable->pHead = pNode; pLinkTable->pTail = pNode; pLinkTable->SumOfNode = 1; } else { pLinkTable->pTail->pNext = pNode; pLinkTable->pTail = pNode; pLinkTable->SumOfNode += 1; } }int DeleteLinkTableNode ( tLinkTable * pLinkTable , tLinkTableNode * pNode){ if ( pLinkTable == NULL || pNode == NULL) { return -1; } if(pLinkTable->pHead == pNode) { pLinkTable->pHead == pLinkTable->pHead->pNext; pLinkTable->SumOfNode -= 1; if(pLinkTable->SumOfNode == 0) { pLinkTable->pTail = NULL; } return 0; } tLinkTableNode *p = pLinkTable->pHead; while(p != NULL) { if(p->pNext == pNode) { tLinkTableNode *q = p->pNext->pNext; p->pNext = q; free(q); pLinkTable->SumOfNode -= 1; if(pLinkTable->SumOfNode == 0) { pLinkTable->pTail = NULL; } return 0; } p = p->pNext; } return -1;}tLinkTableNode * GetLinkTableHead( tLinkTable * pLinkTable ){ if(pLinkTable == NULL) { return NULL; } return pLinkTable->pHead;}tLinkTableNode * GetNextLinkTableNode(tLinkTable *pLinkTable, tLinkTableNode *pNode){ if(pLinkTable == NULL || pNode == NULL) { return NULL; } tLinkTableNode *p = pLinkTable->pHead; while(p != NULL) { if(p == pNode) { return p->pNext; } p = p->pNext; } return NULL;}
3) menu.c
#include <stdio.h>#include <stdlib.h>#include <math.h>#include <string.h>#include <ctype.h>#include "linktable.h"#define CMD_MAX_LEN 10int Hello();int Help();int Show();int Emoji();int Ls();int Date();int Author();int Quit();typedef struct DataNode{ tLinkTableNode * pNext; char * cmd; char * desc; int (*handler)();}tDataNode;tDataNode * Findcmd(tLinkTable * head, char * cmd){ tDataNode * pNode = (tDataNode *)GetLinkTableHead(head); while(pNode != NULL) { if(strcmp(pNode->cmd, cmd) == 0) { return pNode; } else { pNode = (tDataNode *)GetNextLinkTableNode(head, (tLinkTableNode *)pNode); } } return NULL;}int ShowAllcmd(tLinkTable * head){ tDataNode * pNode = (tDataNode *)GetLinkTableHead(head); printf("*******************************\n"); while(pNode != NULL) { printf("************\n"); printf("%s - %s\n", pNode->cmd, pNode->desc); pNode = (tDataNode *)GetNextLinkTableNode(head, (tLinkTableNode *)pNode); } return 0;}int InitMenuData(tLinkTable ** ppLinktable){ *ppLinktable = CreateLinkTable(); tDataNode * pNode = (tDataNode *)malloc(sizeof(tDataNode)); pNode = (tDataNode *)malloc(sizeof(tDataNode)); pNode->cmd = "hello"; pNode->desc = "Welcome to my menu 3.0"; pNode->handler = Hello; AddLinkTableNode(*ppLinktable, (tLinkTableNode *)pNode); pNode = (tDataNode *)malloc(sizeof(tDataNode)); pNode->cmd = "help"; pNode->desc = "What can I do for you O.O ?"; pNode->handler = Help; AddLinkTableNode(*ppLinktable, (tLinkTableNode *)pNode); pNode = (tDataNode *)malloc(sizeof(tDataNode)); pNode->cmd = "show"; pNode->desc = "Show all menu cmd"; pNode->handler = Show; AddLinkTableNode(*ppLinktable, (tLinkTableNode *)pNode); pNode = (tDataNode *)malloc(sizeof(tDataNode)); pNode->cmd = "emoji"; pNode->desc = "the emoji expression: TAT $.$ >o< ~^o^~ "; pNode->handler = Emoji; AddLinkTableNode(*ppLinktable, (tLinkTableNode *)pNode); pNode = (tDataNode *)malloc(sizeof(tDataNode)); pNode->cmd = "ls"; pNode->desc = "List all file in this directory"; pNode->handler = Ls; AddLinkTableNode(*ppLinktable, (tLinkTableNode *)pNode); pNode = (tDataNode *)malloc(sizeof(tDataNode)); pNode->cmd = "date"; pNode->desc = "Show the current date"; pNode->handler = Date; AddLinkTableNode(*ppLinktable, (tLinkTableNode *)pNode); pNode = (tDataNode *)malloc(sizeof(tDataNode)); pNode->cmd = "author"; pNode->desc = "the menu 3.0 by Sunday647.L"; pNode->handler = Author; AddLinkTableNode(*ppLinktable, (tLinkTableNode *)pNode); pNode = (tDataNode *)malloc(sizeof(tDataNode)); pNode->cmd = "quit"; pNode->desc = "Exit the menu cmd\n"; pNode->handler = Quit; AddLinkTableNode(*ppLinktable, (tLinkTableNode *)pNode); return 0;}tLinkTable * head = NULL;int main(){ InitMenuData(&head); while(1) { char cmd[CMD_MAX_LEN]; printf("Welcome to my menu 3.0 ^.^ ,please input a cmd-->"); scanf("%s", cmd); tDataNode *p = Findcmd(head, cmd); if(p == NULL) { printf("the menu doesn't include this cmd!\n"); continue; } printf("%s - %s\n", p->cmd, p->desc); if(p->handler != NULL) { p->handler(); } }}int Hello(){ return 0;}int Help(){ return 0;}int Show(){ ShowAllcmd(head); return 0;}int Emoji(){ return 0;}int Ls(){ system("ls"); return 0;}int Date(){ system("date"); return 0;}int Author(){ return 0;}int Quit(){ exit(0);}
实验五:用callback增强链表模块来实现命令行菜单小程序
实验要求:
- 给lab5-1.tar.gz(在实验楼Linux虚拟机环境下~/se_files/目录下)找bug,quit命令无法运行的bug
- 利用callback函数参数使Linktable的查询接口更加通用
- 注意接口的信息隐藏
实验报告:https://www.shiyanlou.com/courses/reports/1276282
实验代码:
本次实验仍由menu.c,linktable.c,linktable.h三个文件组成,均在lab5-1.tar.gz里的源码基础上进行修改。
在实验四的基础上加了一个SearchLinkTableNode接口
关键代码:
/* * Search a LinkTableNode from LinkTable * int Conditon(tLinkTableNode * pNode); */tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int Conditon(tLinkTableNode * pNode)){ if(pLinkTable == NULL || Conditon == NULL) { return NULL; } tLinkTableNode * pNode = pLinkTable->pHead; while(pNode != NULL) { if(Conditon(pNode) == SUCCESS) { return pNode; } pNode = pNode->pNext; } return NULL;}在linktable.h中只写类型声明, 真正的tLinkTable类型定义在linktable.c中,如下图所示
struct LinkTable{ tLinkTableNode *pHead; tLinkTableNode *pTail; intSumOfNode; pthread_mutex_t mutex;};
实验七:将menu设计为可重用的子系统
实验要求:
- 为menu子系统设计接口,并写用户范例代码来实现原来的功能;
- 使用make和make clean来编译程序和清理自动生成的文件;
- 使menu子系统支持带参数的复杂命令,并在用户范例代码中自定义一个带参数的复杂命令;
- 可以使用getopt函数获取命令行参数。
实验报告:https://www.shiyanlou.com/courses/reports/1278241
实验代码:
1) 在实验五的基础上修改menu,c,添加MenuConfig ()和ExecuteMenu()
int MenuConfig(char * cmd, char * desc, void (*handler)(int argc, char *argv[])){ tDataNode* pNode = NULL; if (head == NULL) { head = CreateLinkTable(); pNode = (tDataNode*)malloc(sizeof(tDataNode)); pNode->cmd = "help"; pNode->desc = "Menu List:"; pNode->handler = Help; AddLinkTableNode(head, (tLinkTableNode *)pNode); } pNode = (tDataNode*)malloc(sizeof(tDataNode)); pNode->cmd = cmd; pNode->desc = desc; pNode->handler = handler; AddLinkTableNode(head, (tLinkTableNode *)pNode);}int ExecuteMenu(){ while(1) { int argc = 0; char *argv[CMD_MAX_ARGV_LEN]; char cmd[CMD_MAX_LEN]; char *pcmd = NULL; printf("Input a cmd number > "); pcmd = fgets(cmd, CMD_MAX_LEN, stdin); if (pcmd == NULL) { continue; } pcmd = strtok(pcmd, " "); while (pcmd != NULL && argc < CMD_MAX_ARGV_LEN) { argv[argc] = pcmd; argc++; pcmd = strtok(NULL, " "); } if (argc == 1) { int len = strlen(argv[0]); *(argv[0] + len - 1) = '\0'; } tDataNode *p = FindCmd(head, argv[0]); if( p == NULL) { printf("This is a wrong cmd!\n "); continue; } printf("%s - %s\n", p->cmd, p->desc); if(p->handler != NULL) { p->handler(argc, argv); } }}2) 添加menu.h
#ifndef _MENU_H#define _MENU_Hint MenuConfig(char * cmd, char * desc, void (*handler)(int argc, char *argv[]));int ExecuteMenu();#endif
3) 添加test.h
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <time.h>#include "menu.h"void quit(int argc, char *argv[]);void version(int argc, char *argv[]);void date(int argc, char *argv[]);void quit(int argc, char *argv[]){ exit(0);}void version(int argc, char *argv[]){ printf("Microsoft Windows 10.0.14393\n");}void date(int argc, char *argv[]){ time_t timep; struct tm *p; time(&timep); p=gmtime(&timep); printf("%d\\",1900+p->tm_year); printf("%d\\",1+p->tm_mon); printf("%d\n",p->tm_mday);}int main(int argc,char* argv[]){MenuConfig("version","XXX1.0(Menu program v7.0 inside)",NULL);MenuConfig("quit","Quit the program",quit);MenuConfig("date","Show the date",date);ExecuteMenu();return 0;}
4) Makefile 文件
## Makefile for Menu Program#CC_PTHREAD_FLAGS = -lpthreadCC_FLAGS = -cCC_OUTPUT_FLAGS = -oCC_MATH = -lmCC = gccRM = rmRM_FLAGS = -fTARGET = testOBJS = linktable.o menu.o test.oall: $(OBJS)$(CC) $(CC_OUTPUT_FLAGS) $(TARGET) $(OBJS) $(CC_MATH).c.o:$(CC) $(CC_FLAGS) $<clean:$(RM) $(RM_FLAGS) $(OBJS) $(TARGET) *.bak
注意:makefile文件中all:以及clean:后不要使用空格,应用Tab键,否则会出错,*missing separator. Stop.
三、总结
总结:经过这个课程的学习,在老师的视频指导下,完成了对一个menu命令行小程序从通用结构到模块化、接口、信息隐藏、增量开发、抽象、代码重用等一系列的软件工程过程的实现,同时时刻强调代码规范,提高自己代码的可读性以及效率。通过此次的学习,打破了自己以往局限于功能实现的设计思想,能从系统大局出发,考虑可读性、可扩展性、可重用性等性能因素,并在具体代码中实践,从整体架构出发,提高了自己的代码质量以及效率。另外,通过这门课的学习,我对Linux一些基本的编程命令也有了一些了解。缺点是,自己还是没有扩大思维去做一个大型一点的实际项目,以后需要针对这方面多练习。毕竟实践才能出真知!
最后,感谢孟老师的教导,讲解很细很耐心,谢谢网易云课堂和实验楼,提供这样一个良好的平台和环境,谢谢~
阅读全文
0 0
- 软件工程(C编码实践篇)学习总结
- 软件工程(C编码实践篇)学习总结
- 软件工程(C编码实践篇) 学习总结
- 软件工程(C编码实践篇)学习总结
- 软件工程(C编码实践篇)学习总结
- 软件工程(C编码实践篇)学习总结
- 软件工程(C编码实践篇)学习总结
- 软件工程(C编码实践)学习总结
- 软件工程(C编码实践篇)学习总结
- 软件工程(C编码实践篇)学习总结
- 软件工程(C编码实践篇)学习总结
- 软件工程(C编码实践篇)学习总结
- 软件工程(C编码实践篇)学习总结
- 软件工程(C编码实践篇)学习总结
- 软件工程(C编码实践篇)学习总结
- 软件工程(C编码实践篇)学习总结
- 软件工程(C编码实践篇)学习总结
- 软件工程(C编码实践篇)学习总结
- 程序中调用进程API时进程打开缓慢引起方法调用失败
- JS组件系列——表格组件神器:bootstrap table(三:终结篇,最后的干货福利)
- bzoj 3029: 守卫者的挑战 概率dp
- cordova app 升级
- 简易拼图(OC)
- 软件工程(C编码实践篇)学习总结
- android 高级之旅 (三 )picasso、glide、imageloader等几个常用的图片加载框架
- Web服务器的工作原理
- Inno Setup使用方法备份
- hdoj 1090
- 21款生物信息在线分析工具汇编
- Excel中利用OFFSET函数解决很多个分块的一次性转置问题(非纯手动)
- 深度序列化的一种解决方案
- Python学习笔记1