C++ understanding issue- linked lists and stack - c++

I have to make a code, that checks if parentheses are balanced using stack and linked list.
Here is my code, that i made using many tutorials and power point presentations from my class, and also with little bit of help from my friend.
but, can anyone explain what is happening under 'int pop' and 'check' parts, line by line(il put as comment parts i do not understand)? I have problems with understanding this part of c++ (stacks and l.lists that are implemented), and i don't have anyone who can explain it and who have time. I've tried many things, but i really don't understand it.
P.S. code works as it should
Thank you guys!
#include<iostream>
#include <string>
using namespace std;
struct node
{
char data;
node *link;
};
int pop(node *&stack) //node that points to address of a stack?
{
char result;
node *top=new node; //how can i explain this?
top=stack; //why are we equalizing top with stack?
result=top->data;//i dont understand
stack=top->link;//dont understand
delete top;
return result;
}
bool Pairs(char openP,char closedP)
{
if(openP == '(' && closedP == ')') return true;
else if(openP == '{' && closedP == '}') return true;
else if(openP == '[' && closedP == ']') return true;
else return false;
}
bool Check(string exp)
{
int i=0;
node *stack=NULL;
while(exp[i])
{
if(exp[i]=='(' || exp[i]=='[')
{
node *neww=new stack;//dont understand
neww->data=exp[i];//dont understand
neww->link=stack; //-II-
stack=neww; //-II-
}
if(exp[i]==')' || exp[i]==']')
{
if(stack==NULL)
return 0;
else if (Pairs(pop(stack), exp[i])==0) //what does mean this part in parentheses?
return 0;
}
i++;
}
if(stack==NULL)
return 1;
else
return 0;
}
int main()
{
string exp;
cout<<"Enter parentheses:\n";
cin>>exp;
if(Check(exp)!=0)
cout<<"P. are balanced";
else
cout<<"P. are not balanced";
return 0;
}

I would recommend the following approach:
Think about your algorithm ignoring language details. A stack is the right way to go but you don't need to consider how you will implement your stack until you've thought out the algorithm.
Having decided that you need a given data structure ask yourself whether it already exists in C++ (std::stack) before inventing your own.
Use C++ idioms not C idioms (i.e. use iterators begin() and end() not indexing) Apart from anything else this will prevent your exp[i] bug.
Don't have one class doing more than one thing. If you need a stack then create a stack class rather than have your parsing class involved with stack implementations. Firstly it makes it easier to think about the checking algorithm and secondly the stack class can be reused elsewhere.
In outline your solution will use iterators to examine the characters of the string and push and pop opening brackets using a
std::stack<char>. There is no need for new or pointers anywhere.

Related

Declaring any new variable changes pointer address for unknown reason

I am writing an auction program for a class project and one of the features I was trying to implement was a hash table to make searching for auction items by name efficient. I set it up in node format so that you can chain nodes together if their hash value lines up with another item that already exists.
The main problem that I cannot seem to figure out is how some pointer values are changing when I don't think I have done anything to them. I stepped through each line of this program keeping an eye on the Red highlighted areas in the attached screenshots to see when the data changes. In case #1 the data was intact and able to be accessed. However, in case #2 where I simply declare an additional variable (int i = 0;) suddenly the data passed into the function appears to point to a different memory location (0xcccccccc) which from what I understand is another version of null? This is the same no matter what variable type I have tried to declare whether it be an int, const char*, string, etc it all reacts like the second screenshot.
Does anyone know why the program would be doing this? Are there any other troubleshooting tips? Is this a common error and how should I avoid it in the future and for this project?
I can provide a complete code if needed. I appreciate any help you can provide.
Image 1: No additional variable declared, data in tact as expected
Image 2: integer variable declared, data at ->next suddenly changed. This appears to be this way from the start of the function.
Update: I created an MRE as suggested in a comment, the same error can be reproduced using this code.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
class AuctionItemBidsMaxHeap {
string name = "test";
public:
const char * getItemName() {
return name.c_str();
}
};
class AuctionItemHashTable {
private:
struct Node {
AuctionItemBidsMaxHeap* AuctionItem;
Node* next = nullptr;
};
Node* itemArray;
int capacity = 50;
int generateHashKey(string auctionItem) {
return 11;
}
public:
AuctionItemHashTable() {
//Create the array of X amount of different possible storage locations
Node emptyNode;
emptyNode.AuctionItem = nullptr;
emptyNode.next = nullptr;
itemArray = new Node[capacity];
for (int i = 0; i < capacity; i++) {
itemArray[i] = emptyNode;
}
}
~AuctionItemHashTable() {
delete itemArray;
}
void insertItem(AuctionItemBidsMaxHeap* auctionItem) {
//Check to see if this item already exists
int key = generateHashKey(auctionItem->getItemName());
Node newAuctionItem;
newAuctionItem.AuctionItem = auctionItem;
newAuctionItem.next = nullptr;
//Check to see if anything has been inserted there yet
if (itemArray[key].AuctionItem == nullptr) {
itemArray[key] = newAuctionItem;
}
else {
//WE have to make room in the semi-linked list
Node holder;
holder.AuctionItem = itemArray[key].AuctionItem;
holder.next = itemArray[key].next;
newAuctionItem.next = &holder;
itemArray[key] = newAuctionItem;
}
}
AuctionItemBidsMaxHeap* getAuctionItem(const char* itemName) {
int key = generateHashKey(itemName);
//Loop through all items in location
Node* currentNode = &itemArray[key];
if (currentNode == nullptr) {
return nullptr;
}
else {
if (currentNode->AuctionItem->getItemName() == itemName) {
cout << "Match" << endl;
}
while (currentNode->next != nullptr && currentNode->next != (void*)0xcccccccc) {
int i = 0;
if (currentNode->next->AuctionItem->getItemName()[0] == 'M') {
cout << "M Matched" << endl;
}
while (currentNode->next->AuctionItem->getItemName()[0] != 'e') {
//cout << currentNode->next->AuctionItem->getItemName()[i];
}
currentNode = currentNode->next;
}
//There was an item stored at this location, lets see which one it is
//void* p = (void*)0xcccccccc; //Creating a pointer since for some reason my final pointer gets changed to another type of null character upon passing it to a function
//cout << currentNode->AuctionItem->getItemName() << endl;
//while (currentNode->next != nullptr && currentNode->next != p) {
//cout << currentNode->AuctionItem->getItemName() << endl;
//currentNode = currentNode->next;
//}
return currentNode->AuctionItem;
}
}
};
int main()
{
/**Creating MaxHeap of one bid**/
AuctionItemBidsMaxHeap myBidTest;
AuctionItemBidsMaxHeap myBidTest2;
/**Creating Auction Item Hash Table**/
AuctionItemHashTable auctionItems;
auctionItems.insertItem(&myBidTest);
auctionItems.insertItem(&myBidTest2);
const char* myInput = "test";
auctionItems.getAuctionItem(myInput);
}
First a rant: Why is it that classes still teach pointers in C++? There are MUCH better ways to do this than Node*.
Your code contains several errors, but the most important one is here:
//WE have to make room in the semi-linked list
Node holder;
holder.AuctionItem = itemArray[key].AuctionItem;
holder.next = itemArray[key].next;
newAuctionItem.next = &holder; ////<<< ERROR HERE
itemArray[key] = newAuctionItem;
You create a temporary variable on the stack Node holder; This variable will be destroyed as soon as you leave the function.
But you take a pointer to this variable here
newAuctionItem.next = &holder;
IOW: Your list contains pointers to objects that no longer exist.
&holder is the address of the variable holder. As soon as holder goes out of scope, the contents of it will be destroyed. But newAuctionItem.next and as a consequence also itemArray[key].next will still point to the memory, where holder used to be.
This is what is called a dangling pointer.
I stopped reading your example, but it is also pretty dangerous to accept pointers to AuctionItems in your insert method. When you are using pointers here, you MUST MAKE SURE, that the actual objects remain valid for as long as they are in the list.
Or, to put it the other way round: You must remove them from your list before they get destructed. And we humans are not made to "make sure". We make errors, so it is better to write code where you cannot make an error like this (i.e. avoid pointers in the first place).
Another error: You are creating an array with itemArray = new Node[capacity];, but you are deleting it with delete itemArray;. When you are using new to create an array, you must use delete[] itemArray to delete it. See here delete vs delete[] operators in C++
A general note: DO NOT USE POINTERS AT ALL (unless you have to). Pointers are an advanced C++ concept.
You could use shared_ptr<> instead. This will take away the burdon of freeing the memory.
For your itemArray you could use std::vector<> instead of allocating an array with new[]; etc...
There are many good and easy to use classes in the C++ library, which will help you a lot writing safer and cleaner code.
Learning C++ is (at least) as much about learning the std Library as about learning the syntax and statements. std::vector<AuctionItemNodes> IS C++.

Unable to understand what type the function is returning [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I'm trying to sort a stack by using another stack and a temporary variable. In the sort function, when I'm trying yo return the address of the second stack I'm not sure what type it is returning. Because I'm getting two errors:
file0.cpp: In function 'int main()':
file0.cpp:97:23: error: cannot convert 'int*' to 'stack*'
97 | arr.ad = sort(one.a);
and
file0.cpp:46:17: note: initializing argument 1 of 'int sort(stack*)'
46 | int sort(stack* obj){
| ~~~~~~~^~~
So, these are the errors I'm getting. I'm tried many things by changing the sort function to:
stack* sort();
int* sort();
None of them are working well. So could anyone please explain what is wrong with the code and correct it? And what are topics I must learn better to not make such mistakes again?
#include <iostream>
#define MAX 101
using namespace std;
class stack{
public:
int top = -1, a[MAX];
int address;
void push(int x){
a[++top] = x;
}
void pop(){
top = top - 1;
}
bool isEmpty(){
if(top == -1){
return true;
}else{
return false;
}
}
int Top(){
return top;
}
void print(stack* arr){ //a function to print the stack just confirmaion
for(int i = 0; i < top; i++){ //that the stack is sorted
cout << arr->a[i];
}
}
};
int sort(stack* obj){ //function to sort the stack
int n = obj->top;
int temp = obj->a[n]; //a variable to hold the element
//if it is greater than the Top stack during sorting
stack two; //second stack for sorting the elements
if(two.isEmpty()){ //
two.push(temp);
}
while(obj->top != 0){
if((temp > obj->a[obj->top]) & (two.a[two.top] > temp)){
two.push(temp);
}else if(two.a[two.top] > obj->a[obj->top]){
two.push(obj->a[obj->top]);
obj->pop();
}else{
temp = obj->a[obj->top];
obj->pop();
obj->push(two.a[two.top]);
two.pop();
}
}
return two.a; //trying to return
//address of the second stack that I created
}
int main() {
stack one;
one.push(12); //pushing into the stack
one.push(1);
one.push(19);
one.push(14);
one.push(7);
one.push(79);
one.push(3);
stack* a;
a->address = sort(one.a);
one.print(a->address);
return 0;
}
```
Well many things wrong here. A pointer to a stack is stack*, but two.a is not a pointer to a stack it's a pointer to the a array inside that stack, that would be int*.
But the whole approach is wrong. stack two is a local variable inside your sort function. Because of this it is destroyed when you exit the sort function. So if you were to return a pointer to it, or a pointer to the array inside of it, you will be returning a pointer to something that no longer exists and your program will crash.
The simple way to handle this is to return the stack itself, not a pointer. I've also changed sort and print so that they use references instead of a pointers.
It seems (like many beginners) you are far too quick to use pointers to solve problems that are better solved in other ways. Pointers are definitely an advanced feature of C++, but are rarely needed in good quality C++ code.
Like this
stack sort(stack& obj)
{
int n = obj.top;
...
stack two;
...
return two;
}
void print(const stack& arr){
...
}
int main()
{
stack one;
one.push(12);
...
stack a = sort(one);
print(a);
}

C++ Statement can be simplified

Apologies for the lame question. I am using Intellij Clion Student licensed version for my C++ curriculum. As a part of implementing an UnsortedList class, we had to write a method isInTheList to see if an element is present in the array. The class implementation goes as
bool UnsortedList::isInTheList(float item) {
for (int i = 0; i < length; i++) {
if (data[i] == item) {
return true;
}
return false;
}
}
However, the ide shows a coloured mark at data[i] == item with a popup saying
Statement can be simplified less... (Ctrl+F1)
This inspection finds the part of the code that can be simplified, e.g. constant conditions, identical if branches, pointless boolean expressions, etc.
For a previous method to check if the list if empty, I used the following simplified form instead of if-else statement.
bool UnsortedList::isEmpty() {
return (length == 0);
}
However, with iteration involved now, I cannot come up with a simplified statement in the former. Any help is much appreciated. Thank you.
Fix
Your return false should be moved outside off the for loop.
Because you accidentally put it inside the for loop, this iteration never execute for the second time.
So your IDE thinks the for loop is pointless, and suggests you to simplify it to:
return data[0] == item;
This obviously isn't what you want. So really this is just a one-line shift to make it right.
Why not use STL?
inline bool UnsortedList::isInTheList(float item) {
return std::find(data, data+length, item) != data+length;
}
std::find returns an iterator pointing to the element if it's found, or an iterator equal to one-past-last item (i.e. exactly the second argument passed) if nothing is found. You can use a simple equality check to decide if one is found.
You are actually returning after one iteration in your loop. That's the remark of your compiler.
Your code could be simplified by easy write this:
bool UnsortedList::isInTheList(float item) {
if (length != 0) {
return data[0] == item;
}
}
Note, that this is still undefined behavior (UB). You do not have a return in all of your execution paths.
If your list is empty, you never enter the loop, which results in an UB, because there is no return statement, but the function has to return a bool.
I think, your intention was, to write something like this.
bool UnsortedList::isInTheList(float item) {
for (int i = 0; i < length; i++) {
if (data[i] == item) {
return true;
}
}
return false;
}
Move the return false; out of your for loop and you will be fine (still there are better ways to implement this, but that's another topic).

Finding all parents from node to the root in a tree by recursion

I have a class Graph, modelling a Tree. Graph contain a pointer Graph* to the parent of my current instance (my current node).
class Graph
{
private:
Graph* parent;
public:
Graph* getparent();
}
Graph* Graph::getparent()
{
return this->parent;
}
parent is at nullptr if root.
I'm trying to find the distance from a node to the root, starting from the node.
Here is my try :
int Graph::howManyParents(Graph* unparent)
{
int nbParents(0);
if(unparent != nullptr)
{
nbParents++;
nbParents =+ howManyParents(this->parent);
}
return nbParents;
}
It compiles but crashes. Debugger show me lots of call to the method, but end up SegFaulting. Is there something wrong with my algorithm ?
Your recursion never stops unless you pass it the root, as you're always calling this->howManyParents and thus passing it the same parent, which won't become null.
It is unclear whether you want the distance from the parameter or the distance from this.
Finding the distance from a given node (there is no reason for this to be a member):
int howManyParents(Graph* unparent)
{
int nbParents(0);
if(unparent != nullptr)
{
nbParents = howManyParents(unparent->getparent()) + 1;
}
return nbParents;
}
Finding the distance from this:
int Graph::howManyParents()
{
int nbParents(0);
if(parent != nullptr)
{
nbParents = parent->howManyParents() + 1;
}
return nbParents;
}
I think you are causing stack overflow with too deep or infinite recursion.
Check your input for errors to ensure it is really a tree, because recursion will be infinite in case of a loop in the graph.
Also, try to increase stack size of your program.
On linux just run the command:
ulimit -s unlimited
To do it in Microsoft Visual C++ just add this line to the code:
#pragma comment(linker, '/STACK:67108864');
To do it in MinGW G++ add this option to compilation line:
-Wl,--stack,67108864
But, I think non-recursive solution is overall better here.
int Graph::howManyParents(Graph* unparent)
{
int nbParents(0);
while (unparent != nullptr)
{
nbParents++;
unparent = unparent->parent;
}
return nbParents;
}
It is better to use loops instead of recursion where it is possible to improve both performance and code readability.
Only use recursion where it is really needed. To traverse the tree, for example.
You can do it like that:
int Graph::howManyParents()
{
return getparent() ? getparent()->howManyParents() + 1 : 0;
}
Also don't forget to write the constructor which makes your parent = nullptr, it's not by default constructor.

Confused over C++ Stack Usage

I'm new to this website and will try to contribute just as much as I ask. Also, please know I never ask a question without spending much time trying to figure it out myself.
As such, C++ Stacks are driving me f***ing crazy.
My Question: where do I place my variables/values in the Stack function block to actually use it. I understand Stacks are a LIFO data-structure, I've read countless examples of stacking plates on top of each other, etc.
Look at this code:
#include <iostream>
using namespace std;
const int MAX_SIZE = 100;
class StackOverFlowException
{
public:
StackOverFlowException()
{
cout << "Stack overflow" << endl;
}
};
class StackUnderFlowException
{
public:
StackUnderFlowException()
{
cout << "Stack underflow" << endl;
}
};
class ArrayStack
{
private:
int data[MAX_SIZE];
int top;
public:
ArrayStack()
{
top = -1;
}
void Push(int element)
{
if ( top >= MAX_SIZE )
{
throw new StackOverFlowException();
}
data[++top] = element;
}
int Pop()
{
if ( top == -1 )
{
throw new StackUnderFlowException();
}
return data[top--];
}
int Top()
{
return data[top];
}
int Size()
{
return top + 1;
}
bool isEmpty()
{
return ( top == -1 ) ? true : false;
}
};
[etc....]
It's basic cookie-cutter....let's say I'm trying to adapt it to express a system where the last food orders placed in, are kicked out first; variables are 'food', 'orders', and whatever else.
Where in the world am I integrating those variables into that stack code above!?!??!
Please help so confused i'm about to indiscriminately punch something
A stack implementation could use templates so that you could put whatever you want in the stack (within reason).
For example, have a class that encapsulates all the data related to orders (this one is just an example):
class FoodOrder
{
int orderNumber;
time_t orderTime;
// add more variables here
}
Then, your stack could look like this:
template<typename T> class Stack
{
T data[MAX_SIZE];
int top;
void Push(T item);
T Pop(void);
// add methods
}
Then, you could have a Stack of whatever items you want:
Stack<int> stackOfInts;
Stack<std::string> stackOfStrings;
Stack<FoodOrder> stackOfOrders;
Use the existing std::stack and wrap it if you want the exceptions, for example like this (note you could easily templatize it):
class protectedstack
{
private:
std::stack<int> stack;
const int myarbitraryupperlimit = 100;
public:
void pop()
{
if(stack.empty())
{
throw new StackUnderFlowException();
}
stack.pop();
}
void push(const int& value)
{
if(stack.size()>=myarbitraryupperlimit)
{
throw new StackOverFlowException();
}
stack.push(value);
}
// Similar for top/empty/constructors/...
};
The type of data, as well as that of what Top & Pop return, and what Push takes as an argument, is what is contained in the stack; that's what you'd replace w/ the type of whatever you want to make this a stack of.
This is a stack:
Think of it this way: the only way to add a book without moving the others is to place it on top : this is what Push does. So by calling Push(Book1), you'd be placing Book1 on top of the pile.
Similarly, the only way to take away a book without moving the others is to take the one on top : this is what Pop does. So by calling Pop(), you'd be getting (and removing from the stack) whichever book is on top of the stack, which in the image is the green book.
Am I missing something or was this your question?
It's all in the top variable. This variable dictates which object is the current top. When you pop(), then the top variable is reduced- meaning that the top is now one below where it was. When you push(), it's incremented- the top is now one above where it was. This variable is what accounts for the LIFO functionality of the stack.
You can, of course, template the class to make it work with a FoodOrder or whatever.
I don't see why the confusion. The data would go in, duh!, the "data" variable.
So, you either use Templates, to make the data buffer able to hold anything, or you change the type of the data to what you specifically need.
If for example you have a FoodOrder class, you can do it like this (my C++ is rusty, but this is basically the gist of it):
FoodOrder *data[MAX_SIZE];
You would have to change the push/pop parameters to accept a FoodOrder pointer/reference accordingly, and you're set.
P.S. About using std::stack --this might be a better solution, but doesn't answer his specific question.
P.S 2 Poster writes: "I'm new to this website and will try to contribute just as much as I ask.". Really? So why hasn't he even picked an answer yet? Does this smell more like a homework assignment?