Infix to Postfix Algorithm in C - c

I'm solve an exercise in which one of the functions has to translate infix notation to postfix notation. Here follows my whole code
#include<stdio.h>
#define MAX 100
char stack[MAX];
int top;
void compact(char Descomp[], char Compac[]);
void init_stack();
int push(char Elem);
int desempilha(char *Elem);
int priority(char Operator);
int arity(char Exp[], int position);
int translate_pos(char exp[], char exp_pos[]);
int main()
{
char Exp[MAX]; /* stores the expression read from stdin */
char Exp_compact[MAX]; /* stores expression without spaces */
char Exp_pos[MAX]; /* stores the expression after the translation for postfix*/
int indicator; /* indicate if an error occurred, 0 for NO ERROR and -1 for ERROR*/
indicator = 0;
printf("\nType the expression: ");
gets(Exp);
compact(Exp, Exp_compact);
indicator = translate_pos(Exp_compact, Exp_pos);
puts(Exp_pos);
return indicator;
}
/* compact function delete spaces within the expression read from stdin */
void compact(char Descomp[], char Compac[])
{
int i;
int j;
i = 0;
j = 0;
while(Descomp[j] != '\0')
{
if(Descomp[j] != ' ')
{
Compac[i] = Descomp[j];
i++;
}
j++;
}
}
/* initiate the stack by setting top = -1 */
void init_stack()
{
top = -1;
}
/* puts the element Elem in the stack */
int push(char Elem)
{
if(top == MAX - 1) /* Stack is full */
return -1;
top++;
stack[top] = Elem;
return 0;
}
/* remove the element in stack[top] and puts it in &Elem*/
int pop(char *Elem)
{
if(top == -1) /* stack is empty */
return -1;
*Elem = stack[top];
top--;
return 0;
}
/* Return the priority of an operator */
int priority(char Operator)
{
switch(Operator)
{
case '+': return 1;
case '-': return 1;
case '*': return 2;
case '/': return 2;
case '^': return 3;
case '(': return 4;
case ')': return 5;
default : return 0;
}
}
/* returns the arity of CONSTANTS + - * / and ^, for ( an ) is merely symbolic */
int arity(char Exp[], int position)
{
if(priority(Exp[position]) == 1)
{
if( (position == 0) || ( (priority(Exp[position - 1]) >= 1) && (priority(Exp[position - 1]) <= 3) ))
return 1;
else
return 2;
}
else if( (priority(Exp[position]) > 1) && (priority(Exp[position]) <= 4))
return 2;
else
return priority(Exp[position]);
}
/* reads an infix expression and returns postfix expression */
int translate_pos(char exp[], char exp_pos[])
{
int i;
int j;
int ind;
char trash;
i = 0;
j = 0;
ind = 0;
trash = ' ';
init_stack();
while(exp[i]!= '\0')
{
if(arity(exp, i) == 0)
{
exp_pos[j] = exp[i];
j++;
}
if(arity(exp, i) == 1)
{
switch(exp[i])
{
case '-':
{
exp_pos[j] = exp_pos[i];
j++;
}
case '+': trash = exp_pos[i];
}
}
if(arity(exp, i) == 2)
{
while((top != -1) && (priority(stack[top]) <= priority(exp[i])))
{
ind = pop(&exp_pos[j]);
j++;
}
ind = push(exp[i]);
}
if(priority(exp[i]) == 4)
{
ind = push(exp[i]);
}
if(priority(exp[i]) == 5)
{
while( (top != -1) && (stack[top] != '('))
{
ind = pop(&exp_pos[j]);
j++;
}
if(stack[top] == '(')
ind = pop(&trash);
}
i++;
}
while(top != -1)
{
ind = pop(&exp_pos[j]);
j++;
}
return ind;
}
The algorithm I used to translate the expression is
while there is token to be read;
read the token;
if token is a constant
push it to Exp_Postfix;
if token is '('
push it to stack
if token is ')'
pop from the stack all symbols until '(' be find and remove '(' from the stack
if token is an operator and its arity is 2
pop all operators with less or equal priority than the token and store then in the Exp_Postfix;
push token to the stack;
if token is an operator and its arity is 1
if token is '-'
push it to Exp_postfix;
if token is '+'
pass to the next token;
pop all remaining symbols in the stack and push then, in order, to the Exp_Postfix;
I compiled the .c archive using
gcc -Wall archive.c -o archive
and executed it. I give the expression
5+(6*9^14)
It the returned expression was
5
I do not now if the error is in my code or in solution to the problem.

