您的位置:首页 > 其它

软件工程第四次作业-3四则运算

2017-10-11 14:40 525 查看
结对同学:姜珊

目录:

1.需求分析

2.基本设计

3.代码说明

4.测试运行

5.重难点知识

6.缺点改进及体会

1.需求分析:

作业链接:https://edu.cnblogs.com/campus/nenu/SWE2017FALL/homework/997

void GetStr(char *str)//构建随机串,并添加括号
{
char str1[1] = "";
int a, b, c, d;
char op1, op2, op3;
int i;
srand((int)time(0));
a = (int)(rand()%10);//四个变量
b = (int)(rand()%10);
c = (int)(rand()%10);
d = (int)(rand()%10);
i = (int)(rand()%4);//三个操作符
switch(i)
{
case 0:
op1 = '+'; break;
case 1:
op1 = '-'; break;
case 2:
op1 = '*'; break;
case 3:
op1 = '/'; break;
}
i=(int)(rand()%4);
switch(i)
{
case 0:
op2 = '+'; break;
case 1:
op2 = '-'; break;
case 2:
op2 = '*'; break;
case 3:
op2 = '/'; break;
}
i=(int)(rand()%4);
switch(i)
{
case 0:
op3 = '+'; break;
case 1:
op3 = '-'; break;
case 2:
op3 = '*'; break;
case 3:
op3 = '/'; break;
}
itoa(a, str1, 10);
strcpy(str, str1);
str[1] = op1;
itoa(b, str1, 10);
strcat(str, str1);
str[3] = op2;
itoa(c, str1, 10);
strcat(str, str1);
str[5] = op3;
itoa(d, str1, 10);
strcat(str, str1);
for(int j = 0; j < 7; j++)
{
if(str[j] == '/')
{
int e;
e = (int)(rand()%9)+1;
itoa(a, str1, 10);
str[j+1] = str1[0];
}
}
int j, k;//左括号右括号
int flag = 0;
j = (int)(rand()%3);
int length = 8;
if(j == 0)//位置1加不加左括号的判定
{
k = (int)(rand()%4);
if(k != 3&&flag != 2)
{
for(int i = length;i > 0;i--)//向坐标0处插入括号
{
str[i] = str[i-1];
}
str[0] = '(';
flag++;
length++;
int l = (int)(rand()%4);
if(l < 2)
{
for(int i = length; i > 4; i--)
{
str[i] = str[i-1];
}
str[4] = ')';
flag--;
length++;
for(int i = length;i > 6;i--)
{
str[i] = str[i-1];
}
str[6] = '(';
flag++;
length++;
for(int i = length;i > 10;i--)
{
str[i] = str[i-1];
}
str[10] = ')';
flag--;
length++;
}
else if(l = 2)
{
for(int i = length; i > 4; i--)
{
str[i] = str[i-1];
}
str[4] = ')';
flag--;
length++;
}
else if(l = 3)
{
for(int i = length; i > 6; i--)//插入括号
{
str[i] = str[i-1];
}
str[6] = ')';
flag--;
length++;
}

}
else if(k != 2&&flag != 2)
{
for(int i = length+1; i > 1; i--)//向坐标0,1处插入俩左括号
{
str[i] = str[i-2];
}
str[0] = '(';
str[1] = '(';
flag = flag+2;
length = length+2;

for(int i = length; i > 5; i--)
{
str[i] = str[i-1];
}
str[5] = ')';
flag--;
length++;

for(int i = length; i > 8; i--)
{
str[i] = str[i-1];
}
str[8] = ')';
flag--;
length++;
}
}

else if(j == 1)
{
k=(int)(rand()%4);
if(k != 3&&flag != 2)
if(0)
{
for(int i = length; i > 2; i--)//向坐标2处插入括号
{
str[i] = str[i-1];
}
str[2] = '(';
flag++;
length++;
}
else if(k != 2&&flag != 2)
{
for(int i = length+1; i > 3; i--)//向坐标2,3处插入俩左括号 ,只能接着向6和8(原坐标)添加括号
{
str[i] = str[i-2];
}
str[2] = '(';
str[3] = '(';
flag = flag+2;
length = length+2;

for(int i = length; i > 7; i--)
{
str[i] = str[i-1];
}
str[7] = ')';
flag--;
length++;
for(int i = length;i > 10;i--)
{
str[i] = str[i-1];
}
str[10] = ')';
flag--;
length++;
}
}
else if(j == 2)
{
k = (int)(rand()%4);
if(k != 3&&flag != 2)
{
for(int i = length; i>4; i--)//向坐标4处插入括号
{
str[i] = str[i-1];
}
str[4] = '(';
flag++;
length++;
//str4 插入左括号一个
for(int i = length; i>8; i--)
{
str[i] = str[i-1];
}
str[8] = ')';
flag--;
length++;
}
}

for(i = 0; i < length-1; i++)
{
printf("%c",str[i]);
}
printf("=");
}


