#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "stack.h"
#define MAX_EQU_LEN 100
static int prec(char operator)
{
switch (operator)
{
case '*':
return 5;
case '/':
return 4;
case '%':
return 3;
case '+':
return 2;
case '-':
return 1;
default:
break;
}
return 0;
}
static int isNumeric(char* num)
{
if(atoi(num) == 0)
{
return 0;
}
return 1;
}
char* infix_to_postfix(char* infix)
{
char* postfix = malloc(MAX_EQU_LEN);
stack* s = create_stack();
s->size = strlen(infix);
node* tempPtr = s->stack;
unsigned int i;
char symbol,next;
for(i = 0; i < s->size ; i++)
{
symbol = *((infix + i));
tempPtr = s->stack;
if(isNumeric(&symbol) != 1)
{
strcat(postfix, &symbol);
}
else if(symbol == '(')
{
push(s, symbol);
}
else if(symbol == ')')
{
while(s->size != 0 && top(s) != '(')
{
next = tempPtr->data;
pop(s);
strcat(postfix, &next);
tempPtr = s->stack;
if(tempPtr->data == '(')
{
pop(s);
}
}
}
else
{
while(s->size != 0 && prec(top(s)) > prec(symbol))
{
next = tempPtr->data;
pop(s);
strcat(postfix, &next);
push(s,next);
}
}
while(s->size != 0)
{
next = tempPtr->data;
pop(s);
strcat(postfix, &next);
}
}
return postfix;
}
int evaluate_postfix(char* postfix) {
//For each token in the string
int i,result;
int right, left;
char ch;
stack* s = create_stack();
node* tempPtr = s->stack;
for(i=0;postfix[i] < strlen(postfix); i++){
//if the token is numeric
ch = postfix[i];
if(isNumeric(&ch)){
//convert it to an integer and push it onto the stack
atoi(&ch);
push(s, ch);
}
else
{
pop(&s[i]);
pop(&s[i+1]);
//apply the operation:
//result = left op right
switch(ch)
{
case '+': push(&s[i],right + left);
break;
case '-': push(&s[i],right - left);
break;
case '*': push(&s[i],right * left);
break;
case '/': push(&s[i],right / left);
break;
}
}
}
tempPtr = s->stack;
//return the result from the stack
return(tempPtr->data);
}
This file is part of a program that uses a stack struct to perform an infix to postfix on an input file. The other functions have been tested and work fine but when I try to add this part and actually perform the operations the program segmentation faults. A debugger says it occurs in the infix_to_postfix function however it doesn't say which line and I can't figure out where. Does anyone know why this would seg fault?
You've done a few things wrong:
if(isNumeric(&symbol) != 1)
The function isNumeric() expects a null terminated string as input, not a pointer to a single character.
strcat(postfix, &symbol);
Here the same thing applies.
strcat(postfix, &next);
I'm guessing this is wrong too. If you want to turn a single character into a string, you can do this:
char temp[2] = {0};
temp[0] = symbol;
strcat(postfix, temp);
static int isNumeric(char* num)
{
if(atoi(num) == 0)
{
return 0;
}
return 1;
}
What if the string is "0"? Consider using strtol instead because it offers a more powerful means of testing the success of the outcome.
An unrelated stylistic note: your first function looks overcomplicated to me. Although it's perfectly possible that the way I'd do it is also overcomplicated.
static int prec(char operator)
{
switch (operator)
{
case '*':
return 5;
case '/':
return 4;
case '%':
return 3;
case '+':
return 2;
case '-':
return 1;
default:
break;
}
return 0;
}
If a function performs a simple mapping from one set to another, It could usually be performed more simply (and faster) as an array lookup. So I'd start with a string of the input characters.
char *operators = "*" "/" "%" "+" "-";
Note that the compiler will concatenate these to a single string value with a null-terminator.
int precedence[] = { 5, 4, 3, 2, 1, 0 };
Then testing whether a char is an operator is:
#include <string.h>
if (strchr(operators, chr))
...;
And getting the precedence becomes:
p = precedence[strchr(operators, chr) - operators];
If there are more values to associate with the operator, I'd consider using an X-Macro to generate a table and a set of associated enum values to use as symbolic indices.
Related
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stack {
int size;
int top;
char *arr;
};
void push(struct stack *st,char x) {
if (st->top >= st->size - 1) {
printf("stack is full");
}
else {
st->top++;
st->arr[st->top] = x;
}
}
char pop(struct stack *st) {
char x;
if (st->top < 0) {
printf("stack is empty");
}
else {
x = st->arr[st->top];
st->top--;
}
return x;
}
int isempty(struct stack st) {
if (st.top < 0) {
return 1;
}
else
return 0;
}
void display(struct stack st) {
int i;
for (i = st.top; i >= 0; i--) {
printf("%c ", st.arr[i]);
}
printf("\n");
}
int balanced(char *expr) {
int i;
struct stack st;
st.size = strlen(expr);
st.top = -1;
st.arr = (char *)malloc(st.size * sizeof(char));
for (i = 0; expr[i] != '\0'; i++) {
if (expr[i] = '(') {
push(&st, expr[i]);
}
else if (expr[i] = ')') {
if (st.top < 0) return false;
else pop(&st);
}
}
if (st.top < 0) return 1;
else return 0;
}
int main() {
char *expr = "((a+b))";
printf("%d", balanced(expr));
return 0;
}
Paranthesis matching using stack implemented in array in c programming .Nothing gets printed when I call the balanced() function.How to correct the above code?
Apart from this method is there any other way to check paranthesis matching and checking if the expression is valid too i.e; (a+)b In this paranthesis is balanced but expression is not valid
In this loop:
for (i = 0; expr[i] != '\0'; i++) {
if (expr[i] = '(') {
push(&st, expr[i]);
}
else if (expr[i] = ')') {
if (st.top < 0) return false;
else pop(&st);
}
}
You have assignments, rather than checks for equality. = vs. ==.
The first condition is always true, so every character is made '(' and pushed onto the stack. Nothing is ever popped from the stack.
You also need to include <stdbool.h> if you wish to use true and false.
Correcting those issues and running the program, the output is 1.
Others have noted the assignment that should have been test for equality.
While it's interesting to use a stack, you could also simply have used a signed integer counter initialised to zero. Increment when encountering an '(' and decrement when encountering a ')'. If the counter goes negative, or a positive final value is found, then the parentheses are not paired correctly.
The world is bigger than only parentheses. Below, another (fixed size!) stack is used to match pairs of enclosing characters. Yes, 'push/pop' of a stack is a convenient way to make sure that 'nesting' meets expectations.
As for checking legitimacy of an expression, one would have to attempt to parse the expression according to some grammar rules. That is a somewhat more complicated.
#include <stdio.h>
#include <stdbool.h>
int main() {
char *str = "{(foo)({gib(bar)gab;}) ((())) []Quick brown fox ";
char stack[ 64 ] = { 0 };
int stkInd = 1;
bool good = true;
for( char *cp = str; *cp; cp++ ) {
switch( *cp ) {
case '(': stack[ stkInd++ ] = ')'; break;
case '{': stack[ stkInd++ ] = '}'; break;
case '[': stack[ stkInd++ ] = ']'; break;
case '<': stack[ stkInd++ ] = '>'; break;
case ')':
case '}':
case ']':
case '>': good = *cp == stack[ --stkInd ]; break;
}
if( stkInd >= sizeof stack ) {
printf( "Stack Full!\n" );
return -1;
}
if( !good ) {
printf( "%s\n", str );
printf( "%*s^---\n", cp - str, " " );
printf( "Unmatched '%c'\n", *cp );
return -1;
}
}
while( stkInd > 1 ) {
char c = stack[ --stkInd ];
switch( c ) {
case ')': c = '('; break;
case '}': c = '{'; break;
case ']': c = '['; break;
case '>': c = '<'; break;
}
printf( "Unpairable %c\n", c );
}
return 0;
}
Looking again at your code, isempty( ) and display( ) may give you trouble as they both deal with a copy of the stack, rather than a pointer to the stack. Since your stack is dimensioned to match the full length of the original string, this may be viewed as wasteful. Passing the stack's address and using a pointer would be more efficient.
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;
}
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
Am building a stack in C. Stack occasionally fails with a EXC_BAD_ACCESS error on the if check in my isEmpty() function, and I'm not sure why.
Typedefs & definitions:
#define NodeSize sizeof(StackNode)
struct stackNode {
int data;
struct stackNode *nextPtr;
};
typedef struct stackNode StackNode;
typedef StackNode *StackNodePtr;
Stack operation functions
void push(StackNodePtr *topPtr, int value) {
// Declare a new node and set it to the top
StackNode *node;
node = malloc(sizeof(NodeSize));
node->data = value;
node->nextPtr = *topPtr;
// Reassign the pointer to the top
*topPtr = node;
printStack(*topPtr);
}
int pop(StackNodePtr *topPtr) {
StackNode *node = *topPtr;
if (isEmpty(node)) {
return 0;
}
// Grab the current top node and reset the one beneath it to the top pointer.
*topPtr = node->nextPtr;
printStack(*topPtr);
return node->data;
}
int isEmpty(StackNodePtr topPtr) {
if (topPtr == NULL || topPtr->nextPtr == NULL) { // BAD_ACCESS
return 1;
}
return 0;
}
void printStack(StackNodePtr topPtr) {
StackNode *iter = topPtr;
// If the stack is immediately empty, just print that.
if (!isEmpty(iter->nextPtr)) {
// Iterate over each element in the stack and print its data
for (;isEmpty(iter); iter = iter->nextPtr) {
printf("%d ", iter->data);
}
printf("NULL");
} else {
printf("NULL");
}
printf("\n");
}
void evaluatePostfixExpression(char *expr) {
// Create the stack and insert an initial parenthesis
StackNode *head;
head = malloc(NodeSize);
for (int i = 0; expr[i] != '\0'; i++) {
char token = expr[i];
// If the current character is a digit
if (token >= '0' && token <= '9') {
push(&head, token - '0');
// If it's an operator
} else if (token == '+' || token == '-' || token == '*' || token == '/' || token == '^' || token == '%') {
int x = pop(&head);
int y = pop(&head);
int result = calculate(y, x, token);
push(&head, result);
}
}
int output = pop(&head);
printf("The value of the expression is: %d\n", output);
}
int calculate(int op1, int op2, char operator) {
switch (operator) {
case '+':
return op1 + op2;
case '-':
return op1 - op2;
case '*':
return op1 * op2;
case '/':
return op1 / op2;
case '%':
return op1 % op2;
}
if (operator == '^') {
int result = 1;
for (int i = 0; i < op2; i++) {
result *= op1;
}
return result;
}
return 0;
}
Even just a hint in the right direction would be appreciated.
Request for context:
int main() {
char postfix[255] = "54*81+4/+";
evaluatePostfixExpression(postfix);
return 0;
}
void evaluatePostfixExpression(char *expr) {
// Create the stack and insert an initial parenthesis
StackNode *head;
head = malloc(NodeSize);
for (int i = 0; expr[i] != '\0'; i++) {
char token = expr[i];
// If the current character is a digit
if (token >= '0' && token <= '9') {
push(&head, token - '0');
// If it's an operator
} else if (token == '+' || token == '-' || token == '*' || token == '/' || token == '^' || token == '%') {
int x = pop(&head);
int y = pop(&head);
int result = calculate(y, x, token);
push(&head, result);
}
}
int output = pop(&head);
printf("The value of the expression is: %d\n", output);
}
int calculate(int op1, int op2, char operator) {
switch (operator) {
case '+':
return op1 + op2;
case '-':
return op1 - op2;
case '*':
return op1 * op2;
case '/':
return op1 / op2;
case '%':
return op1 % op2;
}
if (operator == '^') {
int result = 1;
for (int i = 0; i < op2; i++) {
result *= op1;
}
return result;
}
return 0;
}
It looks like the expression
if (topPtr == NULL || topPtr->nextPtr == NULL)
is giving you an error because topPtr doesn't point to a valid node, nor it's null. So topPtr->nextPtr will give an error, due to the fact that topPtr is not a valid pointer.
According to your code, your head->nextPtr is not initialized to NULL, so this seems to be the cause of the problem.
By the way: Why do you initialize your head variable with an empty node? As far as I can see, you could just use head = NULL and it would work.
Last, but not least: you should free your node variable in the pop() function, in order to avoid a memory leak.
Hope it helps.
I have a program which convert the infix form to postfix form.
example if the input is :(-2+4-(3+3))
then the output is : 2-4+33+-
my expected ouput is : 2 - 4 + 3 3 + -
How should I do to change it , I am thinking somethings like extra 1 more space when I pop() the stack.
Here is the code:
#include <stdio.h>
#include <ctype.h>
#include<string.h>
#define SIZE 50
char s[SIZE];
int top = -1;
void push(char elem) {
s[++top] = elem;
}
char pop() {
return (s[top--]);
}
int pr(char elem) {
switch (elem) {
case '#':
return 0;
case '(':
return 1;
case '+':
case '-':
return 2;
case '*':
case '/':
return 3;
}
}
int main()
{
char infx[50], pofx[50], ch, elem;
int i = 0, k = 0;
printf("\n\nRead the Infix Expression ?");
scanf("%s", infx);
push('#');
while ((ch = infx[i++]) != '\0') {
if (ch=='(')
push(ch);
else if (isalnum(ch))
pofx[k++] = ch;
else if (ch == ')') {
while (s[top] != '(')
pofx[k++] = pop();
elem = pop();
} else {
while (pr(s[top]) >= pr(ch))
pofx[k++] = pop();
push(ch);
}
}
while (s[top] != '#')
pofx[k++] = pop();
pofx[k] = '\0';
printf("\n\nGiven Infix Expn: %s Postfix Expn: %s \n", infx,pofx);
}
Thank you
Well first off, I wasn't able to compile your code due to this line
int top = -1;
void push(char elem) {
s[++top] = elem;
}
It's very dangerous to initialize your arrays using a variable that's negative. When we go to pop() the character symbols in the array, it will return to its initial state at top = -1 which causes the compilation error. My suggestion is to change your code around to something like this, which will lead you to change somethings around with placing characters in your array:
int top = 0;
void push(char elem) {
s[top++] = elem;
}
As for printing your strings with spaces in between each character use something along the lines of:
for (int i = 0, i < stren(infix) + 1; i++)
{
printf ("%c ", infix[i]);
}
// Same goes for the postfix. More of a formatting of the print characters really...