Trouble with popping stack in c RPN calculator - c

I've been working on this assignment for the past week or so and have been stuck trying to work out what is wrong with my pop() function.
The push() function works fine and is able to store input tokens into the stack; however, as soon as I try to pop them, as per the shunting yard algorithm, the code is unable to compile.
Hopefully someone can help me out here!
I apologize if I've used the wrong terminology / caused confusion in my question it is my first programming subject!
Here is the incomplete code so far including the pop function at the bottom:
#include <stdio.h>
#include <string.h>
#include <conio.h>
#define MAX_LENGTH 400
#define MAX_STACK_SIZE 40
void NoWhitespace(char *string);
int IsNumber(char token);
int IsOperator(char token);
int Push(char *stack, int *top, char token);
int Pop(char *stack, int *top, char token);
int Top(char *stack);
int OrderOfOps(char token);
int main()
{
int top = -1;
char input[MAX_LENGTH];
char token;
char output[MAX_LENGTH];
char stack[MAX_STACK_SIZE];
char popped;
//* Greeting Message *//
printf("Simple Calculator\n");
//* While this statement is true, continue with program *//
while(1)
{
//* Display Prompt *//
printf(">>> ");
fflush(stdout);
//* Get the user input *//
gets(input);
//* Check for help *//
if (input[0] == ('h') && input[1] == '\0')
{
printf("Simple Calculator understands the following arithmetic operations:\n^ exponentiation\n+ addition\n- subtraction\n* multiplication\n/ division\n");
}
//* Check for quit *//
else if (input[0] == ('q') && input[1] == '\0')
{
printf("Goodbye!");
return 0;
}
//* Get rid of all the whitespace in the input before looping through it *//
NoWhitespace(input);
//* Initialize value j before the for loop begins so that after breaking, it will reset to zero *//
int j = 0;
//* Go through every component of the string *//
for (int i = 0; input[i] != '\0' ; i++)
{
//* Let variable 'token' be equal to the component that the for loop is up to in the input string *//
token = input[i];
//* Check if the token is a number *//
if (IsNumber(token))
{
//* Add it to the output array and increment j by one *//
output[j++] = token;
}
//* Check if the token is an operator *//
else if (IsOperator(token))
{
if (stack[0] == '\0')
{
Push(stack, &top, token);
}
while (stack[0] != '\0')
{
if ((OrderOfOps(token) <= OrderOfOps(Top(stack))))
{
popped = Pop(stack, &top, Top(stack));
output[j++] = popped;
}
else
{
Push(stack, &top, token);
}
}
}
else if (token == '(')
{
Push(stack, &top, token);
}
}
printf(output);
printf("\n");
printf(stack);
printf('\n');
}
return 0;
}
int Pop(char *stack, int *top, char token)
{
if( *top == -1 )
{
return(-1);
}
else
{
stack[*top] = token;
*top = *top - 1;
return(1);
}
}

Related

There is a Empty character in my Character Array at the end and idkwhy