View Code
  Translate()函数是将中序表达式转化为后序表达式,参数是两个字符串,分别是旧串和转化后的新串。用栈进行操作,并对括号进行配对取出,转化成为没有括号的逆波兰表达式。

int Translate(char *str,char *exp)//中缀表达式转后缀表达式
{
//新建一个栈,来存储符号
char e;
Stack S;
if(InitStack(&S) != 1)
{
printf("初始化栈失败!\n");

}
//当带转换的字符串*mid未终止时,循环处理
while(*str)
{
//如果是数字,则直接输出
if(*str >= '0' && *str <= '9')
{
*(exp++) = *(str++);
continue;
}else if(*str == '+' || *str == '-' || *str == '*' || *str == '/' || *str == '(' || *str == ')')
{
//输入的是合法运算符号,比较之前是否有更高优先级的符号
if(S.top == -1 || '(' == *str)
{
//当符号栈为空或遇到左括号时,符号入栈
push(&S, *(str++));
continue;
}
if(')' == *str)
{
//遇到右括号时,栈顶元素依次出栈;直到遇到第一个左括号时结束
pop(&S, &e);
*(exp++) = e;
while(pop(&S, &e) && e != '(')
{
*(exp++) = e;
}
// printf("%c\n",e);
str++;

continue;
}
//后续的处理都要取出临时的栈顶元素,与当前输入的符号*mid相比较;当临时栈顶元素优先级大于等于输入符号的优先级时,出栈;否则符号入栈(已经弹出一个,记得把弹出的元素也入栈)
pop(&S,&e);
if('+' == *str || '-' == *str)
{
if(e == '(')
{
push(&S, '(');
push(&S, *(str++));
continue;
}
else
{
*(exp++) = e;
push(&S, *(str++));
continue;
}
}
else if('*' == *str || '/' == *str)
{
if('*' == e || '/' == e)
{
*(exp++)=e;
push(&S, *(str++));
continue;
}
else
{
push(&S, e);
push(&S, *(str++));
continue;
}
}

}
else
{
printf("error%c\n", *str);
return -1;
}
}
//当待转换的字符已经结束时,符号栈至少还有一个元素(中缀表达式的特点:数字结尾;后缀表达式以符号结尾);将栈中的元素依次出栈
while(S.top != -1)
{
pop(&S, &e);
*(exp++) = e;
}
//字符串的结束符!
*exp = '\0';
}


  Calculate()函数是将后缀表达式进行计算,返回值类型为double型,值为该表达式的结果。

double Calculate(char* exp)//计算逆波兰表达式的值
{

int i = 0;
double temp[MAXSIZE];
int top = -1;
double a;
while(exp[i] != '\0')
{
if(exp[i]>='0' && exp[i]<='9')
{
temp[++top] = exp[i]-'0';
}
else if(exp[i] == '-')
{
double m = temp[top];
top--;
double n = temp[top];
top--;
temp[++top] = n-m;

}
else if(exp[i] == '+')
{
double m = temp[top];
top--;
double n = temp[top];
top--;
temp[++top] = n+m;
}
else if(exp[i] == '/')
{
double m = temp[top];
top--;
double n = temp[top];
top--;
temp[++top] = n/m;
}
else if(exp[i] == '*')
{
double m = temp[top];
top--;
double n = temp[top];
top--;
temp[++top ] = n*m;
}
i++;
}

return temp[top];
}


  输出有两个函数,PrintOnScr()负责功能一二的输出,PrintOnFile()负责功能三的输出,但是功能三因技术原因未完成,暂时只输出至屏幕。