There are an awful lot of problems, here, for instance:
compact() and translate_pos() leave Exp_compact and Exp_pos, respectively, without a terminating \0, so you're getting garbage printed out.
your arity() function is returning 2 for an opening parenthesis.
in the first switch statement of translate_pos(), you're missing break statements.
Your priority comparison in translate_pos() when arity is 2 is back to front.
When you're comparing operator precedence, you should treat an opening parenthesis specially, since it should have the lowest precedence when on the top of the stack.
You should have a lot more else keywords in translate_pos().
You're using gets(), which was always bad, and now has actually been removed from C.
I haven't exhaustively tested it, but here's a correct version that seems to work for all the test inputs I tried:
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
/* Function prototypes */
void compact(char Descomp[], char Compac[]);
void init_stack();
int push(char Elem);
int desempilha(char *Elem);
int priority(char Operator);
int arity(char Exp[], int position);
int translate_pos(char exp[], char exp_pos[]);
/* Stack variables */
#define MAX 100
char stack[MAX];
int top;
int main(void) {
char Exp[MAX];
char Exp_compact[MAX] = {0};
char Exp_pos[MAX] = {0};
int indicator = 0;
printf("\nType the expression: ");
fgets(Exp, MAX, stdin);
compact(Exp, Exp_compact);
indicator = translate_pos(Exp_compact, Exp_pos);
puts(Exp_pos);
return indicator;
}
/* compact function delete spaces within the expression read from stdin */
void compact(char Descomp[], char Compac[]) {
int i = 0;
int j = 0;
while ( Descomp[j] ) {
if ( !isspace(Descomp[j]) ) {
Compac[i++] = Descomp[j];
}
j++;
}
}
/* initiate the stack by setting top = -1 */
void init_stack() {
top = -1;
}
/* puts the element Elem in the stack */
int push(char Elem) {
if (top == MAX - 1) /* Stack is full */
return -1;
stack[++top] = Elem;
return 0;
}
/* remove the element in stack[top] and puts it in &Elem*/
int pop(char *Elem) {
if (top == -1) /* stack is empty */
return -1;
*Elem = stack[top--];
return 0;
}
/* Return the priority of an operator */
int priority(char Operator) {
switch (Operator) {
case '+':
return 1;
case '-':
return 1;
case '*':
return 2;
case '/':
return 2;
case '^':
return 3;
case '(':
return 4;
case ')':
return 5;
default:
return 0;
}
}
/* returns the arity of OPERATORS + - * / and ^,
* for ( an ) is merely symbolic */
int arity(char Exp[], int position) {
if ( priority(Exp[position]) == 1 ) {
if ( (position == 0) ||
((priority(Exp[position - 1]) >= 1) &&
(priority(Exp[position - 1]) <= 3)) ) {
return 1;
} else {
return 2;
}
} else if ( (priority(Exp[position]) > 1) &&
(priority(Exp[position]) <= 3) ) {
return 2;
} else {
return priority(Exp[position]);
}
}
/* reads an infix expression and returns postfix expression */
int translate_pos(char exp[], char exp_pos[]) {
int i = 0, j = 0, ind = 0;
char trash = ' ';
init_stack();
while ( exp[i] ) {
if ( arity(exp, i) == 0 ) {
exp_pos[j++] = exp[i];
} else if ( arity(exp, i) == 1 ) {
switch (exp[i]) {
case '-':
exp_pos[j++] = exp[i];
break;
case '+':
trash = exp_pos[i];
break;
default:
assert(0);
}
} else if (arity(exp, i) == 2) {
while ( (top != -1) &&
(priority(stack[top]) >= priority(exp[i])) &&
stack[top] != '(' ) {
ind = pop(&exp_pos[j++]);
}
ind = push(exp[i]);
} else if ( priority(exp[i]) == 4 ) {
ind = push(exp[i]);
} else if ( priority(exp[i]) == 5 ) {
while ( (top != -1) && (stack[top] != '(') ) {
ind = pop(&exp_pos[j++]);
}
if ( (top != - 1) && stack[top] == '(') {
ind = pop(&trash);
}
}
i++;
}
while (top != -1) {
ind = pop(&exp_pos[j++]);
}
return ind;
}
Gives the following output for various test cases:
paul#local:~/src/c/postfix$ ./postfix
Type the expression: 1+2
12+
paul#local:~/src/c/postfix$ ./postfix
Type the expression: (1+2)
12+
paul#local:~/src/c/postfix$ ./postfix
Type the expression: 1+2*3
123*+
paul#local:~/src/c/postfix$ ./postfix
Type the expression: (1+2)*3
12+3*
paul#local:~/src/c/postfix$ ./postfix
Type the expression: (3+4)*4/2
34+4*2/
paul#local:~/src/c/postfix$ ./postfix
Type the expression: 5+(6*9^14)
56914^*+
paul#local:~/src/c/postfix$
I'd suggest comparing my code to yours and trying to understand the individual differences to see where you were going wrong.

Related

How to make the calculator count the expression with spaces in the input?

