首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在C中创建接受两位数整数或字符的菜单界面?

如何在C中创建接受两位数整数或字符的菜单界面?
EN

Stack Overflow用户
提问于 2018-09-29 03:53:01
回答 2查看 69关注 0票数 0

我在这个程序上摸索了几个小时,但我似乎找不到一种方法来让这个程序工作。我一开始使用的是switch语句样式的菜单,但后来我遇到了一个问题,菜单可能会失败并退出,我无法解决这个问题,所以我就把代码切换到了一个基于if else的菜单。该计划背后的想法如下:

编写并测试实现基于堆栈的整数计算器的C程序。程序接受输入,直到输入Q为止。然而,我的困难在于让菜单接受大于10的数字。

我让每一个单独的函数在我的程序中正常工作,除了当我输入一个两位数的整数时,它将分别存储两位数。我知道这是因为我有读取和处理字符的菜单设置,但我不能弄清楚如何让字符数组工作。我以前从来没有用C语言编程过,所以动态内存分配的想法暗示了我,因为我不完全确定什么时候需要它。这是我到目前为止拥有的程序的源代码:

代码语言:javascript
复制
#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--;
    }
}
EN

回答 2

Stack Overflow用户

发布于 2018-09-29 13:17:12

我有几件事要注意,我不想把它变成TLDR,所以我会尽量把每一期都放在单独的段落里。你可以对此持保留态度;毕竟,这只是一个建议。

您要查找的指令是%2[0123456789]。将指针传递到适合存储三个字符的位置(即char something[3];第三个字节用于空字符),并检查返回值。该指令需要调用scanf,否则以后调试与空字段相关的问题时可能会出问题,所以表示程序成功处理正确输入的“绿灯”返回值是scanf("%2[0123456789]", ptr_into_array_of_char)将返回1。任何其他返回值都表示发生了琥珀色或红灯。请注意,我在这里非常严格地解释了你的规范(不完整)。实际上,我只需要使用%d,并且很高兴我的用户通过输入1而不是01而患关节炎的机会减少了一半(而且在不处理%[).

  • Our编译器时,您也不太可能出现动脉瘤。通常,当我们犯了一些语法错误时,编译器会发出错误消息并中止编译,但这个要求与此背道而驰:“程序接受输入,直到输入q。”我希望你的完整规范解释了当用户偏离期望时应该发生的事情。我想你可以发出一个错误,清除堆栈,读到行尾,然后就像程序重新启动一样操作……像scanf("%*[^\n]"); getchar(); puts("Error message here"); top = 0;这样的?我们通常使用像CTRL+d (在Linux上)或CTRL+Z (在Windows上)这样的组合键来结束stdin,从而表示输入的终止。
  • “动态内存分配的想法暗示了我”,所以你应该庆幸地知道,你可能不应该在这里使用动态内存分配,除非你想让你的堆栈增长超过你设置的硬编码的6个插槽,也许...
  • 我假设这个问题的标题混淆了;你不是在设计一个菜单,而是实现了一个语法。看看gcc的“菜单”是如何为灵感而设计的。如果你曾经试图围绕stdin设计一个菜单,停下来;也许你真正想要的是一个可以指向并单击的图形用户界面,因为这不是Unix倾向于work.
  • Declaring void fubar(void);,然后是void fubar() { /* SNIP */ }的方式,由于一些技术历史文物,这是未定义的行为,int main()也是如此。这就是为什么你最好选择一本专门教授C语言的书,这本书的作者是有声望的人,来学习C语言。有很多微妙的细微差别可能会让你陷入困境。
  • 在函数原型等笔记中,认为堆栈是一种通用的数据结构。作为另一种思维实验,考虑一下如果只对使用文件作用域声明的数组进行操作,那么使用strcpy将是多么痛苦的事情。从逻辑上讲,它的所有外部数据需求都应该来自它的参数,而不是来自在文件范围内声明的变量,即stack
  • 我们被教导要谨慎地使用内存,在我看来,将变量单独用作控制表达式似乎违反了这些经验。在存在像breakcontinuegoto这样的构造的地方,可以有一个没有变量声明的更干净的替代方案(因此可以使用额外的空闲寄存器来做其他事情)。
票数 1
EN

Stack Overflow用户

发布于 2018-09-29 11:52:21

这次的问题不在于scanf(),而在于解析输入的方式。

一个字符一个字符地解析输入字符没有错,相反,至少在几乎所有的情况下,它使事情变得更容易。但是逐个字符地解析也意味着您要逐个字符地解析每个大于9的正数,或者更好的是逐个数字地解析--您必须从单个数字构建完整的数字。你从“从左到右”进行解析,所以只需乘以10并添加数字即可。冲洗并重复,直到你没有剩下的数字,并将结果放在堆栈上。

示例:

代码语言:javascript
复制
#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--;
  }
}

测试:

代码语言:javascript
复制
$ ./stackbcalc 
: 123+23=
Error: not enough operands for the requested operation
: 23
: Error: invalid command
: q
Goodbye!

不起作用。为什么?函数add()在堆栈上需要两个操作数。您需要将+也放在堆栈上(它是一个整数),一旦您在=的末尾,您就可以计算堆栈。你可能需要学习一些关于中缀/后缀/前缀表示法的知识,才能成功地做到这一点。

提示:我也会忽略开关中的空格(空格和制表符,甚至可能是回车符)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52561889

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档