Search code examples
cstackparentheses

Reading input through stdin using fgets error


For class, I have to write a code that checks for balanced parentheses. The input will be given through stdin (running it as: code.exe < in.txt)

The input is formatted like this:

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

I coded it like this:

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++;
    }
}

But, the output that comes out is wrong. I've already checked my balanced_parenthesis function separately, and it does work, which leads me to believe that the error is in reading the input.

Am I using fgets or strcmp wrong? Is there a better way to read the input?


Edit:

Full Code is shown here:

#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++;
            }
        }
    }
}

Sample Input:

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***

Expected Output:

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

Solution

  • There is a logical flaw in your code:-

    for every line that you wish to check - before that you must ensure to rest the state of the stack. That's what you didn't do which caused problem.

    void stack_reset(){
        top = -1;
    }
    

    In main()

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

    This change will make your code work. Otherwise it was handling with previous state also.

    As you have \n as input to the char array test your comparison fails.

    Considering that your rest of the code is alright , there is a single change you need to do to make this work. (This is problem if there is \n at the end of the input file). It is still good to add this solution - that will make this solution work irrespective of newline at the last line of the file.

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

    You are overwriting the \n with the \0 because strcspn returns the number of character read before it encounters any of the character specified in the second parameter to strcspn.

    Also once return statement is executed there is no use of the break statement as control never reach that point. And you exit from the function.

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

    The way you took input won't fail when you have the input file ended with no newline. If there is then the last comparison with ***end*** will fail.

    The reason behind making the reset() function separate from your main() module is that - if later you need to change the implementation of stack then the user code won't be affected. It can still call the reset() and be sure that it will reset the state of the stack. Also as another suggestion, try not to make the stack variable top global, even better if you can pass the structure from function to function instead of using global one.