In the code below I attempt to create a linked list of strings. I then use the linked list to store output generated by a function (named myFunction) which calls itself recursively. When testing/debugging the code, I noticed that if I print the contents of the linked list after executing the function (which should add items to the linked list) nothing prints out. However, if I attempt to print the linked list after adding items from inside the function it works fine.
It appears that the entire linked list is deleted after the call to myFunction. On the other hand, I'm using dynamic memory allocation when I add elements to the linked list so I don't see the issue.
Please help!
#include <cstdlib>
#include <iostream>
template <class T>
class node{
public:
node *next;
T data;
node(){next=0;};
void print();
};
template <class T>
void node<T>::print(){
std::cout << data;
}
template <class T>
class List{
public:
node<T> *head;
List(){head=0;};
void add(T data);
void print();
int len();
};
template <class T>
int List<T>::len(){
int i=0;
node<T> *current=head;
while(current!= 0){
i++;
current=current->next;
}
return i;
};
template <class T>
void List<T>::add(T myData){
node<T> *current=head;
if(head==0){
head= new node<T>;
head->data=myData;
}
else{
while(current->next!=0){
current=current->next;
}
current->next = new node<T>;
current->next->data=myData;
}
}
template <class T>
void List<T>::print(void){
node<T> *current=head;
if(head==0){
return;
}
else{
do{
std::cout << current->data << " ";
current=current->next;
}while(current!=0);
}
}
void myFunction(List<std::string> myList, int n, std::string starter, int leftParens, int rightParens){
int remainingLength = leftParens+rightParens;
if(remainingLength==0){
myList.add(starter);
std::cout <<myList.len() << std::endl;
}
if(leftParens >0){
myFunction(myList, n, starter+"(", leftParens-1, rightParens);
}
if(leftParens==0 and rightParens >0){
myFunction(myList, n, starter+")", leftParens, rightParens-1);
}
}
int main(int argc, char** argv) {
List<std::string> myList;
myFunction(myList, 5, "", 5, 5);
std::cout <<myList.len();
}
You are passing myList to myFunction by value. Any changes made to myList in the function are changes to the copy, not the original myList in main.
Change myFunction so that it accepts its argument by reference. Then, any changes made to it in myFunction will also be visible in main.
void myFunction(List<std::string>& myList, int n,
// ^^
std::string starter, int leftParens, int rightParens){
You need to use reference if you want to update the variable in the caller context (in other words, if you want to change the variable in main).
Whenever a class allocates memory, you probably need to follow the "rule of three" (constructor, copy-constructor, copy-assignment operator). If you don't, you'll get into trouble if you ever make a copy of the original class [like your call to myFunction as it currently stands]
Related
Well I have a task to make BST (Binary Search Tree) on a template. And I'm stuck on conversion problem, couse using template :/. I don't know how to get over it. I tried this code without template and it works normally.
#include <iostream>
using namespace std;
template <class T> struct drzewo{
private:
int value;
drzewo *l ,*r;
public:
T NewDrzewo(int key){
struct drzewo *temp=(struct drzewo*)malloc(sizeof(struct drzewo));
temp->value=key;
temp->l=temp->r=NULL;
return temp;
}
void inorder(struct drzewo *root) {
if (root != NULL) {
inorder(root->l);
cout << root->value << " -> ";
inorder(root->r);
}
}
T insert(struct drzewo *drzewo, int value) {
if (drzewo == NULL) return NewDrzewo(value);
if (value < drzewo->value){
drzewo->l=insert(drzewo->l, value);
}
else{
drzewo->r=insert(drzewo->r, value);
}
return drzewo;
}
};
int main(int argc, char** argv) {
struct drzewo <int> *root = NULL;
root->insert(root, 8);
return 0;
} ```
You are using the template machinery incorrectly.
template <class T> struct drzewo{
private:
int value; // THIS MAKES NO SENSE
The idea of the template is to pass thet type of the stored element as a parameter and not to hard code it. Thus you should be using
T value;
instead of
int value;
Since T is the type of your stored element and not the type of your tree,
T NewDrzewo(int key){
is also wrong, you should be using
drzewo* NewDrzewo(T key){
Likewise, T insert(... int value) should be drzewo* insert(... T value).
There are other issues unrelated to this one, for example (in no particular order):
Using malloc. Don't do that, use new instead.
Not using constructors and destructors.
Using elaborate-type-specifiers (struct drzewo) without any reason. Use drzewo instead.
Using the obsolete NULL macro. Use nullptr instead.
using namespace std is dangerous, never do that.
insert and NewDrzewo should be static functions as they do not use this. root->insert(root, 8) should be root = drzewo<int>::insert(root, 0) because root-> is illegal when root is a null pointer.
I'm trying to write my own code for the erase function used in dynamic structures (lists specifically) of the stl library for a school project
What I had in mind was to do a loop until i found the node prior to the one i wanted to delete.
while (loop->next!= NULL){
if (loop->next==pValue){
break;
}
else {
loop->next;
}
}
prev=loop;
delete loop;
Then I want to update its pointer and instead of having it point to the node to be deleted, i want it to point to the node after the one i'm going to delete.
So can i do this?
*(prev->next)=*(pValue->next);
in case i can't, what should i do?
Here's my function erase
template <class T>
void list<T>::erase(pos pValue){
list<T>::pos prev;
list<T>::pos temp=pValue->next;
list<T>::pos loop=list<T>::first();
while (loop->next!= NULL){
if (loop->next==pValue){
break;
}
else {
loop->next;
}
}
prev=loop;
delete loop;
*(prev->next)=*(pValue->next);
delete list<T>::get(pValue);
}
And here's part of my class list
template <class T>
class list {
node<T> *pFirst;
int n;
public:
typedef node<T> *pos;
void erase(pos pValue);
};
And the structure of the node:
template <class T>
class node {
public:
T info;
node<T> *next;
};
I am trying to create a simple stack using templated classes. There seems to be an issue when one class calls the constructor of the other class.
#include <iostream>
#include <vector>
int g_MaxSize = 100;
template <class T>
class Stack;
template <class D>
class Node
{
private:
D data;
public:
Node(D value): data(value)
{
}
template <class T>
friend class Stack;
};
template <class T>
class Stack
{
private:
std::vector<Node<T>> stack;
int top;
public:
Stack(): stack(g_MaxSize), top(0)
{
}
void push(T val)
{
// make sure stack isnt full
stack[top++]= Node<T>(val);
}
Node<T> pop()
{
return stack[top--];
}
Node<T> peek()
{
return stack[top];
}
};
int main() {
Node<int> testNode(1) // *this works*
Stack<int> myStack;
myStack.push(3);
return 0;
}
The error is " No matching constructor for initialization of 'Node' ". As shown in the code above, Node constructor works on its own but it does not work when done through the Stack class.
The argument of vector needs a default constructor. Node is missing one, hence the error.
Your issue here is that stack(g_MaxSize) in Stack(): stack(g_MaxSize), top(0)
is requesting that you construct g_MaxSize default constructed Nodes in the vector. You can't do that though since Node is not default constructable.
You can add a default constructor to Node that will fix that. Another way would be to pass a default Node to the vector constructor like stack(g_MaxSize, Node<T>(1)). Lastly you could create the vector with zero size and then call reserve in the constructor body to allocate the storage for the Nodes without constructing them.
I have the following code snipped, which implements a Binary Search Tree with templates:
#include<iostream>
using namespace std;
template<typename T>
class Node{
public:
T data;
Node<T> *left;
Node<T> *right;
Node<T> *parent;
Node(T input_data=NULL){
data=input_data;
left=NULL;
right=NULL;
parent =NULL;
}
};
template<typename T>
class BinarySearchTree{
private:
long n;
Node<T> *root;
public:
BinarySearchTree(Node<T> *input_root=NULL, long input_size=0){
n=input_size;
root=input_root;
}
void insert(Node<T> *p=root, T data){
Node<T> *par=NULL;
while(p!=NULL){
par=p;
if(data <= p->data)
p=p->left;
else
p=p->right;
}
Node<T> *z=new Node<T>(data);
if(root==NULL){
root=z;
n=1;
return;
}
z->parent=par;
if(data<=par->data)
par->left=z;
else
par->right=z;
n+=1;
}
void inorder(Node<T> *p=root){
if(p){
inorder(p->left);
cout<<p->data<<" ";
inorder(p->right);
}
}
int main(){
BinarySearchTree<int> *t=new BinarySearchTree<int>();
t->insert(5);
t->insert(15);
t->insert(3);
t->insert(14);
t->insert(25);
t->insert(10);
t->inorder();
}
There's a compilation error on line 27, (i.e. Node *root;), and which reads: "Invalid use of non-static data member 'BinarySearchTree::root'". I think it has to do with the default arguments that I've included have in the functions 'insert' and 'inorder', because I don't get the error when I remove the default argument 'root'.
My question is, what is happening and how do I get around it? I would like to preserve the default argument of root if that's possible.
If it matters, I'm using a software called 'Quincy 2005' on Windows 8.1 to compile (for certain reasons).
A default value must be a literal, not a variable name.
Additionally, arguments with default values must come last in the argument list.
Rather use:
void insert(Node<T> *p, T data) { ... }
// overload with only one argument
void insert(T data)
{
insert(root, data)
}
In a line such as
void insert( Node<T>* p = root ,T data ) {...}
there are 2 errors.
Firstly ,you can only use default value for the arguments starting at the last parameter and backwards.
Since you didn't give data a default value ,this is an error (solution reorder parameters ,those without default must come first).
Secondly ,the value root is a member of this and there is no this at the point of declaration.
Solution if you need a default there use nullptr as the default and inside your function test for nullptr and if so use root instead.
I have a one-dimensional template list that contains nodes, each node has a link to next node.
It works rather well on it's own, but not when it contains another linked list.
LinkedList and Node looks something like that:
template <class T>
class LinkedList
{
private:
Node<T>* pPreHead;
public:
LinkedList(void);
~LinkedList(void);
Node<T>* getHead(void);
int size();
void addElementToEnd(T& value);
void deleteNextNode(Node<T>* pNodeBefore);
}
template <class T>
class Node
{
private:
T value;
Node* next;
public:
Node();
Node* getNext();
Node* getValue();
void setNext(Node* nextElem);
void setValue(T elem);
};
Now for the task I need to use LinkedList>, which is filled via a loop.
It looks something like this:
ifstream fl;
fl.open("test1.in", std::ifstream::in);
while (fl.good())
{
string currentLine;
getline(fl, currentLine);
LinkedList<string> newDNA;
//newDNA being filled here so I skipped code
DNAStorage.addElementToEnd(newDNA);
//Place 1
}
//Place 2
Now if I insert some test output code in "Place 1" everything is fine, but when the loop enters new iteration newDNA variable gets freed and so is the pointer inside DNAStorage (which is LinkedList<LinkedList<string>> in question), and when I try to print anything in "Place 2" I get segmentation fault.
Unfortunately I can't use any other data structures since this is the kind of task I need to do.
My question is - how can this be fixed, so that it actually is not freed prematurely?
Edit:
Here's my code for AddElementToEnd(T& value):
template <class T>
void LinkedList<T>::addElementToEnd(T &value)
{
Node<T> *newtail = new Node<T>;
newtail.setNext(NULL);
newtail.setValue(value);
if(pPreHead == NULL)
{
pPreHead = newtail;
return;
}
Node<T> *tail = pPreHead;
while(tail.getNext() != NULL)
{
tail = tail.getNext();
}
tail.setNext(newtail);
}
The problem is that you are storing references to objects that are going out of scope, causing undefined behavior when you try and access them. Your LinkedList<string> newDNA gets created and destroyed with each iteration of the while loop, yet you pass a reference to be stored in DNAStorage list.
One solution would be to store a copy of each object (not reference) in the list when addElementToEnd() gets called.