I tried to make calculator supporting brackets, but
I have no idea how to deal if the user's input includes expression with spaces, for example:
input: (2 + 3) * 2
i got: 2
If it's normally get (2+3)*2, it counts 10
.
My code:
#include <stdio.h>
#define MAX_SIZE 1024
int insert_operand(int *operand, int * top_num, int num) /* data is pushed into the data stack*/
{
(*top_num) ++;
operand[*top_num] = num; /*save data*/
return 0; /*Exit normally*/
}
int insert_oper (char * oper , int *top_oper , char ch)
{
(*top_oper)++;
oper[*top_oper] = ch; /*save operator*/
return 0; /*Exit normally*/
}
int compare(char *oper , int *top_oper , char ch) /* compare the priority of the operating server*/
{
if((oper[*top_oper] == '-' || oper[*top_oper] == '+') /*Determine whether the current priority is higher than the priority of the operator at the top of the stack*/
&& (ch == '*' || ch == '/'))
{
return 0;
}
else if(*top_oper == -1 || ch == '('
|| (oper[*top_oper] == '(' && ch != ')')) /*Determine whether the operator stack is empty; whether the top operator is '('*/
{
return 0;
}
else if (oper[*top_oper] =='(' && ch == ')')
{
(*top_oper)--;
return 1;
}
else
{
return -1; /*Operate the operator*/
}
}
int deal_date(int *operand ,char *oper ,int *top_num, int *top_oper) /*perform data operation*/
{
int num_1 = operand[*top_num]; /*Take out two data from the data stack*/
int num_2 = operand[*top_num - 1];
int value = 0;
if(oper[*top_oper] == '+')
{
value = num_1 + num_2;
}
else if(oper[*top_oper] == '-')
{
value = num_2 - num_1;
}
else if(oper[*top_oper] == '*')
{
value = num_2 * num_1;
}
else if(oper[*top_oper] == '/')
{
value = num_2 / num_1;
}
(*top_num) --; /*Move the top of the data stack down one bit*/
operand[*top_num] = value; /*Push the obtained value into the data stack*/
(*top_oper) --; /*Move the top of the operator stack down one bit*/
}
int main()
{
int operand[MAX_SIZE] = {0}; /*data stack, initialize*/
int top_num = -1;
char oper[MAX_SIZE] = {0}; /*operator stack, initialize*/
int top_oper = -1;
char *str = (char *) malloc (sizeof(char) * 100); /*get expression (without =)*/
scanf("%s", str);
char* temp;
char dest[MAX_SIZE];
int num = 0;
int i = 0;
while(*str != '\0')
{
temp = dest;
while(*str >= '0' && *str <= '9') /*judging whether it is data*/
{
*temp = *str;
str++;
temp++;
} /*Encounter a symbol to exit*/
if(*str != '(' && *(temp - 1) != '\0') /*Determine whether the symbol is '('*/
{
*temp = '\0';
num = atoi(dest); /*convert string to number*/
insert_operand(operand, &top_num,num); /*Push data into the data stack*/
}
while(1)
{
i = compare(oper,&top_oper,*str); /*judgment operator priority*/
if(i == 0)
{
insert_oper(oper,&top_oper,*str); /*press operator*/
break;
}
else if(i == 1) /*judging whether the expression in brackets ends*/
{
str++;
}
else if(i == -1) /* data processing */
{
deal_date(operand,oper,&top_num,&top_oper);
}
}
`
str ++; /* point to the next character of the expression */
}
`
printf("%d\n",operand[0]); /*output result*/
return 0;
I tried to count the equation even if there is a space in it. Can someone please help?
Solving the problem by removing spaces:
So if you're working with equation as string you can simply remove spaces with function like this (there will be probably better way or function in library string.h but this was first guess):
char* DeleteSpaces( char* stringWithSpaces, size_t lengthOfString)
{
char* stringWithoutSpaces = (char*)calloc(lengthOfString + 1, sizeof(char));
if( !stringWithoutSpaces )
return NULL;
for( unsigned int x = 0, y = 0; x <= lengthOfString; x++, y++ )
{
if( stringWithSpaces[x] == ' ' ) // if the character is space
{
while( stringWithSpaces[x] == ' ' && x < lengthOfString ) // skip all the spaces OR go away before you hit '\0'
x++;
stringWithoutSpaces[y] = stringWithSpaces[x]; // then copy next character into new string
}
else // if there's no space just copy the character
stringWithoutSpaces[y] = stringWithSpaces[x];
}
return stringWithoutSpaces;
}
This will basically remove all spaces from your received equation. If you really need the smallest possible memory requirement you can use realloc() at the end of the function for more optimal memory usage.
Here's simple example of how to use the function so you can test it:
int main()
{
char firstString[] = "H e l l o w o r l d\0";
char* secondString;
secondString = DeleteSpaces( firstString, strlen(firstString) );
if( !secondString )
return -1;
printf( "%s", secondString );
free( secondString );
return 0;
}
Don't forget to use free(SecondString). I hope I helped you atleast a little :)
As with the previous answer, I added in a function to remove any spaces from the entered formula in order to process the requested calculation. Also, coupled with that, I revised the "scanf" input to read in all of the entered characters which looked to be another symptom you were facing. With that, following is a refactored version of your program with the additional space compression function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 1024
int insert_operand(int *operand, int * top_num, int num) /* data is pushed into the data stack*/
{
(*top_num) ++;
operand[*top_num] = num; /*save data*/
return 0; /*Exit normally*/
}
int insert_oper (char * oper , int *top_oper , char ch)
{
(*top_oper)++;
oper[*top_oper] = ch; /*save operator*/
return 0; /*Exit normally*/
}
int compare(char *oper , int *top_oper , char ch) /* compare the priority of the operating server*/
{
if((oper[*top_oper] == '-' || oper[*top_oper] == '+') /*Determine whether the current priority is higher than the priority of the operator at the top of the stack*/
&& (ch == '*' || ch == '/'))
{
return 0;
}
else if(*top_oper == -1 || ch == '('
|| (oper[*top_oper] == '(' && ch != ')')) /*Determine whether the operator stack is empty; whether the top operator is '('*/
{
return 0;
}
else if (oper[*top_oper] =='(' && ch == ')')
{
(*top_oper)--;
return 1;
}
else
{
return -1; /*Operate the operator*/
}
}
int deal_date(int *operand ,char *oper ,int *top_num, int *top_oper) /*perform data operation*/
{
int num_1 = operand[*top_num]; /*Take out two data from the data stack*/
int num_2 = operand[*top_num - 1];
int value = 0;
if(oper[*top_oper] == '+')
{
value = num_1 + num_2;
}
else if(oper[*top_oper] == '-')
{
value = num_2 - num_1;
}
else if(oper[*top_oper] == '*')
{
value = num_2 * num_1;
}
else if(oper[*top_oper] == '/')
{
value = num_2 / num_1;
}
(*top_num) --; /*Move the top of the data stack down one bit*/
operand[*top_num] = value; /*Push the obtained value into the data stack*/
(*top_oper) --; /*Move the top of the operator stack down one bit*/
return value;
}
void compress(char *stx) /* The additional function */
{
char work[101];
int i = strlen(stx);
strcpy(work, stx);
for (int j = 0; j < i; j++)
{
stx[j] = 0;
}
i = 0;
for (int j = 0; j < (int)strlen(work); j++)
{
if (work[j] != ' ')
{
stx[i] = work[j];
i++;
}
}
}
int main()
{
int operand[MAX_SIZE] = {0}; /*data stack, initialize*/
int top_num = -1;
char oper[MAX_SIZE] = {0}; /*operator stack, initialize*/
int top_oper = -1;
char *str = (char *) malloc (sizeof(char) * 100); /*get expression (without =)*/
//scanf("%s", str);
scanf("%[^\n]", str); /* Refined the scanf call to receive all characters prior to the newline/return character */
compress(str); /* Added this function to remove spaces */
char* temp;
char dest[MAX_SIZE];
int num = 0;
int i = 0;
while(*str != '\0')
{
temp = dest;
while(*str >= '0' && *str <= '9') /*judging whether it is data*/
{
*temp = *str;
str++;
temp++;
} /*Encounter a symbol to exit*/
if(*str != '(' && *(temp - 1) != '\0') /*Determine whether the symbol is '('*/
{
*temp = '\0';
num = atoi(dest); /*convert string to number*/
insert_operand(operand, &top_num,num); /*Push data into the data stack*/
}
while(1)
{
i = compare(oper,&top_oper,*str); /*judgment operator priority*/
if(i == 0)
{
insert_oper(oper,&top_oper,*str); /*press operator*/
break;
}
else if(i == 1) /*judging whether the expression in brackets ends*/
{
str++;
}
else if(i == -1) /* data processing */
{
deal_date(operand,oper,&top_num,&top_oper);
}
}
str ++; /* point to the next character of the expression */
}
printf("%d\n",operand[0]); /*output result*/
return 0;
}
Testing out your sample formula with some additional spacing to ensure the compression function was working properly, following was the terminal output.
#Vera:~/C_Programs/Console/Calculate/bin/Release$ ./Calculate
(2 + 3) * 2
10
Give that a try and see if it meets the spirit of your project.
As pointed out in the comments and other answers, the solution may be to simply "compact" the spaces out of the string before trying to analyse the string's content.
This doesn't require a lot of code:
#include <stdio.h>
char *stripSP( char *src ) {
for( char *d = src, *s = src; ( *d = *s ) != '\0'; s++ )
d += *d != ' ';
return src;
}
int main( void ) {
char *s[] = { "Hello", "H e l l ooo", "(2 + 5) * 3" };
for( int i = 0; i < 3; i++ ) {
printf( "From '%s' ", s[i] );
printf( "'%s'\n", stripSP( s[i] ) );
}
return 0;
}
From 'Hello' 'Hello'
From 'H e l l ooo' 'Hellooo'
From '(2 + 5) * 3' '(2+5)*3'
Even more compact would be to use array indexing:
char *stripSP( char s[] ) {
for( int f=0, t=0; (s[t] = s[f++]) != '\0'; t += s[t] != ' ' ) {}
return s;
}

How to check if the expression has division by 0 in calculator C? Floating point exception

I tried to make simple calculator supporting brackets and classic operators +,-,*,/ and I also need to eliminate division by zero in it. I may not be able to cope with it, I need to check if there is division by zero in the expression and if so function return 0. Now it returns Floating point exception. Can someone help?
My code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 1024
int insert_operand(int *operand, int * top_num, int num) /* data is pushed into the data stack*/
{
(*top_num) ++;
operand[*top_num] = num; /*save data*/
return 0; /*Exit normally*/
}
int insert_oper (char * oper , int *top_oper , char ch)
{
(*top_oper)++;
oper[*top_oper] = ch; /*save operator*/
return 0; /*Exit normally*/
}
int compare(char *oper , int *top_oper , char ch) /* compare the priority of the operating server*/
{
if((oper[*top_oper] == '-' || oper[*top_oper] == '+') /*Determine whether the current priority is higher than the priority of the operator at the top of the stack*/
&& (ch == '*' || ch == '/'))
{
return 0;
}
else if(*top_oper == -1 || ch == '('
|| (oper[*top_oper] == '(' && ch != ')')) /*Determine whether the operator stack is empty; whether the top operator is '('*/
{
return 0;
}
else if (oper[*top_oper] =='(' && ch == ')')
{
(*top_oper)--;
return 1;
}
else
{
return -1; /*Operate the operator*/
}
}
int deal_date(int *operand ,char *oper ,int *top_num, int *top_oper) /*perform data operation*/
{
int num_1 = operand[*top_num]; /*Take out two data from the data stack*/
int num_2 = operand[*top_num - 1];
int value = 0;
if(oper[*top_oper] == '+')
{
value = num_1 + num_2;
}
else if(oper[*top_oper] == '-')
{
value = num_2 - num_1;
}
else if(oper[*top_oper] == '*')
{
value = num_2 * num_1;
}
else if(oper[*top_oper] == '/')
{
value = num_2 / num_1;
}
(*top_num) --; /*Move the top of the data stack down one bit*/
operand[*top_num] = value; /*Push the obtained value into the data stack*/
(*top_oper) --; /*Move the top of the operator stack down one bit*/
return value;
}
void compress(char *stx) /* The additional function */
{
char work[101];
int i = strlen(stx);
strcpy(work, stx);
for (int j = 0; j < i; j++)
{
stx[j] = 0;
}
i = 0;
for (int j = 0; j < (int)strlen(work); j++)
{
if (work[j] != ' ')
{
stx[i] = work[j];
i++;
}
}
}
int main()
{
int operand[MAX_SIZE] = {0}; /*data stack, initialize*/
int top_num = -1;
char oper[MAX_SIZE] = {0}; /*operator stack, initialize*/
int top_oper = -1;
char *str = (char *) malloc (sizeof(char) * 100); /*get expression (without =)*/
//scanf("%s", str);
scanf("%[^\n]", str); /* Refined the scanf call to receive all characters prior to the newline/return character */
compress(str); /* Added this function to remove spaces */
char* temp;
char dest[MAX_SIZE];
int num = 0;
int i = 0;
while(*str != '\0')
{
temp = dest;
while(*str >= '0' && *str <= '9') /*judging whether it is data*/
{
*temp = *str;
str++;
temp++;
} /*Encounter a symbol to exit*/
if(*str != '(' && *(temp - 1) != '\0') /*Determine whether the symbol is '('*/
{
*temp = '\0';
num = atoi(dest); /*convert string to number*/
insert_operand(operand, &top_num,num); /*Push data into the data stack*/
}
while(1)
{
i = compare(oper,&top_oper,*str); /*judgment operator priority*/
if(i == 0)
{
insert_oper(oper,&top_oper,*str); /*press operator*/
break;
}
else if(i == 1) /*judging whether the expression in brackets ends*/
{
str++;
}
else if(i == -1) /* data processing */
{
deal_date(operand,oper,&top_num,&top_oper);
}
}
str ++; /* point to the next character of the expression */
}
printf("%d\n",operand[0]); /*output result*/
return 0;
}
Thanks for all answers
I would detect if the divisor is zero along these lines:
else if(oper[*top_oper] == '/')
{
value = num_1 ? num_2 / num_1 : 0;
}
or perhaps more verbose:
else if(oper[*top_oper] == '/')
{
if(num_1)
value = num_2 / num_1;
else
value = 0;
}
and example session:
1 / 2
0

Check if the input string consisting of braces is well-formed

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.
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 0.
There are multiple problems in your code:
you call cross(str, str[i], str[j]); instead of cross(str, i, j); when you find matches for parentheses and brackets.
the break statement should be moved inside the if 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 via scanf())
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("%79s", 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;
}
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.
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 here
The algorithm
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 a c guy and i don't know to edit,i just copy pasted !
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;
}

