1、 C语言课程设计说明书 题目: 长整型数四则运算 学 院: 班 级: 学 生: 学 号: 班内序号: 提交日期: 年 月 日 目 录 一、需求分析 1 二、设计思
2、绪 1 三、具体设计 2 1、关键函数 2 2、函数关键调用关系图 3 四、调试分析及编程心得体会 3 五、用户手册 3 六、测试结果 3 七、源程序代码 4 1、 main.c 主控文件 4 2、IntFace.h 程序界面模块头文件 5 3、IntFace.c 程序界面处理模块文件 6 4、LongInt.h 长整型数输入输入及运算模块头文件 9 5、LongIO.c 长整型数输入输出处理模块文件 9 6、LongInt.c 长整型数运算处理模块文件 11 7、DuCiLink.h 双向循环链表处理模块头文件 16 8、DuCiLink.c 双向循环链表处理模
3、块代码 17 一、需求分析 1、 设计一个实现任意长整数进行四则运算程序。 2、 输入和输出形式是按中国对于长整数表示习惯,每四位一组,组间用逗号隔开,长整数位数没有上限,以分号结束长整型数据输入。 3、 程序实施命令包含: 1)、输入长整数1;2)、输入长整数2;3)、输入实施运算符;4)、计算并输出结果;5)、结束。 4、测试数据:(以加法为例) (1)、0;0;+;应输出“0”。 (2)、-2345,6789;-7654,3211;+;应输出“-1,0000,0000”。 (3)、-9999,9999;1,0000,0000,0000;+;应输出“9999,00
4、00,0001”. (4)、1,0001,0001;-1,0001,0001;+;应输出“0”. (5)、1,0001,0001;-1,0001,0000;+;应输出“1”。 (6)、-9999,9999,9999;-9999,9999,9999;+;应输出“-1,9999,9999,9998”. (7)1,0000,9999,9999;1;+;应输出“1,0001,0000,0000”. 二、设计思绪 我们首先要考虑是怎样表示长整型数。根据传统习惯要求每4位数形成1组,而一个长整型数可能会有很多组这种4位数,而每节之间是有前后次序,所以我们能够考虑用数组和链表来存放数据。(1)再
5、考虑到每个长整型数长度在输入之间是无法预知,所以使用链表在存放空间分配上更方便部分。(2)在输入数据时总是从高位到低位地存放,而计算时总是从低位向高位运算,(这么话栈也很方便)所以采取双向链表更方便,而为了从头结点方便地转到尾结点能够采取循环链表。总而言之,为了实现上述功效,应以双向循环链表表示长整数,每个结点含一个整型变量,且仅绝对值不超出9999整数,整个链表用十进制数表示。(3)对于每一个长整型数能够设置一个头结点,其中数据域用来表示该长整型数正负号及组数,该值符号则表示该长整型数符号,该数绝对值表示该长整型数包含4位数组数。第一个存放4位数据组结点称为首结点,而最终一个4位数据组结点称
6、为尾结点。 为此需要两个结构数据类型:双向循环链表和长整数,两个类型采取相同结构,只是双向循环链表用来存放数据,长整型用表示数据运算。 1、 双向循环链表数据结构及操作定义以下: typedef short ElemType; //定义基础数据类型,我们采取short来表示任意4位整数。 typedef struct DuCiLinkNode{ // 双向循环链表结点存放结构 ElemType data; struct DuCiLinkNode *prior; //指向上一结点 struct DuCiLinkNode *next; //指向
7、下一结点 }DuCiLinkNode,*DuCiLinkList; //定义双向循环链表结点及链表类型名 基础操作: DuCiLinkNode *MakeNode(ElemType e); //以4位整数e结构1个双向循环链表结点 Status InitList(DuCiLinkList *L); //初始化1个双向循环链表,分配1个结点作头结点 //数据域赋初值0,上下结点指针指向自己 void DestroyList(DuCiLinkList *L); //消毁1个双向循环链表,释放它所占用全部内存空间 //并让链表*L
8、指向NULL void ClearList(DuCiLinkList L); //清除1个双向循环链表,释放数据结点所占用内存空间 //保留头结点,并将数据域置为0,上下结点指针指向自己 Status InsTail(DuCiLinkList L, ElemType e); //在双向循环链表L尾结点以后加入1个以e为 //数据域新结点,并返回OK; 不然返回ERROR。 Status InsFirst(DuCiLinkList L, ElemType e); //将数据元素e插入在线性链表L头结点以后,并返回OK; 不然返回ERR
9、OR。 Status CopyList(DuCiLinkList L, DuCiLinkList C); //将双向循环链表L复制到双向循环链表C中。 2、 长整数数据类型和和操作定义为: typedef struct DuCiLinkNode LongIntNode,*LongInt;//采取双向循环链表为实际存放结构 void OutputNumber(LongInt a); //输出一个长整型数 void InputNumber(LongInt a,int OneOrTwo); //输入一个长整型数 void add(LongInt c,LongInt a,LongI
10、nt b); //长整型数 c = a + b void sub(LongInt c,LongInt a,LongInt b); //长整型数 c = a - b Status mul(LongInt c,LongInt a,LongInt b); //长整型数 c = a * b void div(LongInt c,LongInt a,LongInt b); //长整型数 c = a / b (整除) void rem(LongInt c,LongInt a,LongInt b); //长整型数 c = a % b (求余) void power(LongInt c,Lon
11、gInt a,int n); //长整型数 c = a ^ n (乘方) 3、 本程序包含四个模块: 1) 主程序模块: void main() //main.c { 初始化; do{ 接收命令; 处理命令; }while(“命令”=“结束”) } 2) 程序界面模块 //IntFace.c, IntFace.h 3) 双向循环链表处理模块 // DuCiLink.c,DuCiLink.h 4) 长整型数输入输出模块 //LongIO.c, LongInt.h 5) 长整数运算模块 //LongInt.c LongInt.h 各模
12、块之间调用关系以下: 程序界面模块 双向循环链表单元模块 长整数运算模块 长整数输入输出模块 主程序模块 三、具体设计 1、关键函数 (1)、主控模块main.c void DoCommand() //依据输入命令进行对应处理 void Calculate() //实施计算功效 void ReSet() //重设系统环境 (2)、程序界面模块 IntFace.c void InitiInterface(); //界面初始化 void GoToCmdxy(); //将光标定位到命令选项提醒以后 void GoToPrompt(); /
13、/将光标定位到命令选项提醒行首 void ShowMainPrompt(); //显示命令选项提醒 void ClearScreen(); //以清除整个屏幕,并设置为黑底白字模式 void ClearPromptLine(); //清除提醒行显示 void ClearWorkSpace(); //清除工作区显示 void InputNumberBox(int OneOrTwo);//指定两个输入数输入窗口,假如超出这个范围文字将自动流动 void ResultBox(); //指定计算结果显示窗口,假如超出这个范围文字将自动流动 (3)、长整型数输入输出模块
14、见二小节2分节 (4)、长整型数四则运算处理模块 见二小节2分节 (5)、长整型数存放模块—双向循环链表模块 见二小节1分节 2、函数关键调用关系图 main InitiInterFace DoCommand DrawIntFace Calculate InputNumber InputOperator Reset add sub mul div rem power InitList OutputNumber InsTail ClearList InsFirst CopyList DestroyList DestroyList InitL
15、ist 直接调用 可能调用 四、调试分析及编程心得体会 1、刚开始考虑进位问题过于简单,造成测试数据时数次犯错。 2、刚开始时在输入方法中花了较大功夫,而且用户界面不够友好,程序容错性较差。 3、开始写程序时源程序没有严格按单元模块结构编写,可读性较差。 4、因为首次进行系统程序设计,层次结构划分不太合理,应在以后设计中强化此思维,逐步和工程设计接轨。 ………………………………………… 五、用户手册 1、本程序运行环境为DOS操作系统,实施文件为LongInt.exe。 2、进入演示程序后即显示文本方法用户界面 3、输入命令,实施对应功效: 1 –– 输入第1
16、个整数 o,O –– 输入运算符 r, R –– 重置系统 2 –– 输入第2个整数 c,C –– 实施运算 q,Q –– 退出系统 六、测试结果 (1)、0和0四则运算: (2)、-2345,6789;-7654,3211;+;应输出“-1,0000,0000”。 (3)、-9999,9999;1,0000,0000,0000;+;应输出“9999,0000,0001”. (4)、1,0001,0001;-1,0001,0001;+;应输出“0”. (5)、1,0001,0001;-1,0001,0000;+;应输出“1”。 (6)、-9999,99
17、99,9999;-9999,9999,9999;+;应输出“-1,9999,9999,9998”. (7)1,0000,9999,9999;1;+;应输出“1,0001,0000,0000”. 略………………………………… 七、源程序代码 /******************************************************* 1、main.c 主控文件 *******************************************************/ #include "IntFace.h"/*界面模块头文件*/ #include
18、"LongInt.h"/*长整型数处理模块头文件*/ char cmd; /* menu command */ char opt; /* operator */ int n; /* power */ LongInt a,b,c; /* Long integer numbers */ int flag_n1=0,flag_n2=0,flag_opt=0,flag_cal=0,flag_reset=1; /*标志位*/ void ReSet() /* Reset system */ { ClearWorkSpace(); //清屏幕工作区 flag_n1
19、0; //重置长整数1是否输入标志 flag_n2=0; //重置长整数2是否输入标志 flag_opt=0; //重置运算符 是否输入标志 flag_cal=0; //重置是否进行了运算标志 flag_reset=1; //重置 重置标志 } void Calculate() //实施计算 { int overflow = OK; if (flag_n1*flag_n2*flag_opt == 0 ) return; /*Input is not complete! 输入不完整则直接返回*/ switch (opt) {
20、 case '+': add(c,a,b); break;//实施加法运算 case '-': sub(c,a,b); break;//实施减法运算 case '*': mul(c,a,b); break;//实施乘法运算 case '/': overflow = div(c,a,b); break;//实施整除运算 case '%': rem(c,a,b); break;//实施求余运算 case '^': n = b->prior->data;power(c,a,n); break; //临时以长整数b最终一组数据为幂,实施乘方运算 }; go
21、toxy(2,10); //定位到输出位置 cprintf(overflow==OK ? "Result = ":"DivideBy");//输出结果提醒 ResultBox(); //控制输出范围,以免搞乱程序界面 OutputNumber(c); //输出运算结果 ClearList(c); //清空长整数c window(1,1,80,25); //重新设置显示窗口为全屏幕 } void DoCommand() //依据输入命令进行对应处理 { switch(cmd) { case '1':InputNumber(a,1);fla
22、g_n1=1;break; //输入第1个长整数 case '2':InputNumber(b,2);flag_n2=1;break; //输入第2个长整数 case 'O': case 'o':opt=InputOperator();flag_opt=1;break; //输入运算符 case 'C': case 'c':Calculate();flag_cal=1;break; //实施运算 case 'R': case 'r':ReSet(); //重设系统方便实施下一次运算 } } void main() { InitiInter
23、face();//初始化程序界面 InitList(&a); //初始化长整形数据a,b,c InitList(&b); InitList(&c); do{ GoToCmdxy(); //将光标定位到输入命令处 cmd = getche(); //读取一个操作命令 DoCommand(); //实施对应命令 }while(cmd!='q' && cmd != 'Q'); //假如输入是Q或q则退出 DestroyList(&a); //销毁长整形数据a,b,c,释放它们所占 DestroyList(&b); DestroyList(&
24、c);
ClearScreen(); //清除屏幕上显示
}
/*******************************************************
2、IntFace.h 程序界面模块头文件
*******************************************************/
#include
25、 //界面高度 int width; //界面宽度 char ProgramName[30]; //程序名 char MenuItems[NofMenuItem][12];//功效选项 int MaxItemLength; //功效选项名最大长度 char prompt[40]; //命令选项提醒 int backcolor; //界面背景 int textcolor; //文本颜色 int WaitCmdx; //功效选项输入坐标x int WaitCmdy; //功效选项输入坐
26、标y }; void InitiInterface(); //界面初始化 void GoToCmdxy(); //将光标定位到命令选项提醒以后 void GoToPrompt(); //将光标定位到命令选项提醒行首 void ShowMainPrompt(); //显示命令选项提醒 void ClearScreen(); //以清除整个屏幕,并设置为黑底白字模式 void ClearPromptLine(); //清除提醒行显示 void ClearWorkSpace(); //清除工作区显示 void InputNumberBox(int OneOrTwo);/
27、/指定两个输入数输入窗口,假如超出这个范围文字将自动流动 void ResultBox(); //指定计算结果显示窗口,假如超出这个范围文字将自动流动 /******************************************************* 3、IntFace.c 程序界面处理模块文件 *******************************************************/ #include "IntFace.h" #include "dos.h" /*界面长宽及菜单等数据,具体含义见头文件*/ struct I
28、ntFaceType IntFace = {14,40,"Long Integer Calcultor", {"Number 1 ","Number 2 ","Operator ","Calculate","Reset ", "Quit "},9,"Enter a hotkey: 1,2,O,C,R or Q:",BLUE,WHITE}; /*画界面框架、显示程序功效选项、输入提醒等 ┌─────────── Long Integer Calcultor ───────────┐ │ Number 1 Number 2 Operator Calc
29、ulate Reset Quit │ ├──────────────────────────────────┤ │ │ │ │ │ │ │
30、 │ │ │ │ │ │ │ │
31、 │ ├──────────────────────────────────┤ │Enter a hotkey: 1,2,O,C,R or Q: │ └──────────────────────────────────┘*/ void DrawIntFace() { int i,j,LenProgramName,len; putch(218); //画左上角转角线 LenProgramName
32、 strlen(IntFace.ProgramName); //计算程序名称长度
len = (IntFace.width - 4 - LenProgramName)/2; //计算程序名称左右横线长度
for(i=0;i 33、);putch(179); //画第2行首竖线
for(i=0;i 34、th-2;i++) putch(196); //画第3行横线
putch(180); //画第3行尾三岔线
for(j=4;j 35、195); //画倒数第3行横线
for(i=0;i 36、画最终一行横线
for(i=0;i 37、 (IntFace.MaxItemLength + IntMenuItem) * NofMenuItem + IntMenuItem + 2;
lenprompt = strlen(IntFace.prompt); //输入提醒长度
if (len < lenprompt) len = lenprompt;
if (IntFace.width 38、prompt+2; //命令输入处X坐标
IntFace.WaitCmdy = IntFace.height - 1; //命令输入处Y坐标
clrscr(); //清屏,方便显示程序界面
textbackground(IntFace.backcolor); //设置界面背景颜色
textcolor(IntFace.textcolor); //设置界面文本颜色
DrawIntFace(); //画出界面
}
void ClearScreen()//以清除整个屏幕,并设置为黑底白字DOS传统模式
{
t 39、extbackground(BLACK);
textcolor(WHITE);
clrscr();
}
void ClearPromptLine()/* 清除提醒行显示 */
{
int i;
gotoxy(2,IntFace.height-1); //到倒数第2行首
for(i=0;i 40、height-2;j++)
{
gotoxy(2,j); //到第j行首
for(i=0;i 41、nPrompt() /* 显示命令选项提醒 */
{
ClearPromptLine();
cputs(IntFace.prompt);
}
void InputNumberBox(int OneOrTwo)
{ /*指定两个输入数输入窗口,假如超出这个范围文字将自动流动*/
window(11,(OneOrTwo==1)?4:6,IntFace.width-1,(OneOrTwo==1)?5:7);
clrscr();
}
void ResultBox()
{ /*指定计算结果显示窗口,假如超出这个范围文字将自动流动*/
window(11,10, 42、IntFace.width-1,11);
clrscr();
}
/*******************************************************
4、LongInt.h 长整型数输入输出及运算模块头文件
*******************************************************/
#include "DuCiLink.h"
typedef struct DuCiLinkNode LongIntNode,*LongInt;//采取双向循环链表为实际存放结构
void OutputNumber(Long 43、Int a); //输出一个长整型数
void InputNumber(LongInt a,int OneOrTwo); //输入一个长整型数
void add(LongInt c,LongInt a,LongInt b); //长整型数 c = a + b
void sub(LongInt c,LongInt a,LongInt b); //长整型数 c = a - b
void mul(LongInt c,LongInt a,LongInt b); //长整型数 c = a * b
Status div(LongInt c,LongInt a,LongInt b); / 44、/长整型数 c = a / b (整除)
void rem(LongInt c,LongInt a,LongInt b); //长整型数 c = a % b (求余)
void power(LongInt c,LongInt a,int n); //长整型数 c = a ^ n (乘方)
/*******************************************************
5、LongIO.c 长整型数输入输出处理模块文件
*******************************************************/
#in 45、clude "Intface.h"
#include "LongInt.h"
#include 46、
{
cprintf("%04d%c",s->data,(s == a->prior)?'\0':',');
s = s->next;
}
}
void InputNumberMsg(int OneOrTwo)
{ /*显示输入两个长整型时提醒 */
window(1,1,80,25);
ClearPromptLine();
cputs("Example:-1,0001,0001;");
gotoxy(2,(OneOrTwo==1)?4:6);
cprintf("Number %d:",OneOrTwo);
InputNumberBox(On 47、eOrTwo);
}
void InputNumberErrMsg()
{ /*输入犯错时提醒*/
window(1,1,80,25);
ClearPromptLine();
cprintf("One number out of [0-9999]! Please input the whole number again!");
getch();
}
void InputNumber(LongInt a,int OneOrTwo)
{ /*输入长整型数*/
char c; //统计输入时逗号和分号
short e; //统计输入数据
48、short sign = 0; //统计长整型数符号
short FirstSection = 1; //是否是第1个4位数据组
LongIntNode *pa,*s; //节点临时指针
InputNumberMsg(OneOrTwo);//显示输入提醒
ClearList(a); // 清空长整型数存放空间
fflush(stdin); // 刷清输入缓冲区,以避免以前错误按键残留
do{
cscanf("%d",&e);c = getche();//读取数据
if (FirstSection) //假如是第1个组,则设置整型数符号
49、 {
if(e>=0) sign = 1;
if(e<0) {sign = -1;e *= -1;}
FirstSection = 0;
}
if(e<0 || e>9999)
{ //假如每组数值不在0-9999之内则报错并要求重输整个长整型数
InputNumberErrMsg();
InputNumberMsg(OneOrTwo);
FirstSection = 1;
ClearList(a);
fflush(stdin);/*刷清输入缓冲区*/
c=',';
}
else//假 50、如本组数值符合要求则加入到长整型数据中
{
InsTail(a,e); //在长整型数尾端加入本组数据
a->data++; //组数加1
}
}while(c!=';');
pa = a->next; //pa指向首结点
while (pa->data == 0 && pa->next != a) //数值为0且不是尾结点则删除
{ /*输入时可在前几节输入多个0,需要删除,但又不能将0删除完*/
s = pa; pa = pa->next; //s指向目前结点,pa指向下结点
a->next = pa; //断开对s链接






