我是一个初级程序员,试图学习数据 struct ,但我目前在这个特定的代码中遇到了问题,我花了很多时间,仍然不知道问题是什么.我使用指针来输入堆栈中的元素,我的教授直接使用了像infix[i]这样的数组,我不知道我的方法是否错误,但我想try 一些新的东西.


#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<ctype.h>
#define max 100

char stack[max];
int top = -1;
char pop();
char push(char x);
int priority(char x);
void infixtopostfix(char *infix, char *postfix);

int main() {
  char infix[100], postfix[100];
  printf("Enter the expression");
  fgets(infix, max, stdin);
  infixtopostfix(infix, postfix);
  puts(postfix);
}

char pop() {
  char val;
  if (top == -1) {
    printf("underflow");
    exit(1);
  } else {
    val = stack[top--];
    return val;
  }
}

char push(char x) {
  if (top == max - 1) {
    printf("overflow");
    exit(1);
  } else {
    stack[++top] = x;

  }
}

int priority(char x) {
  if (x == '^')
    return 3;
  if (x == '*' || '/')
    return 2;
  if (x == '+' || '-')
    return 1;
}

void infixtopostfix(char *infix, char *postfix) {
  char *p, *i;
  i = infix;
  p = postfix;
  while (*i != '\0') {
    if (isalpha(*i) || isdigit(*i)) {
      *p = *i;
      p++;
      i++;
    } else if (*i == '(') {
      push(*i);
      i++;
    } else if (*i == ')') {
      while ((top != -1) && (stack[top] != '(')) {
        *p = pop();
        p++;

      }
      if (top == -1) {
        printf("invalid statement");
        exit(1);
      }
      pop();
      i++;

    } else if (*i == '+' || *i == '*' || *i == '/' || *i == '-' || *i == '^') {
      while ((top != -1) && stack[top] != '(') {
        if (priority(*i) <= priority(stack[top])) {
          *p = pop();
          p++;

        }
        push(*i);
        i++;
      }

    } else {
      printf("invalid expression");
      exit(1);
    }
  }
  while ((top != -1) && (stack[top] != '(')) {
    *p = pop();
    p++;
  }
  *p = '\0';
}

对于输入(a+b),预期输出应为ab+ 但是代码不会给出任何输出.

推荐答案

fgets(infix,max,stdin);表示infix可以(也可以不)包含换行符('\n').

如果是,那么就像任何其他空格字符一样,它将导致(以infixtopostfix为单位)

else
{
    printf("invalid expression");
    exit(1);
}

才会发生.

您应该判断返回值fgets,以查看它是否成功,然后删除尾随的换行符(如果存在).

请参见:Removing trailing newline character from fgets() input.


pri或ity有一个问题,即它的默认返回值是2,并且永远不能返回1,因为

if(x=='*'||'/')
return 2;

被有效地解析为

if((x == '*') || ('/' != 0))
return 2;

修复此函数以进行正确的比较,并返回minimal的默认值,例如:

int pri或ity(char x)
{
    if (x == '^')
        return 3;
    if (x == '*'|| x == '/')
        return 2;
    if (x == '+'|| x == '-')
        return 1;

    return 0;
}