How do I use free to deallocate heap allocations made using malloc?

I've encountered an issue with heap deallocation using free() in my tokenizer. The tokenizer is part of a recursive descent parsing calculator, which works flawlessly otherwise. But upon incorporation of a call to the deallocation function, it behaves erratically. While realistically, the calculator will likely never come close to exhausting its heap, writing a program with a memory leak is just poor practice.
tokenize.h
#define OPERAND 0
#define OPERATOR 1
#define PARENTHESIS 2
#define TERMINAL 3
#define ADD '+'
#define SUBTRACT '-'
#define MULTIPLY '*'
#define DIVIDE '/'
#define EXPONENT '^'
#define L_PARENTHESIS '('
#define R_PARENTHESIS ')'
typedef struct {
int id;
char *value;
} token;
int token_count();
token *tokenize();
void deallocate();
tokenize.c
#include <stdio.h>
#include <stdlib.h>
#include "tokenize.h"
int token_count(char string[]) {
int i = 0;
int count = 0;
while (string[i] != '\0') {
if (string[i] >= '0' && string[i] <= '9') {
while (1) {
i++;
if (string[i] >= '0' && string[i] <= '9') {
continue;
} else {
break;
}
}
count++;
continue;
}
switch (string[i]) {
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case EXPONENT:
case L_PARENTHESIS:
case R_PARENTHESIS:
count++;
i++;
continue;
default:
return 0;
break;
}
}
return count;
}
token *tokenize(char string[]) {
int i = 0;
token *ret;
int count = token_count(string);
if (!count) {
return ret;
}
ret = malloc((count + 1) * sizeof(token));
ret[count].id = TERMINAL;
int ret_ind = 0;
while (string[i] != '\0') {
if (string[i] >= '0' && string[i] <= '9') {
ret[ret_ind].id = OPERAND;
int size = 0;
int j = i;
while (1) {
size++;
j++;
if (string[j] >= '0' && string[j] <= '9') {
continue;
} else {
break;
}
}
ret[ret_ind].value = malloc(size * sizeof(char) + 1);
ret[ret_ind].value[size + 1] = '\0';
for(int k = 0; k < size; k++) {
ret[ret_ind].value[k] = string[i + k];
}
i = j;
ret_ind++;
continue;
}
switch (string[i]) {
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case EXPONENT:
ret[ret_ind].id = OPERATOR;
ret[ret_ind].value = malloc(2 * sizeof(char));
ret[ret_ind].value[0] = string[i];
ret[ret_ind].value[1] = '\0';
ret_ind++;
i++;
continue;
case L_PARENTHESIS:
ret[ret_ind].id = PARENTHESIS;
ret[ret_ind].value = malloc(2 * sizeof(char));
ret[ret_ind].value[0] = L_PARENTHESIS;
ret[ret_ind].value[1] = '\0';
ret_ind++;
i++;
continue;
case R_PARENTHESIS:
ret[ret_ind].id = PARENTHESIS;
ret[ret_ind].value = malloc(2 * sizeof(char));
ret[ret_ind].value[0] = R_PARENTHESIS;
ret[ret_ind].value[1] = '\0';
ret_ind++;
i++;
continue;
default:
break;
}
break;
}
return ret;
}
void deallocate(token *in) {
int i = 0;
while (1) {
free(in[i].value);
i++;
if (in[i].id == TERMINAL) {
break;
}
}
free(in);
return;
}
There are multiple problems in your code:
in case the input line has no tokens or a syntax error, you return ret uninitialized from tokenize. You should return NULL instead.
ret[ret_ind].value[size + 1] = '\0'; stores the null terminator one step too far in the allocated array. It should be ret[ret_ind].value[size] = '\0';
malloc(size * sizeof(char) + 1) is inconsistent: if you insist on using sizeof(char), which is 1 by definition, you should write malloc((size + 1) * sizeof(char)), but it is idiomatic to use malloc(size + 1) in C and you could also replace multiple lines of code with a simple ret[ret_ind].value = strndup(string + i, k);
the cases for L_PARENTHESIS and R_PARENTHESIS could be merged into a single block.
the deallocation loop should stop when you reach the TERMINAL token. As currently coded, you cannot handle an empty list, which you should not produce, but it is better to make utility functions more resilient to later changes.
void deallocate(token *in) {
if (in) {
for (int i = 0; in[i] != TERMINAL; i++)
free(in[i].value);
free(in);
}
}
the prototypes in token.h should include the typed argument lists.
Here is a simplified version:
#include <stdio.h>
#include <stdlib.h>
#include "tokenize.h"
int token_count(const char *string) {
int count = 0;
int i = 0;
while (string[i] != '\0') {
switch (string[i++]) {
case ' ':
continue;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
i += strspn(string + i, "0123456789");
continue;
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case EXPONENT:
case L_PARENTHESIS:
case R_PARENTHESIS:
count++;
continue;
default:
return -1;
}
}
return count;
}
token *tokenize(const char *string) {
int count = token_count(string);
if (count <= 0)
return NULL;
token *ret = malloc((count + 1) * sizeof(token));
int i = 0;
int ret_ind = 0;
while (string[i] != '\0') {
if (string[i] >= '0' && string[i] <= '9') {
int size = strspn(string + i, "0123456789");
ret[ret_ind].id = OPERAND;
ret[ret_ind].value = strndup(string + i, size);
ret_ind++;
i += size;
continue;
}
switch (string[i]) {
case ' ':
i++;
continue;
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case EXPONENT:
ret[ret_ind].id = OPERATOR;
ret[ret_ind].value = malloc(2);
ret[ret_ind].value[0] = string[i];
ret[ret_ind].value[1] = '\0';
ret_ind++;
i++;
continue;
case L_PARENTHESIS:
case R_PARENTHESIS:
ret[ret_ind].id = PARENTHESIS;
ret[ret_ind].value = malloc(2);
ret[ret_ind].value[0] = string[i];
ret[ret_ind].value[1] = '\0';
ret_ind++;
i++;
continue;
default:
break;
}
break;
}
ret[ret_ind].id = TERMINAL;
return ret;
}
void deallocate(token *in) {
if (in) {
for (int i = 0; in[i] != TERMINAL; i++)
free(in[i].value);
free(in);
}
}
Here are additional remarks for the rest of the code:
why clear the screen on entry and exit?
you should test for end of file in the main loop:
if (!fgets(user_in, 1024, stdin))
break;
you should strip the newline efficiently:
#include <string.h>
user_in[strcspn(user_in, "\n")] = '\0';
then you can simplify the test for exit:
if (!strcmp(user_in, "exit"))
break;
no need to clear user_in after solve()
you could simplify testing by solving the command line arguments:
for (int i = 1; i < argc; i++)
solve(argv[i]);
you should ignore white space and accept empty lines
you should use "%.17g instead of %lf. Note that the l is mandatory
for scanf() for a double type, but ignored for printf, because
float arguments are converted to double when passed to vararg
functions like printf.
you should use a context structure and pass a pointer to it
to parse and its helper functions to avoid global variables
as you can see in try_add_sub and try_mul_div, it would simplify
the switch to unify token types and avoid the OPERATOR classification.
the parser is too complicated: you should use recursive descent more
directly: try_add_sub should first call try_mul_div and iterate on
additive operators, calling try_mul_div for each subsequent operand.
Similarly, try_mul_div should first call try_exp and try_exp would
call try_primitive which would handle parentheses and constants.
this approach consumes one token at a time, which can be read from
the expression source on the fly, bypassing the need for tokenizing the whole string.
you should accept the full number syntax for constants, which is easy with strtod().
Here is a simplified version along these directions:
//---- tokenize.h ----
#define TERMINAL 0
#define OPERAND 1
#define ERROR 2
#define ADD '+'
#define SUBTRACT '-'
#define MULTIPLY '*'
#define DIVIDE '/'
#define EXPONENT '^'
#define L_PARENTHESIS '('
#define R_PARENTHESIS ')'
#define SYNTAX_ERROR 1
#define PAREN_ERROR 2
typedef struct context {
char *p;
char *nextp;
int parenthesis_balance;
int error_code;
double value;
} context;
int this_token(context *cp);
void skip_token(context *cp);
//---- tokenize.c ----
#include <stdlib.h>
//#include "tokenize.h"
int this_token(context *cp) {
char *p = cp->p;
for (;;) {
switch (*p) {
case '\0':
cp->nextp = p;
return TERMINAL;
case ' ':
case '\t':
case '\n':
/* ignore white space */
p++;
continue;
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case EXPONENT:
case L_PARENTHESIS:
case R_PARENTHESIS:
/* single character operators */
cp->nextp = p + 1;
return *p;
default:
/* try and parse as a number constant */
cp->value = strtod(p, &cp->nextp);
if (cp->nextp > p)
return OPERAND;
return ERROR;
}
}
}
void skip_token(context *cp) {
cp->p = cp->nextp;
}
//---- parse.h ----
int parse(char expression[], double *result);
void solve(char expression[]);
//---- parse.c ----
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
//#include "tokenize.h"
//#include "parse.h"
/* expression parsers return non zero upon error */
int try_add_sub(context *cp, double *result);
int try_mul_div(context *cp, double *result);
int try_exp(context *cp, double *result);
int try_primary(context *cp, double *result);
int try_add_sub(context *cp, double *result) {
if (try_mul_div(cp, result))
return 1;
for (;;) {
double operand;
switch (this_token(cp)) {
case ADD:
skip_token(cp);
if (try_mul_div(cp, &operand))
return 1;
*result += operand;
continue;
case SUBTRACT:
skip_token(cp);
if (try_mul_div(cp, &operand))
return 1;
*result -= operand;
continue;
}
return 0;
}
}
int try_mul_div(context *cp, double *result) {
if (try_exp(cp, result))
return 1;
for (;;) {
double operand;
switch (this_token(cp)) {
case MULTIPLY:
skip_token(cp);
if (try_exp(cp, &operand))
return 1;
*result *= operand;
continue;
case DIVIDE:
skip_token(cp);
if (try_exp(cp, &operand))
return 1;
*result /= operand;
continue;
}
return 0;
}
}
int try_exp(context *cp, double *result) {
if (try_primary(cp, result))
return 1;
if (this_token(cp) == EXPONENT) {
double operand;
skip_token(cp);
if (try_exp(cp, &operand))
return 1;
*result = pow(*result, operand);
}
return 0;
}
int try_primary(context *cp, double *result) {
switch (this_token(cp)) {
case OPERAND:
skip_token(cp);
*result = cp->value;
return 0;
case L_PARENTHESIS:
skip_token(cp);
cp->parenthesis_balance++;
if (try_add_sub(cp, result))
return 1;
cp->parenthesis_balance--;
if (this_token(cp) != R_PARENTHESIS) {
cp->error_code = PAREN_ERROR;
return 1;
}
skip_token(cp);
return 0;
}
cp->error_code = SYNTAX_ERROR;
return 1;
}
/* parse and evaluate an expression, return error code, update result */
int parse(char expression[], double *result) {
context cc;
cc.nextp = cc.p = expression;
cc.parenthesis_balance = 0;
cc.error_code = 0;
cc.value = 0;
if (try_add_sub(&cc, result))
return cc.error_code;
if (this_token(&cc) != TERMINAL)
return SYNTAX_ERROR;
return 0;
}
void solve(char expression[]) {
double result = 0;
switch (parse(expression, &result)) {
case 0:
printf(" %.17g\n", result);
break;
case SYNTAX_ERROR:
printf("ERROR: Syntax\n");
break;
case PAREN_ERROR:
printf("ERROR: Unbalanced parenthesis\n");
break;
}
}
//---- calculator.c ----
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include "parse.h"
int main(int argc, char **argv) {
for (int i = 1; i < argc; i++)
solve(argv[i]);
if (argc == 1) {
char user_in[1024];
char *p;
printf("Terminal Calculator\n");
printf("Type 'exit' to terminate\n\n");
for (;;) {
printf("=> ");
if (!fgets(user_in, sizeof user_in, stdin)) {
printf("\n");
break;
}
/* strip trailing newline */
user_in[strcspn(user_in, "\n")] = '\0';
/* skip initial white space */
p = user_in + strspn(user_in, " \t");
/* ignore empty and comment lines */
if (*p == '\0' || *p == '#')
continue;
/* trap exit command */
if (!strcmp(p, "exit"))
break;
solve(p);
}
}
return 0;
}