void PrintOnScr(double answer,int count)//输出至屏幕,对应功能一二
{
printf("\n");
printf("?");
double ans;
scanf("%lf",&ans);
if(answer == ans)
{
printf("答对啦,你真是个天才!");
count++;
//break;
}
else
{
printf("再想想吧,答案似乎是%d喔!",answer);
}
printf("\n");
}

void PrintOnFile(double answer)//输出至文件,对应功能三
{
printf("\t\t\t%d\n",answer);
return;
}


  主函数里定义两个空串,用于传入函数中接收数据,然后根据参数个数执行对应某段函数体。

int main(int argc, char *argv[])
{
char str[MAXSIZE]="";
char final[MAXSIZE]="";
double answer;
int count = 0;
if(argc == 1)
{

for(int i = 0; i < 20; i++)
{
GetStr(str);
Translate(str,final);
answer=Calculate(final);
PrintOnScr(answer,count);
fflush(stdin);
}
printf("\n");
printf("你一共答对%d道题,共20道题。", count);
return 0;
}
else if(argc == 3)
{
int n = atoi(argv[2]);
if(n < 0)
{
printf("题目数量必须是 正整数。");
}
else if(argv[2][0] >= 'a'&&argv[2][0]<='z')
{
printf("题目数量必须是 正整数。");
}
else
{
for(int i = 0; i < 100; i++)
{
for(int j = 0; j < 100; j++)
{
if(argv[i][j] == '.')
{
printf("题目数量必须是 正整数。");
return 0;
}
}
}

for(int i = 0; i < n; i++)
{
GetStr(str);
Translate(str,final);
answer=Calculate(final);
PrintOnFile(answer);
}
}
}
}


4.测试运行

  功能一和功能二:

  只能算最多2道题,然后程序崩溃了。我估计是堆栈溢出的错误,但是不知如何清空内存,因为在刚刚打开窗口的时候程序是正常的。无法修改这个错误。





  功能三:

  可以正确判断-c后边的参数,却无法进行输出,程序再次崩溃。





5.重难点知识

  本次编程用到了以下知识,参考链接如下:

  C语言产生随机数:http://www.cnblogs.com/qjziyou/p/4782454.html

  Itoa函数:http://www.cnblogs.com/bluestorm/p/3168719.html

  定义字符栈的方法:http://blog.csdn.net/keepupblw/article/details/26343769

  判断整数:http://blog.csdn.net/youngdze/article/details/13628877

  浮点数转换成ASCII码:http://download.csdn.net/download/letre/1936905

6.缺点改进及体会

这次的三个功能都没有完全实现,我和姜珊同学对需求的考虑不充分,没有提前测试一下循环情况下程序会不会溢出,结果真的发生了溢出,也尝试过修改但是并没有奏效。在字符栈那里的使用肯定没有想象的那么顺利。最开始我们一起讨论代码规范的书写,互相交流了风格,发现了我们其实并没有什么风格,就制订了一份详细的规范我们仔细遵守就好。此外,我和姜珊同学对于函数的参数设置进行了争论,最后一致决定采用字符串传参数。在Calculate()函数这里我们讨论了一下是否要使用atoi()函数,我认为采用减去’0’的效果更好更简洁,最后我们决定使用后者的方法。在遇到字符栈输出溢出的时候,我们试着重新写了一个新的函数,遗憾的是,效果还没有原来的好,根本不能运行,直接崩溃。在最后判断浮点数的时候,我提出了将其转化为ASCII码的建议,姜珊同学认为直接搜索小数点即可,我们采用了她的方法。

以后要注意对代码段的掌控,不要等到错误无法挽回在试图修改。

  照片:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: