I wrote a code for pset5 in CS50 course and was wondering if anyone could help me solve the problem of memory leak.
There is a program called speller.c that gets words from a text and use functions in dictionary.c (below) to look at another file (dictionary) and if the word is mispelled or not in the dictionary, it will printf all those words and calculate the running time of the whole program.
My code is actually working fine and I do get the correct output, but when I use valgrind, it says that memory is leaking. Why is this hapenning?
/**
* CS50 - PSET5 - user: linhobru
* Implements a dictionary's functionality.
*/
#include <stdbool.h>
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/time.h>
#include "dictionary.h"
#define ALPHABETSIZE 27
typedef struct node
{
bool is_word;
struct node *children[ALPHABETSIZE];
}
node;
node *root = NULL;
int num_of_words = 0;
/**
* Returns true if word is in dictionary else false.
*/
bool check(const char *word)
{
node* next = root;
int k = ALPHABETSIZE;
for (int i = 0, len = strlen(word); i < len ; i++) // until (char) word[i] == '\0'
{
// verify letter and transform in index from 0 to 26
if (word[i] == '\'')
{
k = ALPHABETSIZE - 1;
}
else if (isalpha(word[i]))
{
k = tolower(word[i]) - 97;
}
if (next->children[k] == NULL)
{
return false;
}
else
{
next = next->children[k];
}
}
return next->is_word;
}
/**
* Loads dictionary into memory. Returns true if successful else false.
*/
bool load(const char *dictionary)
{
FILE *dict = fopen(dictionary, "r");
if (dict == NULL)
{
return false;
}
char word[LENGTH];
root = malloc(sizeof(node));
if (root == NULL)
{
unload();
fclose(dict);
return false;
}
while (fscanf(dict,"%s", word) != EOF)
{
node* now = root;
int k = ALPHABETSIZE;
for (int i = 0; word[i] != '\0'; i++)
{
// verify letter and transform in index from 0 to 26
if (word[i] == 39) // '\''
{
k = ALPHABETSIZE - 1;
}
else if (word[i] >= 97 && word[i] <= 122)
{
k = word[i] - 97;
}
/* else if (word[i] >= 65 && word[i] <= 90)
{
k = word[i] % 65;
}*/
else
{
fclose(dict);
return false;
}
if (now->children[k] == NULL)
{
node* new_node = malloc(sizeof(node));
now->children[k] = new_node;
}
now = now->children[k];
if (word[i + 1] == '\0')
{
now->is_word = true;
}
}
num_of_words++;
}
fclose(dict);
return true;
}
/**
* Returns number of words in dictionary if loaded else 0 if not yet loaded.
*/
unsigned int size(void)
{
return num_of_words;
}
/**
* Receives root at first and then each children to free.
*/
void unloadNode(node* next)
{
// call unloadNode on every node in this node's children
for(int i = 0; i < ALPHABETSIZE; i++)
{
if(next->children[i] != NULL)
{
unloadNode(next->children[i]);
}
}
// once the children nodes are freed, free this node
free(next);
}
/**
* Unloads dictionary from memory. Returns true if successful else false.
*/
bool unload(void)
{
unloadNode(root);
return true;
}
access to files in: https://github.com/linhobru/cs50psets/tree/master/workspace/pset5/speller/
Related
This is my code:
#include <stdio.h>
typedef struct
{
char name[100];
char number[100];
} contact_t;
void empty_array(char *line)
{
for (int j = 0; line[j] != '\0'; j++)
{
line[j] = '\0';
}
}
void read_text(contact_t *contact)
{
int c, cnt = 0;
int i = 0;
char line[100];
do
{
c = getchar();
if ( (c == '\n') || (c == EOF))
{
if( cnt % 2 == 0)
{
for(int j = 0; line[j] != '\0'; j++)
contact -> name[j] = line[j];
}
else
{
for(int j = 0; line[j] != '\0'; j++)
contact -> number[j] = line[j];
}
empty_array(line);
i = 0;
cnt++;
}
line [i] = c;
i++;
} while (c != EOF);
}
int main()
{
contact_t contact = {"x", "0"};
int *j_ptr;
read_text(&contact);
printf("%s", contact.name);
printf("%s", contact.number);
return 0;
}
I am reading a text file(6 lines, name and number, name and number...) from standard input. Then I assign every second line(starting from the first) from that text file to structure contact.name and the rest are I assign to contact.number. So I have several 3 contact structures. I managed to pass to main only the last one, because I don't know how to get acces to int cnt and again make a for cycle.
This is what last prints give me:
John Green
254454556
UPDATE:
I am sorry for not being clear enough as I was writing this question in a hurry. This code is a part of school project and we are not allowed to work with dynamically allocated memory or use fscanf, fopen, qsort, lsearch, bsearch and hsearch etc. Basically, I would just like to use pointers to index of array line and then in main function use a for cycle again to pass all structures from the function read_text to main function of the program.
A few issues ...
main only provides space for one contact entry
read_text needs to use a dynamic array (vs. overwriting the same entry)
read_text needs to return the list pointer and the count to the caller (e.g. main)
The method used in read_text is a bit convoluted.
Style fixes:
contact -> name --> contact->name
list [i] --> list[i]
Here is the refactored code. It is annotated:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char name[100];
char number[100];
} contact_t;
int
read_text(contact_t **listp)
{
char buf[1000];
contact_t *list = NULL;
char *cp = NULL;
int cnt = 0;
// loop on input until EOF
while (fgets(buf,sizeof(buf),stdin) != NULL) {
// increase size of list
++cnt;
list = realloc(list,sizeof(*list) * cnt);
// handle error
if (list == NULL) {
perror("realloc/increase");
exit(1);
}
// point to current record
contact_t *contact = &list[cnt - 1];
// get first name
contact->name[0] = 0;
cp = strtok(buf," \n");
if (cp == NULL)
break;
strcat(contact->name,cp);
// add separater
strcat(contact->name," ");
// get last name
cp = strtok(NULL," \n");
if (cp == NULL)
break;
strcat(contact->name,cp);
// get number
cp = strtok(NULL," \n");
if (cp == NULL)
break;
strcpy(contact->number,cp);
}
// trim to actual amount stored (if error)
if ((cp == NULL) && (cnt > 0)) {
--cnt;
list = realloc(list,sizeof(*list) * cnt);
if (list == NULL) {
perror("realloc/trim");
exit(1);
}
}
// give caller the list pointer
*listp = list;
return cnt;
}
int
main(void)
{
int cnt;
contact_t *list;
cnt = read_text(&list);
// print all entries read in
for (int idx = 0; idx < cnt; ++idx) {
contact_t *contact = &list[idx];
printf("'%s' '%s'\n",contact->name,contact->number);
}
return 0;
}
Here is the test input I used:
John Green 254454556
Fred Smith 8765309
Bob Jones 99728967341
Mary Gallagher 4329268757
Here is the program output:
'John Green' '254454556'
'Fred Smith' '8765309'
'Bob Jones' '99728967341'
'Mary Gallagher' '4329268757'
UPDATE:
I am sorry, I should have clarified that I cannot use dynamically allocated memory. Malloc, calloc or also fsangf is not available –
gregalz
Okay, no malloc et. al. Ironically, I was going to use a predefined fixed size array. But, decided to use a dynamic array instead ;-)
Not sure what fsangf is. So, I'll assume that's fscanf. If you're heavily restricted, maybe you should edit your question and post what you can and can not use.
Here's the code that uses just a fixed array:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char name[100];
char number[100];
} contact_t;
#define NLIST 1000
contact_t list[NLIST];
int
read_text(contact_t *list,int max)
{
char buf[1000];
char *cp = NULL;
int cnt = 0;
// loop on input until EOF
while (fgets(buf,sizeof(buf),stdin) != NULL) {
// don't overflow the max size
if (cnt >= max)
break;
// point to current record and increase list count
contact_t *contact = &list[cnt++];
// get first name
contact->name[0] = 0;
cp = strtok(buf," \n");
if (cp == NULL)
break;
strcat(contact->name,cp);
// add separater
strcat(contact->name," ");
// get last name
cp = strtok(NULL," \n");
if (cp == NULL)
break;
strcat(contact->name,cp);
// get number
cp = strtok(NULL," \n");
if (cp == NULL)
break;
strcpy(contact->number,cp);
}
// trim to actual amount stored (if error)
if ((cp == NULL) && (cnt > 0))
--cnt;
return cnt;
}
int
main(void)
{
int cnt;
cnt = read_text(list,NLIST);
// print all entries read in
for (int idx = 0; idx < cnt; ++idx) {
contact_t *contact = &list[idx];
printf("'%s' '%s'\n",contact->name,contact->number);
}
return 0;
}
I'm making a data structure that stores strings from a file in memory. The struture is:
typedef struct node
{
bool end;
struct node *letters[27];
} node;
Each char from the string goes through a hash function:
int
hash(int letter)
{
int n;
// converts upper case to a number from 1 to 26
if (letter >= 65 && letter <= 90)
n = letter - 64;
// converts letter case to a number from 1 to 26
else if (letter >= 97 && letter <= 122)
n = letter - 96;
// converts apostrophe to 27
else if (letter == '\'')
n = 0;
return n;
}
Thus, the structure is similar to a tree where the position of each pointer in the array corresponds to a letter, as follows:
tree
The function that loads the words into memory is as follows:
bool
load(const char *dict)
{
// open the dictionary file
FILE *infile = fopen(dict, "r");
if (infile == NULL)
{
return false;
}
// pointer for the first tree
node *first = calloc(28, sizeof(node));
if (first == NULL)
return false;
//pointer to the nodes
node *nextptr = NULL;
// word storage variables
int index = 0;
char word[LENGTH+1];
// stores the words of the file in the struct
for (int c = fgetc(infile); c != EOF; c = fgetc(infile))
{
// reads only letters and apostrophes
if ((c >= 65 && c <= 90) || (c >= 97 && c <= 122) || (c == '\''))
{
word[index] = c;
// creates a new tree from the first tree
if (index == 0)
{
// checks if there is a struct for the char
if (first->letters[hash(word[0])] != NULL)
{
nextptr = first->letters[hash(word[0])];
index++;
}
// creates a new struct for the char
else
{
first->letters[hash(word[0])] = calloc(28, sizeof(node));
if (first->letters[hash(word[0])] == NULL)
return false;
nextptr = first->letters[hash(word[0])];
index++;
}
}
// create the following structures
else
{
// checks if there is a struct for the char
if (nextptr->letters[hash(word[index])] != NULL)
{
nextptr = nextptr->letters[hash(word[index])];
index++;
}
// creates a new struct for the char
else
{
nextptr->letters[hash(word[index])] = calloc(28, sizeof(node));
if (nextptr->letters[hash(word[index])] == NULL)
return false;
nextptr = nextptr->letters[hash(word[index])];
index++;
}
}
}
// creates the last struct for a word
else if (c == '\n')
{
// ends the word
word[index] = '\0';
// the boolean end is set to true, defining the end of the word
nextptr->end = true;
nextptr = NULL;
// prepares for a new word
index = 0;
}
}
return true;
}
The function that has an error is an function that check strings and verify if is in the structure:
bool
check(const char *word)
{
node *checkptr = first;
for (int i = 0; i < sizeof(word); i++)
{
if (word[i] == '\0' && checkptr->end == true)
return true;
else if (checkptr->letters[hash(word[i])] != NULL)
checkptr = checkptr->letters[hash(word[i])];
else
return false;
}
return false;
}
When the program is started, segmentation fault occurs on the line else if (checkptr->letters[hash(word[i])] != NULL) and valgrind shows Invalid read of size 8.
I will still create a function to give the necessary free but I guess that the problem is there, mainly because I tried to check if the checkptr pointer was really set to the same structure as the first, but I discover that first is set to NULL, why?
Sorry for my bad english, i'm a beginner programmer and it's my first time on Stack Overflow, but I really don't know how to solve this. If someone can help me in any way, i thank you in advance.
The problem was solved. The error really was in the pointer first. I had accidentally used calloc for a new pointer, instead of the original first, so check was accessing the original first pointer (which had remained NULL).
Im beginner to C/C++.I have defined a reverse strpbrk function which ignores parenthesis (that is named strrpbrk_outside) for a math parser project. Unfortunately program ignores the condition ch != bound.
Can anyone explain what the problem really is?
char* strrpbrk_outside(char* current,char* target,char* bound,char opening,char closing){
for(char* ch = current ; ch != bound ; --ch)
{
for(char* trg = target; *trg != '\0'; ++trg)
{
if ((*ch) == (*trg))
return ch;
}
if ((*ch) == closing)
{
ch = find_opening(ch,bound,opening,closing);
printf("current becomes %s\n",ch);
if (ch == bound)
printf("current == bound\n");
}
}
for(char* trg = target; *trg != '\0'; ++trg)
{
if ((*bound) == (*trg))
return bound;
}
return nullptr;
}
I've tested find_opening function and there wasn't any problem.
char* find_opening(char* current,char* bound,char opening,char closing){
int n = 0;
int i = 0;
if (*current == closing)
--current;//Caution:
for(; current != bound; --current)
{
if (*current == closing)
n = n + 1;
if (*current == opening)
{
i = i + 1;
if (i > n)
return current;
}
}
if (*bound == opening)
{
i = i + 1;
if (i > n)
return current;
}
return nullptr;//Caution: returns current and also checks the bound character
};
here is my test code:
#include <cstdio>
#include <string.h>
#include "AND_OR_NOT.h"
int main()
{
char str[100] = "!<white1>|<white2>&(<sites>|<words>)";
char str1[100] = "(!<white1>|<white2>)&(<sites>|<words>)";
char* pch1 = str1 + 20;
printf("%s\n",pch1-1);--pch1;
char* prev = strrpbrk_outside(pch1,"&|",str1,'(',')');
printf("%s\n",prev);
char END;
printf("press any key to end");
scanf("%c",&END);
}
and here is the strange result::
)&(<sites>|<words>)
current becomes (!<white1>|<white2>)&(<sites>|<words>)
current == bound
current becomes (_,
current becomes²"
current becomes (1'w
current becomes (
current becomes (µ"
current becomes (1'w
current becomes (1'w
current becomes (1'w
press any key to end
cmd image
I've been trying to implement a spell-checker using a large dictionary against some text file which contains around 2000 words. However, my spell-checker returns all words as being misspelled. I honestly have no idea why — could someone help me?
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "dictionary.h"
#define lenght 45
#define hashtable_size 65536
char word[lenght+1];
int count = 0;
/*
*
* Hash function. Thanks to Brenda from cs50 reddit.
*/
int hash_it(const char* needs_hashing)
{
unsigned int hash = 0;
for (int i=0, n=strlen(needs_hashing); i<n; i++)
hash = (hash << 2) ^ needs_hashing[i];
return hash % hashtable_size;
}
typedef struct node
{
char* word;
struct node* next;
}node;
node* previous;
node* hashtable[hashtable_size];
/*
*
* Loads dictionary into memory. Returns true if successful else false.
*/
bool load(const char* dictionary)
{
char word[lenght+1];
FILE* dict = fopen(dictionary,"r");
for(int i = 0; i < 26;i++)
{
hashtable[i] = NULL;
for(int a = fgetc(dict); a != EOF; a = fgetc(dict))
{
count++;
int hashvalue = hash_it(word);
node* new = malloc(sizeof(node));
if(hashtable[hashvalue] == NULL)
{
hashtable[hashvalue] = new;
new -> next = NULL;
}
else
{
new -> next = hashtable[hashvalue];
hashtable[hashvalue] = new;
}
}
}
fclose(dict);
return true;
}
/*
*
* Returns true if word is in dictionary else false.
*/
bool check(const char* word)
{
char tmp[lenght + 1];
int lenghtw = strlen(word);
for (int i = 0; i < lenghtw; i++)
{
tmp[i] = tolower(word[i]);
}
int index = hash_it(tmp);
if (hashtable[index] == NULL)
{
return false;
}
node* cursor = hashtable[index];
while(cursor != NULL)
{
if(strcmp(tmp, cursor -> word) == 0)
{
return true;
}
cursor = cursor -> next;
}
return false;
}
/*
*
* Returns number of words in dictionary if loaded else 0 if not yet loaded.
*/
unsigned int size(void)
{
return count;
}
/*
*
* Unloads dictionary from memory. Returns true if successful else false.
*/
bool unload(void)
{
int index = 0;
while(index < hashtable_size)
{
if(hashtable[index] == NULL)
{
index++;
}
else
{
while(hashtable[index] != NULL)
{
node* cursor = hashtable[index];
hashtable[index] = cursor -> next;
free(cursor);
}
index++;
}
}
return true;
}
int main(int argc, char **argv)
{
if (argc != 2)
return 3;
if (!load("dictionary"))
return 1;
printf("loaded %d words\n", size());
printf("word '%s'%s found\n", argv[1], check(argv[1]) ? "" : " not");
unload();
return 0;
}
There are many problems in your code:
in the load function, you do not load words from the dictionary into the hash table. You read one character at a time with fgetc() and create a node from an uninitialized local buffer word.
the hash_it function only hashes the last 16 characters from the word. Furthermore, hashtable_size is a power of 2, a bad idea. Indeed only the last 8 characters participate in the hash value. This is not a bug, just an inefficient hashing method.
in the check function, you copy the word and convert it to lowercase, but you forget to set the final byte of the tmp array to '\0'.
Here is a corrected version of load that reads one word per dictionary line:
bool load(const char *dictionary) {
char line[256];
FILE *dict = fopen(dictionary, "r");
if (!dict)
return false;
while (fgets(line, sizeof line, dict) != NULL) {
char *p = line + strspn(line, " \t"); // skip blanks
p[strcspn(p, " \t\r\n")] = '\0'; // strip trailing blanks
if (*p == '\0' || *p == '#' || *p == ';')
continue; // ignore blank lines and comments
count++;
int hashvalue = hash_it(p);
node *np = malloc(sizeof(node));
np->word = strdup(p);
np->next = hashtable[hashvalue];
hashtable[hashvalue] = np;
}
fclose(dict);
return true;
}
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.