semantical error with parenthesis balancing here

I've written a C code to check for simple parenthesis balancing which prints NO and YES if balanced, not balanced respectively.
The problem is that I'm getting NO for all inputs. Hence I'm thinking that its a semantic error but cannot find it (I have been trying for 2 days :p)
Could someone please help me here? thanks!
#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);
}
updated code:
#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);
}
Here are some major issues in your code:
you do not properly initialize the stack with create(sptr) before use, preferably in main() where it is defined. Your code has undefined behavior. It prints NO by chance, probably because sptr->top has an initial value of 0, which makes the stack non-empty.
you should only pop from the stack when you encounter a closing delimiter ), ] or }.
you should prevent potential buffer overflow by telling scanf() the maximum number of characters to read into c: scanf("%20s", c). Furthermore you should test the return value to avoid undefined behavior at end of file.
Note also that the STACK can be made a local variable to avoid heap allocation and potential allocation failure, which would cause undefined behavior since it is not tested.
Here is a corrected version:
#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;
}
In your pop function you are not decrementing the top thus your isEmpty function always returns false.
Hence you return no always.
char* isBalanced(char* s, STACK* sptr)
{
....
if(isEmpty(sptr)) return y;
else return n;
}
The following is the correct implementation:
char pop(STACK* sptr)
{
if(isEmpty(sptr) == 0)
return sptr->s[sptr->top--];
else
return '$';
}
I assume that the idea is this: an opening paren is always permitted (in the analyzed text), but a closing paren must match the last opened. This is why a stack is required. Also, in the end, if the stack is not empty that means that some parens were not closed.
So, you should use the stack, but only when you encounter parens - either opening or closing.
In the function isBalanced(), the main cycle could be this:
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;
}
The rest of the function is ok. Now, I modified the the pop() function: renamed to popmatch, because it should check if the argument matches the top of the stack. If it does, pop the stack and return OK. So the function would be:
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;
}
Please note that the code mirrors pretty well the "analysis"; when the analysis is short and clear, and the code follows the analysis, the result often is short and clear too.
I would add the flags to see which one does not match
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);
}
Not the stack version but just for the idea. It is rather easy to add push and pop

Resources