【问题标题】:semantical error with parenthesis balancing here此处括号平衡的语义错误
【发布时间】:2019-05-24 05:25:33
【问题描述】:

我编写了一个 C 代码来检查简单的括号平衡,如果平衡,则分别打印 NOYES

问题是我得到了所有输入的NO。因此我认为这是一个语义错误但找不到它(我已经尝试了 2 天:p)

有人可以帮我吗?谢谢!

#include <stdio.h>
#include <stdlib.h>

typedef struct stack {
    char s[1000];
    int top;
} STACK;

void create(STACK *sptr) {
    sptr->top = -1;
}

int isEmpty(STACK *sptr) {
    if (sptr->top == -1)
        return 1;
    else
        return 0;
}

void push(STACK *sptr, char data) {
    sptr->s[++sptr->top] = data;
}

char pop(STACK *sptr) {
    if (isEmpty(sptr) == 0)
        return sptr->s[sptr -> top];
    else
        return '$';
}

char *isBalanced(char *s, STACK *sptr) {
    char *y, *n;
    int i = 0;
    y = (char*)malloc(sizeof(char) * 4);
    y[0] = 'Y';
    y[1] = 'E';
    y[2] = 'S';
    y[3] = '\0';
    n = (char*)malloc(sizeof(char) * 3);
    n[0] = 'N';
    n[1] = 'O';
    n[2] = '\0';

    while (s[i] != '\0') {
        if (s[i] == '(' || s[i] == '{' || s[i] == '[') {
            push(sptr, s[i]);
        } else {
            char x = pop(sptr);
            switch (s[i]) {
              case ')':
                if (x != '(') 
                    return n;
                break;

              case '}':
                if (x != '{') 
                    return n;
                break;

              case ']':
                if (x != '[') 
                    return n;
                break;
            }
        }
        ++i;
    }

    if (isEmpty(sptr))
        return y;
    else
        return n;
}

int main() {
    STACK *sptr = (STACK *)malloc(sizeof(STACK));
    char c[21];
    int ch;
    do {
        printf("enter sequence:");
        scanf("%s", c);
        char *msg = isBalanced(c, sptr);
        printf("%s", msg);
        printf("choice?:");
        scanf("%d", &ch);
    } while(ch);
}

更新代码:

#include <stdio.h>
#include <stdlib.h>

typedef struct stack {
    char s[1000];
    int top;
} STACK;

void create(STACK *sptr) {
    sptr->top = -1;
}

int isEmpty(STACK *sptr) {
    if (sptr->top == -1)
        return 1;
    else 
        return 0;
}

void push(STACK *sptr, char data) {
    sptr->s[++sptr->top] = data;
}

char pop(STACK *sptr) {
    if (isEmpty(sptr) == 0)
        return sptr->s[sptr->top--];
    else
        return '$';
}

int isBalanced(char *s, STACK *sptr) {
    int i = 0;

    while (s[i] != '\0') {
        if (s[i] == '(' || s[i] == '{' || s[i] == '[') {
            push(sptr, s[i]);
        } else {
            char x = pop(sptr);
            switch (s[i]) {
              case ')':
                if (x != '(')
                    return 0; 
                break;
              case '}':
                if (x != '{') 
                    return 0;
                break;
              case ']':
                if (x != '[') 
                    return 0;
                break;
            }
        }
        ++i;
    }

    if (isEmpty(sptr))
        return 1;
    else 
        return 0;
}

int main() {
    STACK *sptr = malloc(sizeof(STACK));
    char c[21];
    int ch;
    do {
        printf("enter sequence:");
        scanf("%s", c);
        printf("%s", (isBalanced(c, sptr) ? "YES" : "NO"));
        printf("choice?:");
        scanf("%d", &ch);

    } while(ch);
}

【问题讨论】:

  • 在处理输入时,您是否调试过代码以观察相关变量的值,包括 scanf() 的返回值?
  • 您忽略了 scanf() 的返回值,风险自负。考虑不要。
  • OT 再次:C 中的比较无论如何都会评估为 1 (true)/0 (false),因此您可能/应该更喜欢 return sptr -&gt; top == -1;(或 size == 0,如果您遵循我之前的建议) .
  • pop 的每个字符都不是任何类型的左括号 - 如果还有除右括号以外的字符,这将失败...
  • 请注意,点. 和箭头-&gt; 运算符绑定非常紧密;你不应该在它们周围放置空格。

标签: c function parentheses


【解决方案1】:

在您的pop 函数中,您不会递减top,因此您的isEmpty 函数始终返回false

因此你总是返回no

char* isBalanced(char* s, STACK* sptr)
{
    ....

   if(isEmpty(sptr)) return y;
   else return n;
}

以下是正确的实现:

char pop(STACK* sptr)
{
    if(isEmpty(sptr) == 0)
        return sptr->s[sptr->top--];
    else
        return '$';
}