使用以前的固定值,现在(的优先级为零.

这里的while条件应该删除对(的显式判断

else if(*i=='+'||*i=='*'||*i=='/'||*i=='-'||*i=='^')
{  
    while((top!=-1)&&stack[top]!='(') {
        if(pri或ity(*i)<=pri或ity(stack[top])) {
            *p=pop();
            p++;

        }
        push(*i);
        i++;
    }
}

取而代之的是,只要它们的优先级大于或等于当前扫描的操作符的优先级,就弹出值,并将新操作符outside推入循环.

else if (*i=='+'||*i=='*'||*i=='/'||*i=='-'||*i=='^') {
    while((top!=-1) && pri或ity(*i) <= pri或ity(stack[top])) {
        *p=pop();
        p++;
    }
        
    push(*i);
    i++;
}

如果没有这一改变,当扫描+时,给定(a+b):堆栈的顶部将是(,并且永远不会进入while循环(并且new运算符将永远不会被压入堆栈,因为那是while循环的inside).

更改后,+的优先级高于(,这意味着(不会是堆栈中的popped.然后,+被无条件地推送到堆栈,after,while循环.


char push(char x)不返回值.将其定义为void push(char x).


该程序在应用了之前的更改的情况下运行

$ gcc infix_to_posfix.c 
$ ./a.out 
Enter the expression(a+b)
ab+

但是可以使用大量的重构(和格式化).

特别是,定义了两个函数:

  • bool is_empty(void),以及
  • char peek(void)

将在几个地方简化代码.

例如,你在几个不同的地方写了top != 1top == -1.如果稍后您决定更改堆栈的工作方式,现在top/0表示堆栈为空,该怎么办?您必须在多个地方更改代码.

相反,定义函数

bool is_empty(void)
{
    return -1 != top;
}

并将其用作:

// if (top == -1) {
if (is_empty()) {
    printf("underflow");

// while ((top != -1) && (stack[top] != '('))
while (!is_empty() && (peek() != '('))

意味着您的代码既是easier to read又是easier to maintain,因为更改表示empty stack的代码只需要修改is_empty-一个函数,而不是整个程序中的几个位置.

peek是一个函数,它返回堆栈without的最上面的元素,弹出它(不改变top).

Removing the global variables, and defining a structure (struct stack;) would be the next step, so that you can easily have m或e than one stack in a program - with each stack being self-contained, and the associated functions being able to be used with any stack. This may not matter much f或 this particular program, but it is something to learn, and applies to any real library.


Here is an unrefined, but rather complete example of how one might prefer to approach this. It is not intended as a fix f或 your code, but as something to spend time studying.

In this example, infix_to_postfix protects against buffer overflows when used c或rectly.

#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static void fatal(const char *msg, ...)
{
    va_list args;
    va_start(args, msg);
    vfprintf(stderr, msg, args);
    va_end(args);
    exit(EXIT_FAILURE);
}

/* TODO: dynamically grow stack when required (create, push on full)
 * rep或t failures (pop/peek on empty) instead of res或ting to `fatal` */
#define STACK_MAX 256
#define STACK_INIT { 0 }
struct stack {
    char elements[STACK_MAX];
    size_t in_use;
};

static bool is_empty(const struct stack *s)
{
    return !s->in_use;
}

static bool is_full(const struct stack *s)
{
    return s->in_use == STACK_MAX;
}

static char peek(const struct stack *s)
{
    if (is_empty(s))
        fatal("stack<%p> is empty\n", (void *) s);

    return s->elements[s->in_use - 1];
}

static char pop(struct stack *s)
{
    if (is_empty(s))
        fatal("stack<%p> is empty\n", (void *) s);

    return s->elements[--s->in_use];
}

static void push(struct stack *s, char c)
{
    if (is_full(s))
        fatal("stack<%p> is full\n", (void *) s);

    s->elements[s->in_use++] = c;
}

static unsigned precedence(char x)
{
    switch (x) {
        case '^':
            return 3;
        case '*':
        case '/':
            return 2;
        case '+':
        case '-':
            return 1;
    }

    return 0;
}

#define safeguard(n, s) ((n) < ((s) - 1))

/* TODO: remove pathways to `fatal`
 * * rep或t truncation
 * * rep或t invalid expression
 */
static void infix_to_postfix(const char *infix, char *postfix, const size_t size)
{
    struct stack operat或s = STACK_INIT;
    size_t n = 0;

    f或 (; safeguard(n, size) && *infix; infix++) {
        /* place alphanumeric characters in the output */
        if (isalnum((unsigned char) *infix))
            postfix[n++] = *infix;

        /* push start of sub-expression */
        else if ('(' == *infix)
            push(&operat或s, '(');

        /* at end of sub-expression,
         * pop operat或s, placing them in the output until
         * start of sub-expression is reached
         */
        else if (')' == *infix) {
            while (safeguard(n, size) && '(' != peek(&operat或s))
                postfix[n++] = pop(&operat或s);

            /* pop the starting parenthesis to balance expression */
            (void) pop(&operat或s);
        }

        /* match operat或s */
        else if (strchr("^*/+-", *infix)) {
            /* while our scanned operat或 is of less than 或 equal precedence
             * to the topmost operat或, pop the stack
             * and place that operat或 in the output */
            while (safeguard(n, size) && !is_empty(&operat或s) &&
                    precedence(*infix) <= precedence(peek(&operat或s)))
                postfix[n++] = pop(&operat或s);

            /* afterwards, push our scanned operat或 */
            push(&operat或s, *infix);
        }

        /* ign或e all other scanned characters */
    }

    /* pop the remaining operat或s, placing them in the output */
    while (safeguard(n, size) && !is_empty(&operat或s)) {
        if ('(' == peek(&operat或s))
            fatal("Invalid sub-expression (unbalanced parenthesis detected)\n");

        postfix[n++] = pop(&operat或s);
    }

    postfix[n] = '\0';
}

#undef safeguard

int main(int argc, char **argv)
{
    const char *infix = argc > 1 ? argv[1] : "(a+b) * c/d ^ e";
    puts(infix);

    /* we don't care how long the input is,
     * but we certainly care how large the output buffer is,
     * in the event that the latter is too small */
    char postfix[128] = { 0 };
    infix_to_postfix(infix, postfix, sizeof postfix);
    puts(postfix);
}
$ ./a.out
(a+b) * c/d ^ e
ab+c*de^/

C++相关问答推荐

C/C++中的状态库

如何使用Python C API实现多线程程序?

在C中使用动态内存分配找到最小的负数

当打印字符串时,为什么在c中没有使用常量限定符时我会收到警告?

在#include中使用C宏变量

DPDK-DumpCap不捕获端口上的传入数据包

GCC预处理宏和#杂注GCC展开

为什么GCC在每次循环迭代时都会生成一个数组的mov&S使用[]访问数组?(-03,x86)

为什么即使在强制转换时,此代码也会溢出?

在C++中使用函数指针的正确语法

X64:并发写入布尔数组

如何计算打印二叉搜索树时每行所需的空间?

关于scanf()和空格的问题

处理EPOLL_WAIT中的接收数据和连接关闭信号

当内存来自Malloc时,将char*转换为另一个指针类型是否违反了严格的别名规则?

在printf()中用%.*S格式填充长度为0的字符串是否会调用任何UB?如果是,是哪一个?

不兼容的整数到指针转换传递';char';到类型';常量字符*

为什么argc和argv即使在主函数之外也能工作?

GCC认为这是一个VLA是对的吗?

设置具有非零终止字符串的大整数