So my project is to get a file called "contacts.txt", read in the data and put the data into a node. Then, I put that node into a list. I purge duplicates and print out the resulting list. I'm trying to get the reading in the data and the printing part down first but I'm having problem printing out my list.
A line of contact looks like:
Angelina M. Pierre 306 420 1235
And each part of the line (first name, middle initial, last name, phone number) is supposed to have their own variable. I'm not really sure what I'm doing wrong and I would appreciate the help. My code is:
#include <iostream>
#include <bits/stdc++.h>
#include <stdlib.h>
#include <fstream>
using namespace std;
class Node
{
public:
string firstName;
string middleI;
string lastName;
string phoneNum;
Node *next;
};
// This function prints contents of linked list
// starting from the given node
void printList(Node* n)
{
while (n != NULL) {
cout << n->firstName->middleI->lastName->phoneNum << endl;
n = n->next;
}
}
//This function reads the data from a file called "contacts"
//And streams each line into a new node.
void readData(Node* &p)
{
Node *newNode = new Node; /* Initializing the node*/
ifstream fin("C:\\Users\\owner\\Documents\\contacts.txt");
p = newNode;
while(!EOF){
//fin >> firstName >> middleI >> lastName >> phoneNum;
//while(getline(fin,newNode->contacts)){
newNode->firstName;
newNode->middleI;
newNode->lastName;
newNode->phoneNum;
newNode->next = new Node;
newNode = newNode->next;
}
}
// Driver code
int main()
{
Node *head;
readData(head);
printList(head);
return 0;
}
There are a couple things that I think are majorly detracting from your program's performance. In your printList function, you have the line cout << n->firstName->middleI->lastName->phoneNum << endl;, and I assume here you intend to print all of the information for a user. What is happening here, however, is that the program takes the pointer n, attempts to find the firstName property of the object being pointed to, then takes this property and attempts to find the middleI property of that property, then the lastName property of that property, etc. These fields of course do not exist, so your program will likely crash. Rather, I think using something like cout << n->firstName << " " << n->middleI << " " << n->lastName << " " << n->phoneNum << endl; would work better.
Also, in your readData function, your while loop will continue to update the singular node p instead of creating new nodes, so (assuming that your input file is properly formatted and all that jazz) your head node, which is what is passed into this function when it is called by main(), will only be equal to the last contact in your file and your list will have a length of 1.
Incidentally, I see that you only have a Node class. If you are wanting to work with lists, you probably should create a second class (i.e. LinkedList) that takes one more level of abstraction. Your Node class, then, will handle setting/reporting its data and answering which node follows it, and your LinkedList class will handle keeping track of the list (by remembering where the head is), adding to/deleting from the list, and finding specific nodes in the list.
Some other considerations:
Variables held by a class should almost always be private instead of public. The reason for encapsulating the information in the first place, aside from organizing it, is to make sure that other parts of the program that have no business altering this portion of your code cannot touch it, and you lose this safeguard when you make everything public.
The functions that you are using to create/add nodes, print lists, etc., should all be methods (i.e. functions of a particular class). Say I have some class, Foo, which has a function that acts upon it named bar. To implement it, I could write something like:
class Foo {
private:
//Foo's variables
public:
void bar() {
//bar's implementation
}
}
You will be able to use the method bar() elsewhere because it is labeled public, and bar() will be responsible for handling any necessary manipulation of Foo's information.
It is considered bad practice to use using namespace std; because it can sometimes lead to ambiguous function calls and adding std:: is more explicit. See here for more information.
Using the keyword NULL is very C-style, whereas nullptr is considered more proper (and even safer) in C++. If you are curious, this seems to give a pretty in-depth explanation of this change.
Using while(!fin.eof()) is also considered wrong because !fin.eof() will only return true after you have finished reading the input file. Thus, you will attempt to read past the end of the file and this is plain dangerous. See here for more information.
A little lengthy, but I hope this clarifies things for you a bit! Feel free to comment if you have any questions.
Related
I'm having trouble understanding Linked Lists. I am trying to print to standard output all the items in the list, but only the last record is being printed out. I am not sure what is wrong with my code. I believe the head pointer is only storing one record and is being overwritten each time I put data into a new record, but I don't know where the issue lies exactly and I'm not sure how to rectify it because I can't see where the code is wrong. Please let me know if you can see the issue with my code, and how I can fix it. Thank you.
My int main function is small, but I believe all the necessary information is there. Here is my int main:
int main(void){
sPtr head;
head=NULL;
cout<<putIntoList(head);
system("pause");
return 0;
}
The struct looks like this:
struct drugData{
string name;
string disease;
int effectiveness;
drugData *next;
drugData(){
effectiveness=0;
name="n";
disease="n";
next=NULL;
}
}
And here is the typedef to use for drugData types as function parameters.
typedef drugData* sPtr;
This is the first function, which reads data from a file into the fields of the struct drugData.
void putIntoList(sPtr &head){
(code to open file is located here)
sPtr structPointer=new drugData;
while (!inFile.eof()){
getline(inFile,tempDrugName, ',');
getline(inFile,tempDisease,',');
inFile>>tempEff;
structPointer->name=tempDrugName;
structPointer->disease=tempDisease;
structPointer->effectiveness=tempEff;
cout<<"Drug:"<<structPointer->name;
approvalGetter(structPointer);//This function asks the user for input on each drug.
}
headInsert(structPointer, head);//This function inserts new objects at head.
menuOptions(structPointer, head);//This function presents a menu to either print, search, or quit.
inFile.close();
}//End of putIntoList function.
Here is the code for the function called headInsert:
void headInsert(sPtr &newItem, sPtr& head){
newItem->next=head;
head=newItem;
newItem=NULL;
}
And here is the code for the menuOptions function:
void menuOptions(sPtr& pointer, sPtr& head){
int menuAnswer=0;
cout"Choose a menu option:"<<endl<<"(1) Print"<<endl<<"(2) Search"<<endl<<"(3) Quit"<<endl;
cin>>menuAnswer;
if (menuAnswer==1){
for (pointer=head; pointer!=NULL; pointer=pointer->next){
cout<<pointer->drugName;
}
}//Included here is the menu options 2 and 3.
}
I expect the output to be the names of the drugs contained in the file, of which there are six, but the only output I see is the name of the last drug in the file.
I'm experiencing a problem at the moment where apparently I am Attempting to reference a deleted function. As far as I can see, I'm not actually referencing a function but a smart pointer to a struct.
This is a university project whereupon multiple header files and CPP files are being used to allow us to understand how to use multiple files in the same project and link them together along with understanding and making use of polymorphism. We are using multiple files as the brief states we must. The files and definitions were provided for us.
The following is supposed to conduct a "Breadth-first" search on a terrain map (array of numbers ranging from 0-3) from a starting location to the goal location. It is about path-finding.
This is what I have so far:
#include "SearchBreadthfirst.h" // Declaration of this class
#include <iostream>
#include <list>
using namespace std;
bool CSearchBreadthFirst::FindPath(TerrainMap& terrain, unique_ptr<SNode> start, unique_ptr<SNode> goal, NodeList& path)
{
// Initialise Lists
NodeList closedList; // Closed list of nodes
NodeList openList; // Open list of nodes
unique_ptr<SNode>currentNode(new SNode); // Allows the current node to be stored
unique_ptr<SNode>nextNode(new SNode); // Allows the next nodes to be stored in the open list
// Boolean Variables
bool goalFound = false; // Returns true when the goal is found
// Start Search
openList.push_front(move(start)); // Push the start node onto the open list
// If there is data in the open list and the goal hasn't ben found
while (!openList.empty() || goalFound == false)
{
cout << endl << "Open list front:" << openList.front() << endl;
currentNode->x = openList.front()->x;
currentNode->y = openList.front()->y;
currentNode->score = openList.front()->score;
currentNode->parent = openList.front()->parent;
}
}
It's highlighting this line: currentNode->x = openList.front()->x; as the problem.
The NodeList type is defined in SearchBreadthfirst.h as the following:
using NodeList = deque<unique_ptr<SNode>>;
SNode is also defined in SearchBreadthfirst.h as such:
struct SNode
{
int x; // x coordinate
int y; // y coordinate
int score; // used in more complex algorithms
SNode* parent = 0; // note use of raw pointer here
};
The program breaks upon build. I've been trying to wrap my head around this for days now, so any help is greatly appreciated. If I've missed anything out, let me know and I'll add it in!
James
The error message Attempting to reference a deleted function is due to the fact that std::unique_ptr explicitly deletes its copy constructor because, obviously, there's only supposed to be one copy of the pointer it contains.
When you call
openList.push_front(start);
You're creating a copy of start which is of type unique_ptr<SNode> and it has a deleted copy constructor. In order to use a std::unique_ptr with a container, you need to move the object into the container. You need to do something like this:
openList.push_front(move(start));
That will move start into the deque and move what was in there into start.
I have this tree structure:
public:
node(string& const n);
virtual ~node();
string get_name() const;
void set_name(string& new_name);
int get_nr_children() const;
node get_child(int i) const;
void add_child(node child);
private:
string& name;
vector<node> children;
};
and my main.cpp looks like this:
int main() {
string s = "root";
node r(s);
string s2 = "left child";
node ls(s2);
string s3 = "right child";
node rs(s3);
r.add_child(ls);
r.add_child(rs);
r.~node();
}
(I know that ~node() is run on all objects anyway at the end of the main funciton, but I want to make sure it is executed on the root r first)
All methods are working fine so far, except for the destructor. This is my first destructor, and I came up with the following recursive try, but don't know why it won't work.
node::~node() {
cout << "Enter ~node of " << this->get_name() << endl;
while (this->get_nr_children() != 0) {
this->get_child(0).~node();
this->children.pop_back();
}
delete this;
cout << "Leave ~node of " << this->get_name() << endl;
}
The result is an endless output of "Enter ~node of left child"
"(I know that ~node() is run on all objects anyway at the end of the main funciton, but I want to make sure it is executed on the root r first)"
This quote is enough to say that everything into this question is based only on misconceptions.
It doesn't even make sense to try to correct: a full rewrite is necessary.
Instead read more about destrcuctors, their invocation and what they are for.
Calling it explicitly does not suppress the implicit call of it. And double destruction is undefined behavior.
Also delete this is something very tricky requiring you must be VERY SURE of what it means.
And accessing class methods (this->...) or data after deleting them ... is only looking for troubles.
This is invalid and yields Undefined Behavior if it compiles:
vector<node> children;
At the point of this data member declaration the class node is incomplete; its size isn't yet known.
You can't use an incomplete type as item type for a standard library container (but you can use pointers).
In the destructor implementation, also
delete this;
yields Undefined Behavior, an infinite recursion calling the destructor which (in this delete expression) calls itself, and so on.
The data member declaration
string& name;
also has a strong, unpleasant odour about it, but since you're not showing the constructor implementations I can't state categorically 100% that it's wrong.
However, given the rest of the code, the chance of this being correct is infinitesimal. Just use
string name_;
Ordinarily, a tree uses nodes that are allocated on the free store. That means trafficking in pointers to nodes, and deleting nodes that are no longer in use. The code in the question doesn't follow that model: it allocates the root node on the stack, and stores node objects rather than pointers within each node. With that code, all of the compiler-generated destructors will work just fine. There is no need for any user-defined destructors.
I am working on a Binary Search Tree (BST) program. Per the assignment's requirements, the user loads a text file to construct the tree. If the user would like, they can then create a new tree by loading a new text file. Loading a new text file should destroy the old tree.
To accommodate this require, my method to create a new tree, readNewFile(), first checks if a tree already exists. If it does, it runs the destructor on the tree. However, I then need to create a new tree, that exists outside the scope of readNewFile(), so that it can be accessed globally. Is this possible to do? If so, could you please explain how?
My reduced code:
int main() {
//BST
BST rootTree;
readNewFile(rootTree);
readNewFile(rootTree);
return 0;
}
void readNewFile(BST& tree) {
ifstream inFile;
string fileName;
// if tree was previously filled, destroy it
if (tree.rootPtr() != NULL) {
tree.~BST();
BST tree = new BST();
}
cout << "\nEnter file to load: ";
cin.ignore();
getline(cin, fileName);
cout << "Opening file " << fileName << endl;
inFile.open(fileName.c_str(), ios::in);
// Populates tree... //
}
Destructor (within BST.hpp):
BST::~BST() {
destroyTree(root);
}
void BST::destroyTree(TreeNode*& treePtr) {
if (treePtr != NULL) {
destroyTree(treePtr->leftChildPtr);
destroyTree(treePtr->rightChildPtr);
delete treePtr;
}
}
This returns a segfault, which makes sense, since the tree was destroyed. However, is there a way I can create a new tree, with the same scope as the destroyed BST rootTree?
One way to accomplish the requirement is to have a method called del() in your BST class. All it does is delete all the nodes of the tree but not the root pointer. This is the pointer that points to the root node. After calling del(), you can start creating a new tree. The pseudo code would look something like this:
// if tree was previously filled, destroy it
if (tree.rootPtr() != NULL) {
tree.del()
}
// read the input file
// Start inserting the new nodes
First off: what's wrong with the code.
As you already pointed out, if the tree is destroyed, you can't be using it again. In this case, it's double-bad: by calling the destructor on BST in readNewFile(), you're causing the destructor to be called twice -- once when you explicitly call it, and the second time when the local instance in main() goes out of scope. This is bad.
Now about how to fix it:
The easiest way would just to declare rootTree as a pointer inside main(), and then make readNewFile() take a pointer-to-pointer as an argument. readNewFile() would destroy the existing tree pointed to by the pointer, and then reset the pointer to point at the new tree it creates. Simple.
What would be a better design, though, would be to make readNewFile() a member function of BST. Then main() should construct a new BST and call that instance's readNewFile().
You never invoke the destructor directly unless you know pretty well what you're doing. And then, it's typically because it was created using placement new. Further, "T t = new T;" doesn't make sense, assigning a pointer-to-T to a T. My guess is you are reproducing a Javaism here, but the object models of these two languages are too different.
I'm trying to implement the Ford Fulkerson Algorithm in C++.
However, I'm having trouble with my find_edge function. When I call this function in my_alg, it chooses the correct edge and then the flow is incremented in my_alg. It chooses the right edge and increment its flow (flow), but when I call the find_edge function again, the flow is not incremented as it should be.
This results in an endless loop of my algorithm. Probably I do something wrong with the pointers. You can see my code below.
//An object of this class represents an edge in the graph.
class Edge
{
private:
//Node *prev;
public:
int flow;
Edge(Node *firstNode, Node *secNode, unsigned inCost) {
orgNode = firstNode;
dstNode = secNode;
bridge_capacity = inCost;
}
Edge() {
flow=0;
}
};
//An object of this class holds a vertex of the graph
class Node
{
public:
Node *prev;
vector<Edge>& getAdjNodeList() {
return adjNodeList;
}
};
Edge *find_edge(Graph *g,Node *from,Node *to) {
vector<Edge> b=from->getAdjNodeList();
for(int i=0;i<b.size();i++) {
if(b[i].getDstNode()==to)
return (&b[i]);
}
return NULL;
}
int my_alg(Graph *as,Node *source,Node *sink){
Edge *find_edge();
int max_flow=0;
while(bfs(as,source,sink)) {
Node *b=as->nodeList[num_isl];
int inc=100000000;
while(b->prev!=NULL) {
Edge *bok=find_edge(as,b->prev,b);
inc=min(inc,bok->get_bridge_capacity()-bok->flow);
b=b->prev;
}
b=as->nodeList[num_isl];
while(b->prev!=NULL){
Edge *bok = find_edge(as,b->prev,b);
bok->flow += inc; // This is the place the flow is incremented
bout << bok->flow; // Here, everything is alright.
bok = find_edge(as,b->prev,b);
cout << bok->flow; // However, this is is not the correct result.
}
max_flow+=inc;
}
return max_flow;
}
I had a more thorough look at your code. To help you track your problems down yourself in the future, I will show you a sample process of finding the error.
If you really can not find the problem by looking at the code, you may want to strip down everything that obfuscates your view on the problem. The reduced code could look like this:
class Edge {
public:
int flow;
};
class Node {
private:
vector<Edge> adjNodeList; // list of outgoing edges for this vertex
public:
vector<Edge> & getAdjNodeList() {
return adjNodeList;
}
void addAdjNode(Node* newAdj) {
adjNodeList.push_back(Edge(newAdj));
}
};
int main() {
Node *node1 = new Node();
Node *node2 = new Node();
node1->addAdjNode(node2);
vector<Edge> t = node1->getAdjNodeList();
vector<Edge> f = node1->getAdjNodeList();
t[0].flow = 11;
cout << t[0] << endl;
cout << f[0] << endl;
}
If you would run this code, you would notice that t[0] and f[0] are not the same. As I just copied the crucial elements of your code, the reason should still be the same.
What is happening here? When calling
vector<Edge> t = node1->getAdjNodeList();
the adjacency list is returned by reference, which should leave you with a reference to the original list - you should be able to change it's elements, shouldn't you? However, when assigning this reference to the newly allocated vector t, the implicit copy constructor is called, thus t will contain a copy (!) of your vector while you wanted to save a reference.
To get around this problem, you could just have done the following:
vector<Edge> & t = node1->getAdjNodeList();
which saves the reference and does not create a new object.
I can only assume why the pointers happened to be identical between calls to the function: The object probably was copied to the same place every time. Furthermore, note that you increased the value of an object that did not exist anymore - the copy was deleted with the end of the find_edge-call.
It took some time to give an answer to your question as you did not track the problem down yourself. If you had given the example above, I bet your solution would have been there within a matter of minutes. You are encouraged to raise your problems here at stack overflow - however, most members will not be willing to work through a lot of code to identify the problem themselves. That means, high quality answers usually require questions that directly come to the point. (The last paragraph was intended to help you in the future, however, it could be reduced without altering the question).
Apart from that, I would strongly encourage you not to use your objects the way you do. By passing everything as references and making all changes outside the object, you essentially bypass the encapsulation that makes object orientated programming that powerful. For example, it would be much wiser (and would not have given you your problem) if you just had added another function increaseFlow(Edge* to, int increment) to your Node and had done everything within the object.
Hope I could help.