您如何制作一个菜单界面来接受C中的两位数整数或字符?

时间:2018-09-28 19:53:01

标签: c arrays string char malloc

在过去的几个小时中,我一直在困惑于此程序,但似乎找不到找到使该程序正常工作的方法。我以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--;
    }
}

2 个答案:

答案 0 :(得分:1)

我需要注意几件事,并且不想将其转变为TLDR,所以我将尝试将每个问题放在单独的段落中。您可以一粒盐吃掉所有这些;毕竟,这只是建议。

  • 您要查找的格式指令是%2[0123456789]。将指针传递到大小适合存储三个字符的位置,然后检查返回值。该指令需要对其寂寞地调用scanf,否则您以后可能会用动脉瘤调试与空字段有关的问题,因此“绿灯”返回值指示您的程序正在成功处理好的输入是scanf("%2[0123456789]", ptr_into_array_of_char)将返回1。任何其他返回值表示琥珀色红色灯亮了。提醒您,我在这里严格解释您的规格(不完整)...实际上,我只用%d,并很高兴我的用户通过输入{{1 }}而不是1(而且在不与01打交道时,您也不太可能患有动脉瘤)。
  • 我们的编译器通常会在出现语法错误时发出错误消息并中止编译,但是这一要求与实际情况不符:“程序接受输入直到输入q。” 希望您的完整说明解释了当用户偏离期望值时会发生什么。我想您可能会发出一个错误,清除堆栈,读到行尾,然后像程序%[一样运行就可以了?通常,我们使用一些组合键,例如CTRL + d(在Linux上)或CTRL + Z(在Windows上)关闭scanf("%*[^\n]"); getchar(); puts("Error message here"); top = 0;,从而表示输入终止。
  • “动态内存分配的想法暗示了我” ,因此您将很高兴知道您可能不应该在这里使用动态内存分配,除非您希望堆栈 超出您设置的6个硬编码插槽,
  • 我认为这个问题的标题混淆不清;您不是在设计菜单,而是在执行语法。在这里查看stdin的“菜单”是如何设计的。如果您曾经想在gcc周围设计菜单,请停止;也许您真正想要的是GUI指向并单击,因为这不是Unix的工作方式。
  • 由于一些技术上的历史人工因素,在stdin之后先声明void fubar(void);是不确定的行为,void fubar() { /* SNIP */ }也是如此……这就是为什么您最好选择一本书该语言专门由著名的人讲授C语言来学习C语言。有许多细微的细微差别可以吸引您。
  • 关于函数原型等,请注意堆栈是通用数据结构。作为另一种思考实验,请考虑如果int main()仅对用文件作用域声明的数组进行操作,将给您带来痛苦。从逻辑上讲,其所有外部数据要求应来自其参数,而不应来自变量,即使用文件范围声明的strcpy
  • 我们被教导要谨慎地使用内存,在我看来,像仅将变量用作控制表达式一样,与这些课程相抵触。在存在stackbreakcontinue之类的构造的地方,可以使用更干净的替代方法而无需声明变量(因此可以使用额外的自由寄存器供其他使用)。

答案 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表示法的知识,才能成功实现。

提示:我也将忽略开关中的空格(空格和制表符,甚至返回)。