咖啡机《软件工程(C编码实践篇)》MOOC课程作业http://mooc.study.163.com/course/USTC-1000002006
新创建一个目录lab7完成实验。
getopt()
函数获取命令行参数。在menu.h
添加两个函数MenuConfig()
,ExecuteMenu()
用于添加命令和运行menu程序
/* add cmd to menu */
int MenuConfig(char* cmd, char* desc, int (*handler)(int argc, char *argv[]));
/* Menu Engine Execute */
int ExecuteMenu();
在menu.c
中实现MenuConfig()
函数和ExecuteMenu()
函数
/* Set or configure menu list */
int MenuConfig(char* cmd, char* desc, int (*handler)(int argc, char *argv[]))
{
tDataNode *pNode = NULL;
if(head == NULL)
{
head = CreateLinkTable();
pNode = (tDataNode*)malloc(sizeof(tDataNode));
pNode->cmd = "help";
pNode->desc = "This is the informations of commands";
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);
return 0;
}
/* menu program */
int ExecuteMenu()
{
/* cmd line begins */
while(1)
{
int argc = 0;
char *argv[CMD_MAX_ARGV_NUM];
char cmd[CMD_MAX_LEN];
char *pcmd = NULL;
printf("Input a command> ");
pcmd = fgets(cmd, CMD_MAX_LEN, stdin);
tDataNode *p = FindCmd(head, cmd);
if( pcmd == NULL)
{
continue;
}
pcmd = strtok(pcmd, " ");
while(pcmd != NULL && argc < CMD_MAX_ARGV_NUM)
{
argv[argc] = pcmd;
argc ++;
pcmd = strtok(NULL, " ");
}
if(argc == 1)
{
int len = strlen(argv[0]);
*(argv[0] + len -1) = '\0';
}
tDataNode *pn = (tDataNode*)SearchLinkTableNode(head, SearchCondition, (void*)argv[0]);
if(pn == NULL)
{
printf("This is a wrong cmd!\n");
continue;
}
if(pn->handler != NULL)
{
pn->handler(argc, argv);
}
}
return 0;
}
利用getopt()
获取命令参数,为命令定义不同参数下的不同执行操作。
int Help(int argc,char* argv[])
{
int opt;
while((opt=getopt(argc,argv,"l:a:"))!= -1)
{
switch(opt)
{
case 'a':
printf("this is -a option\n");
ShowAllCmd(head);
break;
case 'b':
printf("this is -b option\n");
break;
default:
printf("Unknowed option %c\n",opt);
}
}
return 0;
}
主要由test.c
承担,调用menu.c
中的接口,添加和调用指令。其中,自定义的指令包括:
- version
- exit
- plus
- minus
- multiply
- divide
#include
#include
#include
#include
#include "linktable.h"
#include "menu.h"
int Exit(int argc, char *argv[])
{
printf("exit the program\n");
exit(0);
}
int Version(int argc, char *argv[])
{
printf("menu program v3.0\n");
}
int plus(int argc, char *argv[])
{
float a,b;
printf("Input two numbers:\n");
scanf("%f", &a);
scanf("%f", &b);
printf("The sum of %f and %f is %f\n", a, b, a+b);
}
int minus(int argc, char *argv[])
{
float a,b;
printf("Input two numbers:\n");
scanf("%f", &a);
scanf("%f", &b);
printf("%f minus %f equals %f\n", a, b, a-b);
}
int multiply(int argc, char *argv[])
{
float a,b;
printf("Input two numbers:\n");
scanf("%f", &a);
scanf("%f", &b);
printf("%f multiply %f equals %f\n", a, b, a*b);
}
int divide(int argc, char *argv[])
{
float a,b;
printf("Input two numbers:\n");
scanf("%f", &a);
scanf("%f", &b);
if ( b == 0)
printf("Error: 0 can not be used as a divisor!\n");
else
printf("%f divided by %f is %f\n", a, b, a/b);
}
int main(int argc, char *argv[])
{
MenuConfig("version", "menu program v3.0", Version);
MenuConfig("plus", "sum of a and b", plus);
MenuConfig("minus", "result of a minus b", minus);
MenuConfig("multiply", "result of a times b", multiply);
MenuConfig("divide", "result of a divided by b", divide);
MenuConfig("exit", "Exit this program", Exit);
ExecuteMenu();
return 0;
}
使用make
和make clean
来编译程序和清理自动生成的文件。
CC_PTHREAD_FLAGS = -lpthread
CC_FLAGS = -c
CC_OUTPUT_FLAGS = -o
CC_MATH = -lm
CC = gcc
RM = rm
RM_FLAGS = -f
TARGET = test
OBJS = linktable.o menu.o test.o
all: $(OBJS)
$(CC) $(CC_OUTPUT_FLAGS) $(TARGET) $(OBJS) $(CC_MATH)
.c.o:
$(CC) $(CC_FLAGS) $<
clean:
$(RM) $(RM_FLAGS) $(OBJS) $(TARGET) *.bak
包括三部分:
- 利用make
指令编译程序
- 执行程序,并利用help -a
、version
、exit
等三个正确指令,quit
一个错误指令进行测试
- 利用make clean
清理程序执行过程中自动生成的文件。
Github地址:https://github.com/973301529/se/tree/master/lab7
通过此次实验,对程序进行了更进一步的可重用设计,学习了Makefile的编写方法,简化了编译命令。