【讨论】:

    【解决方案2】:

    我会添加标志以查看哪个不匹配

    unsigned match(const char *f)
    {
        int p = 0,s = 0,b = 0;
        while(*f)
        {
            switch(*f++)
            {
                case '(':
                    p++;
                    break;
                case ')':
                    p -= !!p;
                    break;
    
                case '[':
                    s++;
                    break;
                case ']':
                    s -= !!s;
                    break;
    
                case '{':
                    b++;
                    break;
                case '}':
                    b -= !!b;
                    break;
                default:
                    break;
            }
        }
        return (!p) | ((!s) << 1) | ((!b) << 2);
    }
    

    不是堆栈版本,只是为了想法。添加push和pop比较容易

    【讨论】:

    • 因此,基本上,这对于检查平衡括号不起作用。正确的?它只确保)1( 通过。
    • @usr2564301 是 - 圣诞节编码,但不是在编辑之后
    【解决方案3】:

    我假设这个想法是这样的:始终允许打开括号(在分析的文本中),但关闭括号必须与最后打开的匹配。这就是为什么需要堆栈的原因。另外,最后,如果堆栈不为空,则意味着某些括号没有关闭。

    因此,您应该使用堆栈,但仅在遇到括号时使用 - 无论是打开还是关闭。

    在isBalanced()函数中,主循环可能是这样的:

    while (s[i] != '\0') {
        if ( s[i] == '(' || s[i] == '{' || s[i] == '[' ) {
            // opening - remember it
            push(sptr, s[i]);
        } else if ( s[i] == ')' || s[i] == '}' || s[i] == ']' ) {
            // closing - it should match
            if ( ! popmatch(sptr, s[i]) )
              return n;
        }
        ++i;
    }
    

    其余功能正常。现在,我修改了 pop() 函数:重命名为 popmatch,因为它应该检查参数是否与栈顶匹配。如果是,则弹出堆栈并返回 OK。所以函数是:

    char popmatch(STACK* sptr, char c) {
        // an empty stack can not match
        if (isEmpty(sptr))
          return 0;
    
        // not empty, can check for equality
        if ( c =! sptr->s[sptr->top] )
          return 0;
          // does not match!
    
        // ok, it matches so pop it and return ok
        sptr->top--;
        return 1;
    }
    

    请注意,代码很好地反映了“分析”;当分析简洁明了,代码跟随分析,结果往往也简洁明了。

    【讨论】:

    • @lamyabhasin 你能发布你使用的代码吗?调试会话肯定会发现错误。
    • 我发帖向上滚动
    • 你使用什么类型的调试器?我现在不使用任何东西。我有一台 macbook air
    • @lamyabhasin 我没有看到新代码,也没有看到 popmatch() 函数。关于调试器,我认为在linux系统上使用gdb,但并不是很重要。
    【解决方案4】:

    以下是您的代码中的一些主要问题:

    • 在使用之前,您没有使用create(sptr) 正确初始化堆栈,最好在定义它的main() 中。您的代码具有未定义的行为。它偶然打印NO,可能是因为sptr-&gt;top 的初始值为0,这使得堆栈非空。

    • 只有在遇到结束分隔符)]} 时才应从堆栈中弹出。

    • 您应该通过告诉scanf() 要读入c 的最大字符数来防止潜在的缓冲区溢出:scanf("%20s", c)。此外,您应该测试返回值以避免在文件末尾出现未定义的行为。

    • 另请注意,可以将 STACK 设为局部变量,以避免堆分配和潜在的分配失败,这会导致未定义的行为,因为它未经测试。

    这是一个更正的版本:

    #include <stdio.h>
    
    typedef struct stack {
        char s[1000];
        int top;
    } STACK;
    
    void create(STACK *sptr) {
        sptr->top = -1;
    }
    
    int isEmpty(STACK *sptr) {
        if (sptr->top == -1)
            return 1;
        else 
            return 0;
    }
    
    void push(STACK *sptr, char data) {
        sptr->s[++sptr->top] = data;
    }
    
    char pop(STACK *sptr) {
        if (isEmpty(sptr) == 0)
            return sptr->s[sptr->top--];
        else
            return '$';
    }
    
    int isBalanced(char *s, STACK *sptr) {
        int i;
    
        for (i = 0; s[i] != '\0'; i++) {
            switch (s[i]) {
              case '(':
              case '{':
              case '[':
                push(sptr, s[i]);
                break;
              case ')':
                if (pop(sptr) != '(')
                    return 0; 
                break;
              case '}':
                if (pop(sptr) != '{') 
                    return 0;
                break;
              case ']':
                if (pop(sptr) != '[') 
                    return 0;
                break;
            }
        }
        return isEmpty(sptr);
    }
    
    int main() {
        STACK s, *sptr = &s;
        char c[100];
        int ch;
    
        do {
            printf("Enter sequence: ");
            if (scanf(" %99[^\n]", c) != 1)
                break;
            create(sptr);
            printf("%s\n", isBalanced(c, sptr) ? "YES" : "NO");
            printf("Choice? ");
            if (scanf("%d", &ch) != 1)
                break;
        } while (ch);
    
        return 0;
    }
    

    【讨论】:

    • if (fgets (c, sizeof c, stdin) == NULL) break; 作为奖励。没有空格的序列似乎不太可读。
    • @DavidC.Rankin:您对空格的看法是正确的,但是在此处使用 fgets() 并在下一个问题中使用 scanf() 会导致此循环的第二次迭代出现意外行为。我用不同的修复更新了答案。
    • @chqrlie 哦!我终于明白了我的错误。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-10
    • 2013-06-05
    • 1970-01-01
    相关资源
    最近更新 更多