在过去的几个小时中,我一直在困惑于此程序,但似乎找不到找到使该程序正常工作的方法。我以switch语句样式的菜单开始,但是随后出现一个问题,菜单会掉落并退出,我无法弄清楚,所以我只是将代码切换到基于if else的菜单。该程序背后的思想如下:
编写并测试一个实现基于堆栈的基于整数的计算器的C程序。程序接受输入,直到输入q。但是,我的困难在于让菜单接受大于10的数字。
我的每个程序都可以在程序中正常工作,但当我输入两位整数时,它将分别存储两位数。我知道这是因为我具有读取和使用char的菜单设置,但是我无法弄清楚如何使char数组起作用。我以前从未用C编程过,所以动态内存分配的想法隐含了我的意思,因为我不确定何时需要它。这是到目前为止该程序的源代码:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#define SIZE 6
int stack[SIZE]; //stack size
int top = 0; //top of stack
void pop();
void clear();
void display();
void top_element();
void add();
void multiply();
void subtract();
void division();
void power();
int main()
{
char input;
int flag = 1;
while(flag == 1)
{
printf(": ");
scanf(" %c",&input);
if(isdigit(input))
{
if(top < SIZE)
{
stack[top] = input - '0';
top++;
}
else
printf("Error: stack overflow\n");
}
else if(input=='p')
pop();
else if(input=='c')
clear();
else if(input=='d')
display();
else if(input=='=')
top_element();
else if(input=='+')
add();
else if(input=='*')
multiply();
else if(input=='-')
subtract();
else if(input=='/')
division();
else if(input=='^')
power();
else if(input=='q')
flag = 0;
else
printf("Error: invalid command\n");
}
printf("Goodbye!\n");
return 0;
}
void pop()
{
if(top==0)
printf("Error: stack is empty\n");
else
top--;
}
void clear()
{
top=0;
}
void display()
{
int i;
if(top == 0)
printf("Error: stack is empty\n");
else
{
for(i = top - 1; i >= 0; i--)
printf("%d\n",stack[i] );
}
}
void top_element()
{
printf("%d\n",stack[top-1] );
}
void add()
{
if(top<2)
printf("Error: not enough operands for the requested operation\n");
else
{
int ans=stack[top-1]+stack[top-2];
stack[top-2]=ans;
top--;
}
}
void multiply()
{
int ans=stack[top-1]*stack[top-2];
stack[top-2]=ans;
top--;
}
void subtract()
{
if(top < 2)
printf("Error: not enough operands for the requested operation\n");
else
{
int ans = (stack[top-2] - stack[top-1]);
stack[top-2]=ans;
top--;
}
}
void division()
{
if(top < 2)
printf("Error: not enough operands for the requested operation\n");
else
{
if(stack[top-1]==0)
printf("Error: attempt to divide by 0\n");
else
{
int ans = (stack[top-2]/stack[top-1]);
stack[top-2]=ans;
top--;
}
}
}
void power()
{
if(top < 2)
printf("Error: not enough operands for the requested operation\n");
else
{
int ans = pow(stack[top - 2], stack[top - 1]);
stack[top - 2] = ans;
top--;
}
}
答案 0 :(得分:1)
我需要注意几件事,并且不想将其转变为TLDR,所以我将尝试将每个问题放在单独的段落中。您可以一粒盐吃掉所有这些;毕竟,这只是建议。
%2[0123456789]
。将指针传递到大小适合存储三个字符的位置,然后检查返回值。该指令需要对其寂寞地调用scanf
,否则您以后可能会用动脉瘤调试与空字段有关的问题,因此“绿灯”返回值指示您的程序正在成功处理好的输入是scanf("%2[0123456789]", ptr_into_array_of_char)
将返回1。任何其他返回值表示琥珀色或红色灯亮了。提醒您,我在这里严格解释您的规格(不完整)...实际上,我只用%d
,并很高兴我的用户通过输入{{1 }}而不是1
(而且在不与01
打交道时,您也不太可能患有动脉瘤)。%[
一样运行就可以了?通常,我们使用一些组合键,例如CTRL + d(在Linux上)或CTRL + Z(在Windows上)关闭scanf("%*[^\n]"); getchar(); puts("Error message here"); top = 0;
,从而表示输入终止。stdin
的“菜单”是如何设计的。如果您曾经想在gcc
周围设计菜单,请停止;也许您真正想要的是GUI指向并单击,因为这不是Unix的工作方式。stdin
之后先声明void fubar(void);
是不确定的行为,void fubar() { /* SNIP */ }
也是如此……这就是为什么您最好选择一本书该语言专门由著名的人讲授C语言来学习C语言。有许多细微的细微差别可以吸引您。int main()
仅对用文件作用域声明的数组进行操作,将给您带来痛苦。从逻辑上讲,其所有外部数据要求应来自其参数,而不应来自变量,即使用文件范围声明的strcpy
。 stack
,break
和continue
之类的构造的地方,可以使用更干净的替代方法而无需声明变量(因此可以使用额外的自由寄存器供其他使用)。答案 1 :(得分:0)
问题不在这次scanf()
中,而是问题在于您解析输入。
逐个字符地解析输入的字符是正确的,相反,至少在几乎所有情况下,它使事情变得容易得多。但是,逐个字符地解析也意味着您要解析每个大于9的正数,也要逐个字符地解析或逐个数字地更好地解析-您必须在单个数字中构建完整的数字。您是从“从左到右”解析的,因此只需乘以10并加上数字即可。冲洗并重复直到没有剩余数字并将结果放入堆栈中。
示例:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#define SIZE 6
/* you should look up what "static" means and when and how to use */
static int stack[SIZE]; //stack size
static int top = 0; //top of stack
/*
* You need to expicitely add "void" to the argumet list.
* It defaults to "int" otherwise.
* Please do yourself a favor and switch all warnings on.
*/
void pop(void);
void clear(void);
void display(void);
void top_element(void);
void add(void);
void multiply(void);
void subtract(void);
void division(void);
void power(void);
/* Most checks and balances omitted! */
int main(void)
{
/* "int" to make things easier */
int input;
int flag = 1, anumber;
while (flag == 1) {
printf(": ");
/* get a(n ASCII) character */
input = fgetc(stdin);
if (isdigit(input)) {
anumber = 0;
/*
* We have a digit. Parse input for more digits until
* no further digits appear and add all digits to "anumber".
* We assume a decimal representation here.
*/
/* TODO: check for overflow! */
for (;;) {
anumber *= 10;
anumber += input - '0';
input = fgetc(stdin);
if (!isdigit(input)) {
break;
}
}
/* Push number on the stack */
if (top < SIZE) {
stack[top] = anumber;
top++;
} else {
printf("Error: stack overflow\n");
}
}
/* "input" from fgetc() is an integer, we can use a switch */
switch (input) {
case 'p':
pop();
break;
case 'c':
clear();
break;
case 'd':
display();
break;
case '=':
top_element();
break;
case '+':
add();
break;
case '^':
power();
break;
case 'q':
flag = 0;
break;
default:
printf("Error: invalid command\n");
break;
}
}
printf("Goodbye!\n");
return 0;
}
void pop(void)
{
if (top == 0)
printf("Error: stack is empty\n");
else
top--;
}
void clear(void)
{
top = 0;
}
void display(void)
{
int i;
if (top == 0)
printf("Error: stack is empty\n");
else {
for (i = top - 1; i >= 0; i--)
printf("%d\n", stack[i]);
}
}
void top_element(void)
{
printf("%d\n", stack[top - 1]);
}
void add(void)
{
if (top < 2)
printf("Error: not enough operands for the requested operation\n");
else {
int ans = stack[top - 1] + stack[top - 2];
stack[top - 2] = ans;
top--;
}
}
/* Using pow() from math.h is not a good idea beause it uses floating point */
/* TODO check for overflows! */
static int integer_pow(int x, int n)
{
int r;
r = 1;
while (n != 0) {
if (n & 1) {
r *= x;
}
x *= x;
n >>= 1;
}
return r;
}
void power(void)
{
if (top < 2)
printf("Error: not enough operands for the requested operation\n");
else {
int ans = integer_pow(stack[top - 2], stack[top - 1]);
stack[top - 2] = ans;
top--;
}
}
测试:
$ ./stackbcalc
: 123+23=
Error: not enough operands for the requested operation
: 23
: Error: invalid command
: q
Goodbye!
不起作用。为什么?函数add()
在堆栈上需要两个操作数。您还需要将+
放在堆栈上(它是整数),一旦您使用=
结束,就可以评估堆栈。您可能需要学习有关infix / postfix / prefix表示法的知识,才能成功实现。
提示:我也将忽略开关中的空格(空格和制表符,甚至返回)。