#include <stdio.h>
#include <stdlib.h>
char * stack = NULL;
int top = -1;
void push (char letter);
void pop();
int main()
{
char stringy [100];
stack = (char *)malloc(100*sizeof(char));
printf("Enter a String : ");
scanf("%s",stringy);
char letter = '1';
for (int i = 0 ; letter != '\0'; i++){
letter = stringy[i];
push(letter);
printf("Top = %d, Character = %c",top,letter);
}
top--;
for (top; top != -1; top){
pop();
}
return 0;
}
void push(char letter){
top++;
stack[top] = letter;
}
void pop(){
printf("%c",stack[top]);
top--;
}
THERE IS A EMPTY CHARACTER THAT IS BEING PUSHED AND I DONT KNOW WHY PLEASE HELP
There is a fourth element being pushed into my stack as well which has no display on the stdout.
Look at this loop in your code:
for (int i = 0; letter != '\0'; i++){
letter = stringy[i];
push(letter);
When the value of i is equal to index of stringy array where null character exists (i.e. stringy[i] is '\0', it will first assign that '\0' character to letter and then that null character is pushed to stack.
Instead of checking letter != '\0', you should directly check the stringy[i] != '\0' in for loop condition.
Few other problems in your code:
In main() function, you are doing
top--;
for (top; top != -1; top){
pop();
}
It can be implemented in a better way, like this:
while (top != -1) {
pop();
}
A suggestion - Instead of printing character in pop() function, better to return the character, popped from stack, from pop() function.
Since, the size of stringy array is 100 characters, put a restriction in scanf() to not to read more than 99 characters (the remain one character space is for null terminating character):
scanf("%99s",stringy);
Follow good programming practice, always check malloc function return and free the dynamically allocated memory once your program done with it.
Putting these altogether, you can do:
#include <stdio.h>
#include <stdlib.h>
char * stack = NULL;
int top = -1;
void push (char letter);
void pop();
int main (void) {
char stringy [100];
stack = (char *)malloc(100*sizeof(char));
if (stack == NULL) {
printf ("Failed to allocate memory\n");
exit (EXIT_FAILURE);
}
printf("Enter a String : ");
scanf("%99s",stringy);
for (int i = 0; stringy[i] != '\0'; i++) {
push(stringy[i]);
printf("Top = %d, Character = <%c>\n", top, stringy[i]);
}
while (top != -1) {
pop();
}
free (stack);
return 0;
}
void push(char letter) {
top++;
stack[top] = letter;
}
void pop() {
printf("%c",stack[top]);
top--;
}
A stack data structure can be implemented in much better way. Leaving it up to you to learn and modify the implementation.
Your program had few bugs. I fixed those. Now, it is working correctly.
There were two changes:
The condition in the for loop was changed.
top-- was removed from the main() function.
The updated code is below:
#include <stdio.h>
#include <stdlib.h>
char *stack = NULL;
int top = -1;
void push (char letter);
void pop();
int main()
{
char stringy [100];
stack = (char *)malloc(100*sizeof(char));
printf("Enter a String : ");
scanf("%s",stringy);
char letter = '1';
for (int i = 0 ; ((letter = stringy[i]) != '\0'); i++){
push(letter);
printf("Top = %d, Character = %c\n",top,letter);
}
for (top; top != -1; top) {
pop();
}
return 0;
}
void push(char letter)
{
top++;
stack[top] = letter;
}
void pop()
{
printf("%c",stack[top]);
top--;
}

This code don't run on other compiler except vscode

The giver code is for converting infix to postfix using stack. I tried it everywhere no errors or warning were shown except for one time there was a segmentation fault on my school's computer. If anyone can explain the correct way to write the code it'll be very helpful as I'm unable to find.
In code we scan the infix expression and check if it's an operator and then if it is an operator we push it to stack and character or digit go to an array. We then pop the operator from the stack if we find another operator of more precedence than the previous pushed operator and we keep popping till we get less precedence operator in stack and append it to the array that is also our output.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<ctype.h>
struct stack
{
int size;
int top;
char *arr;
};
int stacktop(struct stack *sp)
{
return sp->arr[sp->top];
}
void push(struct stack *ptr, char val)
{
if (ptr->top == ptr->size - 1)
{
printf("Stack is full\n");
}
else
{
ptr->top++;
ptr->arr[ptr->top] = val;
}
}
char pop(struct stack *ptr)
{
int a;
if (ptr->top == -1)
{
printf("\n");
}
else
{
a = ptr->arr[ptr->top];
ptr->top--;
return a;
}
}
int isoperator(char symbol)
{
if (symbol == '^' || symbol == '*' || symbol == '/' || symbol == '+' || symbol == '-')
{
return 1;
}
else
{
return 0;
}
}
int precedence(char symbol)
{
if (symbol == '^')
{
return (3);
}
else if (symbol == '*' || symbol == '/')
{
return (2);
}
else if (symbol == '-' || symbol == '+')
{
return (1);
}
else
{
return (0);
}
}
char *infix_to_postfix(char *infix)
{
struct stack *sp = (struct stack *)malloc(sizeof(struct stack));
sp->size = 50;
sp->top = -1;
sp->arr = (char *)malloc(sp->size * sizeof(char));
char *postfix = (char *)malloc(strlen((infix) + 1) * sizeof(char));
int i = 0, j = 0, x = 0;
while (infix[i] != '\0')
{
if (infix[i] == '(')
{
push(sp, infix[i]);
}
else if( isdigit(infix[i]) || isalpha(infix[i])){
postfix[j]=infix[i];
j++;
}
else if (isoperator(infix[i])==1)
{
x=pop(sp);
while(isoperator(x)==1 && precedence(x)>=precedence(infix[i])){
postfix[j]=x;
j++;
x=pop(sp);
}
push(sp, x);
push(sp, infix[i]);
}
else if (infix[i] == ')')
{
x = pop(sp);
while (x != '(')
{
postfix[j] = x;
j++;
x = pop(sp);
}
}
i++;
}
while (!(sp->top == -1))
{
postfix[j] = pop(sp);
j++;
}
postfix[j] = '\0';
return postfix;
}
int main()
{
char *infix;
printf("Enter your expression\n");
scanf("%s",infix);
printf("Postfix is %s", infix_to_postfix(infix));
return 0;
}
The pointer variable char *infix doesn't point to anything so it's not about VSCode and other compilers. It's complete luck that it's working on VSCode.
You should allocate some memory either statically char infix[100] or dynamically char *infix = (char *)malloc(100).
Also, you have a problem with pop function. You shouöd always return a char from this function not only under certain conditions.

Unknown C String Truncation/Overwrite

I am having an interesting memory problem with a simple string manipulation. The problem itself isn't actually in the reading of the string but right before it when I am trying to call the string.
char *removeInvalid(char *token){
fprintf(stderr," Before: %s \n", token);
char *newToken = malloc(sizeof(100) + 1);
fprintf(stderr," After: %s \n", token);
}
Whenever I run this, the string if truncated right after the char *newToken is malloc'd. So the printout of this results in
Before: Willy Wanka's Chochlate Factory
After: Will Wanka's Chochlate F!
Anyone have any clue what this is? I looked at other examples of malloc, but can't figure out how it is going wrong here.
EDIT: FULL CODE BELOW. Take note I am a college student who just began C, so it isn't perfect by anymeans. But it works up until this error.
Function calls goes as follows. Main->initialReadAVL (This part works perfectly)
Then after commandReadAVL is called which goes commandReadAVL->ReadHelper (Again works fine here.
Then CleanUpString->removeSpaces(works fine)
Then CleanUpString->removeInvalid(THIS IS WHERE IT ERRORS)
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include "node.h"
#include "avl.h"
#include "scanner.h"
#include "bst.h"
/* Options */
int avlSwitch = 0;
int bstSwitch = 0;
int insertSwitch = 0;
int deleteSwitch = 0;
int frequencySwitch = 0;
int displaySwitch = 0;
int statisticSwitch = 0;
int ProcessOptions(int argc, char **argv);
char *cleanUpString(char *token);
char *turnToLowerCase(char *token);
char *removeSpaces(char *token);
char *removeInvalid(char *token);
char *readHelper(FILE *in);
void Fatal(char *fmt, ...);
void preOrder(struct node *root);
void initialReadAVL(avl *mainAVL, FILE *in);
void initialReadBST(bst *mainBST, FILE *in);
void commandReadBST(bst *mainBST, FILE *commandList);
void commandReadAVL(avl *mainAVL, FILE *commandList);
int main(int argc, char **argv) {
struct avl *mainAVL;
struct bst *mainBST;
FILE *text;
FILE *commandList;
if(argc != 4){
Fatal("There must be 4 arguments of form 'trees -b corpus commands' \n");
}
int argIndex = ProcessOptions(argc,argv);
text = fopen(argv[2], "r");
commandList = fopen(argv[3], "r");
//Protect against an empty file.
if (text == NULL){
fprintf(stderr,"file %s could not be opened for reading\n", argv[2]);
exit(1);
}
if (commandList == NULL){
fprintf(stderr,"file %s could not be opened for reading\n", argv[3]);
exit(1);
}
if (avlSwitch){
mainAVL = newAVL();
initialReadAVL(mainAVL, text);
preOrder(mainAVL->root);
fprintf(stderr,"\n");
commandReadAVL(mainAVL, commandList);
preOrder(mainAVL->root);
fprintf(stderr,"\n");
}
else if (bstSwitch){
mainBST = newBST();
initialReadBST(mainBST, text);
preOrder(mainBST->root);
commandReadBST(mainBST, commandList);
preOrder(mainBST->root);
}
return 0;
}
void commandReadAVL(avl *mainAVL, FILE *commandList){
char *command;
char *textSnip;
while(!feof(commandList)){
command = readHelper(commandList);
textSnip = readHelper(commandList);
textSnip = cleanUpString(textSnip);
if(command != NULL){
switch (command[0]) {
case 'i':
fprintf(stderr,"%s \n", textSnip);
insertAVL(mainAVL, textSnip);
break;
case 'd':
deleteAVL(mainAVL, textSnip);
break;
case 'f':
break;
case 's':
break;
case 'r':
break;
default:
Fatal("option %s not understood\n",command);
}
}
}
}
void commandReadBST(bst *mainBST, FILE *commandList){
char *command;
char *textSnip;
while(!feof(commandList)){
command = readHelper(commandList);
textSnip = readHelper(commandList);
textSnip = cleanUpString(textSnip);
if(command != NULL){
switch (command[0]) {
case 'i':
insertBST(mainBST, textSnip);
break;
case 'd':
deleteBST(mainBST, textSnip);
break;
case 'f':
break;
case 's':
break;
case 'r':
break;
default:
Fatal("option %s not understood\n",command);
}
}
}
}
char *readHelper(FILE *in){
char *token;
if (stringPending(in)){
token = readString(in);
}
else {
token = readToken(in);
}
return token;
}
void initialReadBST(bst *mainBST, FILE *in){
char *token;
while(!feof(in)){
token = readHelper(in);
token = cleanUpString(token);
if (token != NULL){
insertBST(mainBST, token);
}
}
}
void initialReadAVL(avl *mainAVL, FILE *in){
char *token;
while(!feof(in)){
token = readHelper(in);
token = cleanUpString(token);
if (token != NULL){
insertAVL(mainAVL, token);
}
}
}
//Helper Function to clean up a string using all the prerequisites.
char *cleanUpString(char *token){
char *output = malloc(sizeof(*token)+ 1);
if (token != NULL){
output = removeSpaces(token);
fprintf(stderr,"before : %s \n", output);
output = removeInvalid(output);
fprintf(stderr,"%s \n", output);
output = turnToLowerCase(output);
return output;
}
return NULL;
}
//Helper function to turn the given string into lower case letters
char *turnToLowerCase(char *token){
char *output = malloc(sizeof(*token) + 1);
for (int x = 0; x < strlen(token); x++){
output[x] = tolower(token[x]);
}
return output;
}
//Helper function to remove redundent spaces in a string.
char *removeSpaces(char *token){
char *output;
int x = 0;
int y = 0;
while (x < strlen(token)){
if (token[x]== ' ' && x < strlen(token)){
while(token[x] == ' '){
x++;
}
output[y] = ' ';
y++;
output[y] = token[x];
y++;
x++;
}
else {
output[y] = token[x];
y++;
x++;
}
}
return output;
}
char *removeInvalid(char *token){
fprintf(stderr," Before: %s \n", token);
char *newToken = malloc(sizeof(* token)+ 1);
fprintf(stderr," After: %s \n", token);
int x = 0;
int y = 0;
while (x < strlen(token)){
if (!isalpha(token[x]) && token[x] != ' '){
x++;
}
else {
newToken[y] = token[x];
y++;
x++;
}
}
return newToken;
}
//Processes a system ending error.
void Fatal(char *fmt, ...) {
va_list ap;
fprintf(stderr,"An error occured: ");
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
exit(-1);
}
//Processes the options needed to be executed from the command line
int ProcessOptions(int argc, char **argv) {
int argIndex;
int argUsed;
int separateArg;
argIndex = 1;
while (argIndex < argc && *argv[argIndex] == '-')
{
/* check if stdin, represented by "-" is an argument */
/* if so, the end of options has been reached */
if (argv[argIndex][1] == '\0') return argIndex;
separateArg = 0;
argUsed = 0;
if (argv[argIndex][2] == '\0')
{
separateArg = 1;
}
switch (argv[argIndex][1])
{
case 'b':
bstSwitch = 1;
break;
case 'a':
avlSwitch = 1;
break;
default:
Fatal("option %s not understood\n",argv[argIndex]);
}
if (separateArg && argUsed)
++argIndex;
++argIndex;
}
return argIndex;
}
void preOrder(struct node *root) {
if(root != NULL)
{
fprintf(stderr,"%s ", root->key);
preOrder(root->lChild);
preOrder(root->rChild);
}
}
ReadString()
char *
readString(FILE *fp)
{
int ch,index;
char *buffer;
int size = 512;
/* advance to the double quote */
skipWhiteSpace(fp);
if (feof(fp)) return 0;
ch = fgetc(fp);
if (ch == EOF) return 0;
/* allocate the buffer */
buffer = allocateMsg(size,"readString");
if (ch != '\"')
{
fprintf(stderr,"SCAN ERROR: attempt to read a string failed\n");
fprintf(stderr,"first character was <%c>\n",ch);
exit(4);
}
/* toss the double quote, skip to the next character */
ch = fgetc(fp);
/* initialize the buffer index */
index = 0;
/* collect characters until the closing double quote */
while (ch != '\"')
{
if (ch == EOF)
{
fprintf(stderr,"SCAN ERROR: attempt to read a string failed\n");
fprintf(stderr,"no closing double quote\n");
exit(6);
}
if (index > size - 2)
{
++size;
buffer = reallocateMsg(buffer,size,"readString");
}
if (ch == '\\')
{
ch = fgetc(fp);
if (ch == EOF)
{
fprintf(stderr,"SCAN ERROR: attempt to read a string failed\n");
fprintf(stderr,"escaped character missing\n");
exit(6);
}
buffer[index] = convertEscapedChar(ch);
}
else
buffer[index] = ch;
++index;
ch = fgetc(fp);
}
buffer[index] = '\0';
return buffer;
}
INPUT: Commands.txt
i "Willy Wonka's Chochlate Factory"
INPUT testFile.txt
a b c d e f g h i j k l m n o p q r s t u v w x y z
Thanks!
char *turnToLowerCase(char *token){
char *output = malloc(sizeof(*token) + 1);
for (int x = 0; x < strlen(token); x++){
output[x] = tolower(token[x]);
}
return output;
}
This is probably your main issue. You allocate enough space for two characters and then proceed to store lots more than that. You probably wanted:
char *output = malloc(strlen(token) + 1);
Since token is a char*, *token is a char. So sizeof(*token) is sizeof(char) -- definitely not what you want.
You almost certainly have a buffer overrun in some part of the code that you're not showing us. If I were to guess, I'd say you allocate too little storage for token to contain the full string you're writing into it in the first place.
Did you by any chance allocate token using the same erroneous code you have in removeInvalid():
malloc(sizeof(100) + 1);
^^^^^^^^^^^ this doesn't allocate 101 characters, it allocates sizeof(int)+1
char *readHelper(FILE *in){
char * token = malloc(sizeof(char *) + 1);
if (stringPending(in)){
token = readString(in);
}
else {
token = readToken(in);
}
return token;
}
It's hard to make sense of this without being able to see readString or readToken, but this can't possibly be right.
First, you allocate one more byte than is needed for a pointer to one or more characters. What use would such a thing be? If you're not storing a pointer to one or more characters, why use sizeof(char *)? If you are storing a pointer to one or more characters, why add one? It's hard to imagine the reasoning that lead to that line of code.
Then, in the if, you immediately lose the value you got back from malloc because you overwrite token by using it to store something else. If you weren't going to use the value you assigned to token, why did you assign it at all?
Bluntly, a lot of this code simply doesn't make any sense. Without comments, it's hard to understand the reasoning so we could point out what's wrong with it.
Either there was reasoning behind that line of code, in which case it's just completely wrong reasoning. Or worse, the line of code was added with no reasoning in the hopes it would work somehow. Neither method will produce working code.
When you're trying to debug code, first remove anything you added experimentally or that you didn't understand. If you do understand malloc(sizeof(char *) + 1), then please explain what you think it does so that your understanding can be corrected.
Why did you think you needed a buffer that was one byte larger than the size of a pointer to one or more characters?
With the help of David Schwartz and the other posters I was able to find the bug in my problem. When I was allocating memory for my token/output, I wasn't allocating enough space.. Using the erroneous code of
malloc(sizeof(100) + 1);
and
malloc(sizeof(*token) + 1);
both of which produced only a couple of bytes to be allocated. This caused a buffer problem causing random letters and numbers/ truncation to happen. The first resulting in the space equivalent to int + 1 and the second in char + 1. (as I was taking the sizeof token which is just the size of what it originally started as, a char)
To fix this I changed the allocation of my token variable to that of
malloc(strlen(token) + 1);
This allocates a space equivalent to the "string" length of token + 1. Allowing the appropriate space for my problem which would end up with space of <= token.

How to get a pointer back from a void function after it iterates through a string pointer

I'm trying to write a code that goes through a given string using a pointer to parse it.
The original code I wrote worked fine but it was... redundant so I tried making it into a function call to make it more concise. Here is what i have:
char inputArray[300];
char buffer[300];
char username[100];
char password[100];
char name[100];
int i=0;
void repeat(char *to)
{
while(*to!='=')
{
to++;
}
}
void array(char *mm,char *tt)
{
i=0;
while(*tt!='+')
{
mm[i]=*tt;
tt++;
i++;
}
}
int main()
{
printf("give me the shit in this fashion: username=?+password=?+real=?\n");
scanf("%s",inputArray);
strcpy(buffer,inputArray);
char *tok=buffer;
repeat(tok);
tok++;
array(username,tok);
repeat(tok);
tok++;
array(password,tok);
tok++;
repeat(tok);
tok++;
array(name,tok);
}
For some reason it won't give me back the pointer array tok where it left off from the previous function call. why is that? it acts as if after calling it the pointer starts back from the beginning.
Functions receive copies of their arguments. Original arguments remain unaffected.
Giving something back has a special syntax in C: the return statement. Thus
char* repeat (char *to) // <- this function gives back a char*
{
while (*to != '=')
{
to++;
}
return to; // <- giving something back
}
Call it like this:
tok = repeat(tok);
Treat array in the same fashion.
Note 1, this function will result in *undefined behaviour if the string doesn't contain '='.
Note 2, it is also possible to pass a pointer to tok as the other answer suggests, but for sake of clarity it is only recommended to use this style when you need to return more than one thing from a function.
just change your repeat to this:
void repeat(char **to) {
while (**to != '=') {
(*to)++;
}
}
and call it like this:
repeat(&tok);
and always check for errors:
if (scanf("%299s", inputArray) != 1){
printf("incorrect input\n");
return 1;
}
and your sample code (and add check for errors in array and repeat to not go out of bounds):
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
char inputArray[300];
char buffer[300];
char username[300];
char password[300];
char name[300];
int i = 0;
void repeat(char **to) {
while (**to != '=') {
(*to)++;
}
}
void array(char *mm, char *tt){
i = 0;
while (*tt != '+') {
mm[i] = *tt;
tt++;
i++;
}
}
int main() {
printf("give me the shit in this fashion: username=?+password=?+real=?\n");
if (scanf("%299s", inputArray) != 1){
printf("incorrect input\n");
return 1;
}
inputArray[299] = 0;
strcpy(buffer, inputArray);
char *tok = buffer;
repeat(&tok);
tok++;
array(username, tok);
repeat(&tok);
tok++;
array(password, tok);
tok++;
repeat(&tok);
tok++;
array(name, tok);
}
and you may use this to not go out of bounds:
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
char* read_str(char *src, char *dst){
char *p, *q;
p = src;
while (*p != 0 && *p != '=') p++;
if (*p == 0) {
*dst = 0;
return NULL; // '=' not found
}
p++;
q = p;
while (*q != 0 && *q != '+') q++;
//if (*q == 0) return NULL;// '+' not found
while (p <= q) *dst++ = *p++;
dst--;
*dst = 0;
q++;
return q;
}
#define MAX_LEN 100
int main() {
char username[MAX_LEN];
char password[MAX_LEN];
char name[MAX_LEN];
char inputArray[MAX_LEN] = "username=Alex+password=123+real=Alex";
char *p = inputArray;
p = read_str(p, username);
if (p == NULL)return 1; // error
p = read_str(p, password);
if (p == NULL)return 1; // error
read_str(p, name);
printf("username: %s \n", username);
printf("password: %s \n", password);
printf(" name: %s \n", name);
}

Balanced Expression

Below is the code to determine balancing of symbol.
If the expression is balanced then it should print appropriate message. E.g:
((A+B))+(C+D)) --> Balanced
((A+B)+(C+D) ---> Unbalanced
((A+B)+(C+D}) --> Unbalanced
Here is the code
#include <stdio.h>
#include <stdlib.h>
struct Stack {
char data;
struct Stack *next;
};
void push(struct Stack **top, char data) {
struct Stack *new_node;
if (*top == NULL) {
new_node = malloc(sizeof(struct Stack));
new_node->data = data;
new_node->next = *top;
*top = new_node;
} else {
new_node = malloc(sizeof(struct Stack));
new_node->data = data;
new_node->next = *top;
*top = new_node;
}
}
char pop(struct Stack **top, int flag) {
if (*top != NULL && flag == 0) {
printf("\n Expression is In-Valid :) \n");
return '\0';
}
if (*top == NULL && flag == 1) {
printf("\n Unbalanced Expression \n");
return '\0';
}
if (*top != NULL && flag == 1) {
struct Stack *temp = *top;
char op;
op = (*top)->data;
*top = (*top)->next;
free(temp);
return op;
}
}
/*
void display(struct Stack *top) {
struct Stack *temp = top;
while (temp) {
printf("\n %c", temp->data);
temp = temp->next;
}
}
*/
int main(void) {
struct Stack *top = NULL;
int i = 0;
char str[] = "((A+B)+[C+D])", op;
printf("\n Running the programe to check if the string is balanced or not ");
for (i = 0; str[i] != '\0'; ++i) {
if (str[i] == '(' || str[i] == '[' || str[i] == '{' || str[i] == '<')
push(&top, str[i]);
else
if (str[i] == ')' || str[i] == ']' || str[i] == '}' || str[i] == '>') {
op = pop(&top, 1);
if ((op == '(' && str[i] == ')') ||
(op == '[' && str[i] == ']') ||
(op == '{' && str[i] == '}') ||
(op == '<' && str[i] == '>')) {
continue;
} else {
printf("\n The expression is un-balanced \n");
break;
}
}
}
pop(&top, 0);
return 0;
}
But it does not give the desired output. I have debugged the code but was not able to find the issue.
How can I have it print the appropriate message ?
You should immediately clean the stack and stop processing as soon as you detect something unbalanced, and print "Balanced" when you reach return 0. And you should print "Unbalanced" from one single place in your code.
And it is bad that one branch of pop does not return a value when it is declared to return one.
So, pop could become:
char pop(struct Stack **top,int flag)
{
if(*top!=NULL && flag==0)
{
return '\0';
}
if(*top==NULL && flag ==1)
{
return '\0';
}
if(*top!=NULL && flag==1)
{
struct Stack *temp=*top;
char op;
op=(*top)->data;
*top=(*top)->next;
free(temp);
return op;
}
// *top == null && flag == 0
return 'O'; // for OK
}
I would add a clean method - not required because program exit cleans the stack, but I do prefer that:
void clean(struct Stack *top) {
struct Stack *next;
while (top != NULL) {
next = top->next;
free(top);
top = next;
}
}
And some changes in main:
int main(void)
{
struct Stack *top=NULL;
int i=0, err=0;
...
else
{
err = 1;
break;
}
}
}
if (err || (pop(&top,0) == '\0')) {
printf("\n The expression is un-balanced \n");
clean(top);
// return 1; optionally if you want to return a different value to environment
}
else {
printf("\n The expression is balanced \n");
}
return 0;
}
Your pop function is wrong.
You have not handled if top is null and flag is 0. It might also be a case.
Secondly, why do you **top in your push\pop signature when you should be passing top in it. I think it should have *top in its signature.
Also, why you use if in push. Its not needed. You are essentially doing same thing.
You can do this simply by simple modification in this code. I take it from Find maximum depth of nested parenthesis in a string this. It's also help for knowing details. I think it's helpful to you
#include <iostream>
using namespace std;
// function takes a string and returns the
// maximum depth nested parenthesis
int maxDepth(string S)
{
int current_max = 0; // current count
int max = 0; // overall maximum count
int n = S.length();
// Traverse the input string
for (int i = 0; i< n; i++)
{
if (S[i] == '(')
{
current_max++;
// update max if required
if (current_max> max)
max = current_max;
}
else if (S[i] == ')')
{
if (current_max>0)
current_max--;
else
return -1;
}
}
// finally check for unbalanced string
if (current_max != 0)
return -1;
return max;
}
// Driver program
int main()
{
string s = "( ((X)) (((Y))) )";
if (maxDepth(s) == -1)
cout << "Unbalance";
else
cout << "Balance";
return 0;
}
Time Complexity : O(n)
Auxiliary Space : O(1)
Thanks for the suggestions. Here is my below working code of the same problem
#include<stdio.h>
#include<stdlib.h>
struct Stack{
char data;
struct Stack *next;
};
void push(struct Stack **top,char data)
{
struct Stack *new_node;
new_node=malloc(sizeof(struct Stack));
new_node->data=data;
new_node->next=*top;
*top=new_node;
}
int compare(char str,char op)
{
if( (op == '(' && str == ')') || (op == '{' && str == '}') || (op == '[' && str == ']') || (op == '<' && str == '>') )
return 1;
else
return 0;
}
int pop(struct Stack **top,char str)
{
char op,ret;
struct Stack *temp=*top;
if(*top==NULL)
return 0;
else if(*top!=NULL)
{
// Pop the element and then call comapre function
op=(*top)->data;
free(temp);
*top=(*top)->next;
return(ret=compare(str,op));
}
}
void display(struct Stack *top)
{
struct Stack *temp=top;
while(temp!=NULL)
{
printf("%c ",temp->data);
temp=temp->next;
}
printf("\n");
}
int isNotEmpty(struct Stack *top)
{
if(top!=NULL)
return 1;
else
return 0;
}
int main(void)
{
struct Stack *top=NULL;
int i=0,y,flag=0;
char str[]="((A+B)+(C+D)>",op;
printf("\n Running the programe to check if the string is balanced or not ");
for(i=0;str[i]!='\0';++i)
{
if( str[i] == '(' || str[i] == '[' || str[i] == '{' || str[i] == '<' )
push(&top,str[i]);
else if( str[i] == ')' || str[i] == ']' || str[i] == '}' || str[i] == '>')
{
y=pop(&top,str[i]);
if(!y)
{
printf("\n Unbalanced Expression ");
flag=1;
}
}
}
if(!flag)
{
if(isNotEmpty(top))
printf(" \nUnbalanced Expression ");
else
printf(" \n Balanced Expression ");
}
printf("\n");
return 0;
}
Check this code it is super easy and easy to understand
package com.codewithsouma.stack;
import java.util.Arrays;
import java.util.List;
import java.util.Stack;
public class Expression {
private final List<Character> leftBrackets = Arrays.asList('(','{','[','<');
private final List<Character> rightBrackets = Arrays.asList(')','}',']','>');
public boolean isBalanced(String input) {
Stack<Character> stack = new Stack<>();
for (char ch : input.toCharArray()) {
if (isLeftBracket(ch))
stack.push(ch);
if (isRightBracket(ch)) {
if (stack.isEmpty()) return false;
char top = stack.pop();
if (!bracketsMatch(top,ch)) return false;
}
}
return stack.isEmpty();
}
private boolean isRightBracket(char ch) {
return rightBrackets.contains(ch);
}
private boolean isLeftBracket(char ch) {
return leftBrackets.contains(ch);
}
public boolean bracketsMatch(char left, char right){
return leftBrackets.indexOf(left) == rightBrackets.indexOf(right);
}
}
At first, we create a hash table and store all brackets, left brackets are key and the value is its corresponding right brackets. Then we take an expression string from the user and create a character array. then we iterate the array and take a character then we check is this character left brackets or not if it is left bracket then we put into the stack (leftBracketContainer) otherwise we check is it the right bracket if right bracket then we pop the left bracket from the stack and find the closing bracket/ opposite bracket from the hash table and matching the current character/bracket if not matched ( for example our stack contain { this bracket so its closing bracket is } we find from the hash map and our current character = ] current character != opposite bracket ) return false otherwise we continue. At last when loop over then stack should empty. (if stack contain one more left bracket that means our expression needs another right bracket) if stack empty that means our expression is balanced otherwise not.
N:B when we check left bracket or not using isItLeftBracket(ch) then we check is our map contains the keys because all keys are left brackets like the ways we cheak right bracket by using isItRightBracket(ch) here we chake our map contains the value because all the value of the map are right bracket
package com.codewithsouma.stack;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
public class BalancedExpressionUsingMap {
private final Map<Character,Character> map;
public BalancedExpressionUsingMap() {
this.map = new HashMap<>();
map.put('(',')');
map.put('[',']');
map.put('<','>');
map.put('{','}');
}
public boolean isBalanced(String expression){
Stack<Character> leftBracketContainer = new Stack<>();
char [] arrayOfCharacter = expression.toCharArray();
for (char ch : arrayOfCharacter) {
if(isItLeftBracket(ch))
leftBracketContainer.push(ch);
else if(isItRightBracket(ch)){
if(leftBracketContainer.isEmpty()) return false;
char leftBracket = leftBracketContainer.pop();
char oppositeBracket = getOppositeBracket(leftBracket);
if (oppositeBracket != ch) return false;
}
}
return leftBracketContainer.isEmpty();
}
private char getOppositeBracket(char leftBracket) {
return map.get(leftBracket);
}
private boolean isItRightBracket(char ch) {
return map.containsValue(ch);
}
private boolean isItLeftBracket(char ch) {
return map.containsKey(ch);
}
}
Instead of allocating a stack for the delimiters, you can use a recursive function that skips balanced subexpressions and returns NULL upon mismatches:
#include <stdio.h>
const char *check(const char *s, char open) {
while (*s) {
switch (*s++) {
case ')': return (open == '(') ? s : NULL;
case ']': return (open == '[') ? s : NULL;
case '}': return (open == '{') ? s : NULL;
case '>': return (open == '<') ? s : NULL;
case '(':
case '[':
case '{':
case '<':
s = check(s, s[-1]);
if (s == NULL)
return NULL;
break;
}
}
if (open) {
/* closing delimiter not found */
return NULL;
}
return s;
}
void test(const char *s) {
printf("%s -> %s\n", s, check(s, 0) ? "Balanced" : "Unbalanced");
}
int main() {
test("((A+B)+(C+D))");
test("((A+B))+(C+D))");
test("((A+B)+(C+D)");
test("((A+B)+(C+D})");
return 0;
}
Output:
((A+B)+(C+D)) -> Balanced
((A+B))+(C+D)) -> Unbalanced
((A+B)+(C+D) -> Unbalanced
((A+B)+(C+D}) -> Unbalanced
Note that contrary to your assertion, ((A+B))+(C+D)) is unbalanced.

Resources