I have spent the last two hours trying to debug my code that is supposed to check if the input consists of well-formed brackets. What I mean by well formed is that ()()[]
or ([()])
are acceptable but ((((()
is not.
I'm not allowed to use any header file apart from <stdio.h>
#include <stdio.h>
void cross(char str[], int i, int j) {
str[i] = 'X';
str[j] = 'X';
}
int iscrossed(char str[]) {
int i = 0;
while (str[i] != '\0') {
if (str[i] != 'X')
return 0;
i ;
}
return 1;
}
int check(char str[]) {
int i = 1, j;
while (str[i] != '\0') {
if (str[i] == ')') {
for (j = i - 1; j >= 0; j--) {
if (str[j] == '(') {
cross(str, str[i], str[j]);
}
break;
}
} else
if (str[i] == ']') {
for (j = i - 1; j >= 0; j--) {
if (str[j] == '[') {
cross(str, str[i], str[j]);
}
break;
}
}
i ;
}
if (iscrossed(str) == 1)
return 1;
else
return 0;
}
int main() {
char str[20];
scanf("%s", str);
printf("%d\n", check(str));
}
For certain inputs the program prints a zero followed by a segmentation fault and for the others it just prints a zero. Please keep in mind that I'm a beginner programmer so please don't include too much heavy stuff in your hints. I'd be grateful for any help on this.
Edit: It would be wonderful if your answer tells me the errors in my code, because that was my question in the first place.
CodePudding user response:
Pseudocode of a possible answer:
initialize char[] unclosed
int latest_unclosed_index = -1
for each char in string {
if char == opening_bracket {
latest_unclosed_index = 1
unclosed[latest_unclosed_index] = char
} else if char == closing_bracket {
if latest_unclosed_index < 0 {
return false
} else if char == closing_of(unclosed[latest_unclosed_index]) {
unclosed[latest_unclosed_index] = null
latest_unclosed_index -= 1
} else {
return false
}
}
}
if latest_unclosed_index == -1 {
return true
} else {
return false
}
This works by keeping an array of all unclosed opening brackets in the order that you encounter them in, and removing them whenever you encounter a closing bracket, as a sort of stack.
This solution has a complexity of O(n).
A problem with this implementation is that there is an unknown amount of brackets in string, which may cause the array to overflow if it isn't large enough.
Solution:
- To be sure that this solution doesn't overflow, the size of the array should be at least half the size of the input string, and you'll have to check at each character if there are enough characters left in the input string to be able to completely close all brackets.
- Use a list implementation (or write your own) instead of an array for
unclosed
.
CodePudding user response:
Here a simple recursive solution:
#include <stdio.h>
int brace(const char **s, char cc)
{
while(1) {
if(**s == cc) { return 0; }
switch(**s) {
case '\0': return -1;
case '[': (*s); if(brace(s, ']')) { return -1; } (*s); break;
case '{': (*s); if(brace(s, '}')) { return -1; } (*s); break;
case '(': (*s); if(brace(s, ')')) { return -1; } (*s); break;
case ']':
case '}':
case ')': return -1;
default: (*s);
}
}
}
int check_brace(const char *s)
{
return brace(&s, '\0');
}
int main()
{
printf("%d\n", check_brace(" hekl(l o{ asdf } te)ts()({})"));
}
Returns -1
when somethings wrong. Otherwise the length of the string.
CodePudding user response:
If its ok for you to use stdlib.h
then,
#include <stdio.h>
#include <stdlib.h>
#define bool int
// structure of a stack node
struct sNode {
char data;
struct sNode* next;
};
// Function to push an item to stack
void push(struct sNode** top_ref, int new_data);
// Function to pop an item from stack
int pop(struct sNode** top_ref);
// Returns 1 if character1 and character2 are matching left
// and right Brackets
bool isMatchingPair(char character1, char character2)
{
if (character1 == '(' && character2 == ')')
return 1;
else if (character1 == '{' && character2 == '}')
return 1;
else if (character1 == '[' && character2 == ']')
return 1;
else
return 0;
}
// Return 1 if expression has balanced Brackets
bool areBracketsBalanced(char exp[])
{
int i = 0;
// Declare an empty character stack
struct sNode* stack = NULL;
// Traverse the given expression to check matching
// brackets
while (exp[i])
{
// If the exp[i] is a starting bracket then push
// it
if (exp[i] == '{' || exp[i] == '(' || exp[i] == '[')
push(&stack, exp[i]);
// If exp[i] is an ending bracket then pop from
// stack and check if the popped bracket is a
// matching pair*/
if (exp[i] == '}' || exp[i] == ')'
|| exp[i] == ']') {
// If we see an ending bracket without a pair
// then return false
if (stack == NULL)
return 0;
// Pop the top element from stack, if it is not
// a pair bracket of character then there is a
// mismatch.
// his happens for expressions like {(})
else if (!isMatchingPair(pop(&stack), exp[i]))
return 0;
}
i ;
}
// If there is something left in expression then there
// is a starting bracket without a closing
// bracket
if (stack == NULL)
return 1; // balanced
else
return 0; // not balanced
}
// Driver code
int main()
{
char exp[100] = "{()}[]";
// Function call
if (areBracketsBalanced(exp))
printf("Balanced \n");
else
printf("Not Balanced \n");
return 0;
}
// Function to push an item to stack
void push(struct sNode** top_ref, int new_data)
{
// allocate node
struct sNode* new_node
= (struct sNode*)malloc(sizeof(struct sNode));
if (new_node == NULL) {
printf("Stack overflow n");
getchar();
exit(0);
}
// put in the data
new_node->data = new_data;
// link the old list off the new node
new_node->next = (*top_ref);
// move the head to point to the new node
(*top_ref) = new_node;
}
// Function to pop an item from stack
int pop(struct sNode** top_ref)
{
char res;
struct sNode* top;
// If stack is empty then error
if (*top_ref == NULL) {
printf("Stack overflow n");
getchar();
exit(0);
}
else {
top = *top_ref;
res = top->data;
*top_ref = top->next;
free(top);
return res;
}
}
Features
- Support nested parantheses like
(())
- Support bad nestings such as
([)]
- Commented but not by me (see the below spoiler)
Note: i feel guilty that i have copied code from
Pseudocode Like Block code!
If it's not ok for you to use
stdlib.h
,then someone may edit this code and remove the errors that occur when we remove that line(#include <stdlib.h>
),I am not ac
guy and i don't know to edit,i just copy pasted !CodePudding user response:
First attempt didn't worked with bad nesting, as MOehm wrote in the comments. Storing the opened braces that not have been closed yet helps to recognize bad nesting. The last opened brace will determine which closing brace is need.
#include <stdio.h> int check(char str[], int size) { char opened[size/2]; char close; int i = 0; int pos = 0; int error = 0; while((i < size) || (pos < size/2)) { if((str[i] == '(') || (str[i] == '[')) { opened[pos] = str[i]; pos ; } else if((str[i] == ')') || (str[i] == ']')) { if(str[i] == close) { opened[pos-1] = 0; pos--; } else { error = 1; break; } } printf("%s\n", opened); if(pos > 0) { switch(opened[pos-1]) { case '(': close = ')'; break; case '[': close = ']'; break; } } else close = 0; i ; } return error; } int main() { char str[20]; printf("%d\n", check(str, sizeof(str))); return 0; }
CodePudding user response:
There are multiple errors in your code:
- you call
cross(str, str[i], str[j]);
instead ofcross(str, i, j);
when you find matches for parentheses and brackets.- the
break
statement should be moved inside theif
block.- your method does not allow detection of nesting errors
- your method would have undefined behavior if
str
is an empty string (which you cannot input viascanf()
)Here is a modified version:
#include <stdio.h> void cross(char str[], int i, int j) { str[i] = str[j] = 'X'; } int iscrossed(char str[]) { int i = 0; while (str[i] != '\0') { if (str[i] != 'X') return 0; i ; } return 1; } int check(char str[]) { int i = 0, j; while (str[i] != '\0') { if (str[i] == ')') { for (j = i - 1; j >= 0; j--) { if (str[j] == '(') { cross(str, i, j); break; } } } else if (str[i] == ']') { for (j = i - 1; j >= 0; j--) { if (str[j] == '[') { cross(str, i, j); break; } } } i ; } return iscrossed(str); } int main() { char str[80]; if (scanf("ys", str) == 1) { printf("%d\n", check(str)); } return 0; }
Here is a simpler alternative:
#include <stdio.h> const char *check(const char str[], int endc) { while (str) { int c = *str ; switch (c) { case '(': str = check(str, ')'); break; case '[': str = check(str, ']'); break; case '{': str = check(str, '}'); break; case ')': case ']': case '}': case '\0': return c == endc ? str : NULL; } } return NULL; } int main() { char str[80]; if (fgets(str, sizeof str, stdin)) { printf("%d\n", check(str, '\0') != NULL); } return 0; }