【问题标题】:Reading input through stdin using fgets error使用 fgets 错误通过标准输入读取输入
【发布时间】:2018-05-09 02:46:11
【问题描述】:

对于类,我必须编写一个检查平衡括号的代码。输入将通过标准输入(运行方式为:code.exe

输入格式如下:

CASE 1: (())
CASE 2: [})(
CASE n: ...
***end***

我是这样编码的:

int main(void) {
    char test[200];
    char str[200];
    char end[] = "***end***";
    int caseNo = 1;
    int j;
    int flag;

    while(1) {
    if(strcmp(fgets(test, 200, stdin), end) == 0) {
        break;
    } else {
        strcpy(str, test);
        int len = strlen(str);
        for(int i = 0; i < len; i++) {
            if(str[i] == ':') {
                j = i + 2;
                break;
            }
        }

        flag = balanced_parenthesis(str, j);

        if(flag == 0) {
            printf("CASE %d: NOT BALANCED\n", caseNo);
        } else if(flag == 1) {
            printf("CASE %d: BALANCED\n", caseNo);
        }
        caseNo++;
    }
}

但是,输出的结果是错误的。我已经单独检查了我的 balance_parenthesis 函数,它确实有效,这让我相信错误在于读取输入。

我是否使用了 fgets 或 strcmp 错误?有没有更好的方法来读取输入?


编辑:

此处显示完整代码:

#include <stdio.h>
#include <string.h>

int top = -1;
char stack[200];

void push(char c) {
    top++;
    stack[top] = c;
}

char pop() {
    return(stack[top--]);
}

int pairs(char open, char close) {
    if(open == '(' && close == ')') {
        return 1;
    } else if (open == '[' && close == ']') {
        return 1;
    } else if (open == '{' && close == '}') {
        return 1;
    }
    return 0;
}

int balanced_parenthesis(char str[], int j) {
    int len = strlen(str);
    for(int i = j; i < len; i++) {
        if((str[i] == '(') || (str[i] == '[') || (str[i] == '{')) {
            push(str[i]);
        } 
        if((str[i] == ')') || (str[i] == ']') || (str[i] == '}')) {
            if(top == -1) { //empty
                return 0;
            } else {
                char temp = pop();
                if(pairs(temp, str[i]) == 0) {
                    return 0; //not pairs
                }
            }
        }
    }

    if(top == -1) {
        return 1; //balanced
    } else {
        return 0; //not balanced
    }
}

int main(void) {
    char test[200];
    char str[200];
    char end[] = "***end***";
    int caseNo = 1;
    int j;
    int flag;

    while(1) {
        if(fgets(test, 200, stdin) == NULL) {
            break;
        } else {
            test[strcspn(test, "\n")] = '\0';
            if(strcmp(test, end) == 0) {
                break;
            } else {
                strcpy(str, test);
                int len = strlen(str);
                for(int i = 0; i < len; i++) {
                    if(str[i] == ':') {
                        j = i + 2;
                        break;
                    }
                }

                flag = balanced_parenthesis(str, j);

                if(flag == 0) {
                    printf("CASE %d: NOT BALANCED\n", caseNo);
                } else if(flag == 1) {
                    printf("CASE %d: BALANCED\n", caseNo);
                }
                caseNo++;
            }
        }
    }
}

示例输入:

CASE 1: ([[]{()}])()
CASE 2: ()[]{}
CASE 3: (([[]))
CASE 4: (()}
CASE 5: (()()()())
CASE 6: (((())))
CASE 7: (()((())()))
CASE 8: ((((((())
CASE 9: ()))
CASE 10: (()()(()
CASE 11: ][
CASE 12: ({)}
***end***

预期输出:

CASE 1: BALANCED
CASE 2: BALANCED
CASE 3: NOT BALANCED
CASE 4: NOT BALANCED
CASE 5: BALANCED
CASE 6: BALANCED
CASE 7: BALANCED
CASE 8: NOT BALANCED
CASE 9: NOT BALANCED
CASE 10: NOT BALANCED
CASE 11: NOT BALANCED
CASE 12: NOT BALANCED

【问题讨论】:

  • if(strcmp(fgets(test, 200, stdin), end) == 0) {比较之前需要删除尾随换行符
  • 使用test[strcspn(test,"\n")]='\0' 覆盖'\n'。然后进行比较strcmp(test,end)==0breakreturn 0 之后是多余的。
  • 我尝试按照您的建议使用 strcspn,现在我可以在没有 '\n' 的情况下读取输入,但是输出仍然不正确:/
  • 你知道fgets可能返回null吗?
  • 我不认为我可以发布问题链接,抱歉。而且我目前正在读取返回类型,并且我添加了一条语句来捕获 fgets 是否返回 NULL,但它仍然输出不正确的输出。

标签: c stack parentheses


【解决方案1】:

您的代码存在逻辑缺陷:-

对于您希望检查的每一行 - 在此之前您必须确保保持堆栈状态。那是你没有做的事情导致了问题。

void stack_reset(){
    top = -1;
}

main()

  ...
  if(strcmp(test, end) == 0) {
        break;
    } else {
        reset();
        strcpy(str, test);
        ...

此更改将使您的代码正常工作。否则它也在处理以前的状态。

由于您将\n 作为字符数组test 的输入,因此您的比较失败。

考虑到您的其余代码都没有问题,您需要进行一项更改才能使其正常工作。 (如果输入文件末尾有\n,则会出现问题)。添加这个解决方案仍然很好 - 这将使这个解决方案无论文件最后一行的换行如何都可以工作。

while(1) {
    if( !fgets(test, 200, stdin) ){
       /* error handling*/
    }
    test[strcspn(test,"\n")]='\0';
    if(strcmp(test, end) == 0) {
        break;
    } else {
        ...

您正在用\0 覆盖\n,因为strcspn 在遇到strcspn 的第二个参数中指定的任何字符之前返回读取的字符数。

同样,一旦return 语句被执行,break 语句就不再使用,因为控制永远不会到达那个点。然后退出函数。

            if(pairs(temp, str[i]) == 0) {
                return 0; //not pairs
                // break; <-- not needed.
            } 

当您的输入文件以没有换行符结束时,您输入的方式不会失败。如果有,则与***end*** 的最后一次比较将失败。

reset() 函数与main() 模块分开的原因是 - 如果稍后您需要更改stack 的实现,那么用户代码将不会受到影响。它仍然可以调用reset() 并确保它会重置堆栈的状态。另外作为另一个建议,尽量不要使堆栈变量top 成为全局变量,如果您可以将结构从函数传递到函数而不是使用全局变量,那就更好了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多