So I am currently working on a graph abstract data type for my CS163 class. Everything else for this program works awesome BUT the depth-first traversal of the graph. When testing, I add all the vertices I want, then connect them as I need to. I check and everything is indeed linked as it should be so we are good to go. I jump into this function below, given the name of the friend(vertex) to start from. The line I commented "*current_buddy = myQueue.front();" is the line I found in GDB to be the offending piece of code that causes a seg fault. Also using GDB, I was able to successfully print the proper vertex using "p myQueue.front()"
So perhaps a sample test to give a bit more context. say I have the points a,b,c,d, and e. a is connected to c,d, and e. b is connected to c. I want to start at vertex "a" for this test. Passing in a to the function, it finds the proper index with the find_location function which simply returns said index integer. It will then push that vertex onto the queue and mark that vertex as visited so that upon traversal, I don't return to that point to push it onto the queue again. I create a node "current" that is attached to the first node in the edge list for the "a" vertex. When it goes into the first loop, I use the previously created vertex "current_buddy" to point to the first object in the queue, which is the vertex "a." This is the point that the program hits a seg fault and I cannot for the life of me figure out what is going on with that line of code that would cause this.
Both "vertex" and "node" are structs I have created and the queue I am using is from the standard library #include queue more on the queue bit here if needed Any and all information would be greatly appreciated! Obviously since this is a school assignment, I don't expect anyone to just give me the answer but I am lost at the moment.
bool graph::breadth_first(char * start)
{
if(adjacency_list[0].buddy_name == NULL)
return false;
int location = find_location(start);
queue<vertex> myQueue;
myQueue.push(adjacency_list[location]);
adjacency_list[location].visited = true;
node * current = adjacency_list[location].head;
vertex * current_buddy = NULL;
while(myQueue.empty() == false)
{
*current_buddy = myQueue.front();//THIS LINE SEG FAULTS
cout << "THIS IS A FRIEND IN THE BREADTH-FIRST TRAVERSAL" << current_buddy->buddy_name << endl;
current = current_buddy->head;
myQueue.pop();
while(current != NULL)
{
if(current->connected_buddy->visited == false)
{
current_buddy = current->connected_buddy;
location = find_location(current_buddy->buddy_name);
myQueue.push(adjacency_list[location]);
adjacency_list[location].visited = true;
current = current->next;
}
}
}
for(int i = 0; adjacency_list[i].buddy_name != NULL; ++i)
{
adjacency_list[i].visited = false;
}
return true;
}
I don't know if this will work as you expect, but a quick fix might be to use the address-of operand and actually assign the pointer instead of dereferencing it:
current_buddy = &myQueue.front();
(EDIT: For the first part of this question, the solution/answer provided by Joachim may perform better. I just like avoid pointer when possible.)
You could try:
vertex * current_buddy = NULL;
while(myQueue.empty() == false)
{
vertex front_buddy = myQueue.front();
cout << "THIS IS A FRIEND IN THE BREADTH-FIRST TRAVERSAL" << front_buddy.buddy_name << endl;
current = front_buddy.head;
BTW - I think you need to check for null here:
while(current != NULL)
{
if (current->connected_buddy == NULL)
{
// add error handling
}
else
{
// normal code
}
}
So that you don't get another crash
This part
while(current != NULL)
{
if(current->connected_buddy->visited == false)
{
// your code
current = current->next;
}
}
looks like an endless loop in case current->connected_buddy->visited is true.
Maybe you want
while(current != NULL)
{
if(current->connected_buddy->visited == false)
{
// your code
}
// Moved out of the if-statement
current = current->next;
}
It's segfault because you are attempting to deference a NULL pointer.
vertex * current_buddy = NULL;
while(myQueue.empty() == false)
{
// V de-referencing a NULL pointer
*current_buddy = myQueue.front();//THIS LINE SEG FAULTS
You should change it to
// vertex * current_buddy = NULL; // < Remove this line
while(myQueue.empty() == false)
{
vertex *current_buddy = &myQueue.front();
Related
I wrote a program to merge two sorted linked list into one and this function was the one I used to do it but it's not working. The code of the function is as follows is as follows:
void combine(Node **temp, Node *temp_1, Node *temp_2){
while(temp_1 != NULL || temp_2 != NULL){
if(temp_1->data > temp_2->data){
push(temp, temp_2->data);
temp_2 = temp_2->next;
}
else{
push(temp, temp_1->data);
temp_1 = temp_1->next;
}
}
while(temp_1 != NULL){
push(temp, temp_1->data);
temp_1 = temp_1->next;
}
while(temp_2 != NULL){
push(temp, temp_2->data);
temp_2 = temp_2->next;
}
}
Now, this code doesn't add anything to the final linked list. If I write something like
push(temp, temp_1->data);
it will add elements just fine so the problem isn't definitely with the push function. Can someone tell me what is the problem with the above code?
The full code is in the following URL:
https://ide.geeksforgeeks.org/FZ8IS4PADE
The issue is the while condition:
while(temp_1 != NULL || temp_2 != NULL){
This will allow the execution of the body of the loop when just one of those two pointers is null, and this will result in undefined behaviour on the first statement in that body:
if(temp_1->data > temp_2->data){
The || should be an &&. This will fix your issue.
Other remarks on your code
Don't use NULL for comparing your pointer variables against, but nullptr
The use of push makes your code inefficient: at every push, your code is starting an iteration through the whole list to find the end of it. Since you actually know what is the last node (since it was created in the previous iteration of the loop) this is a waste of time. Instead, keep a reference to the tail of the list that is being created. As there is no tail at the start of the combine process, it might be useful to create a "sentinel" node that comes before the real list that will be returned.
Use better variable names. temp is not temporary at all. It is the result that the caller wants to get: this name is misleading.
Avoid code repetition. The last two loops are the same except for the list that is copied from, and this code is again similar to the parts in the main loop. So create a function that does this job of copying a node from a source list to the end of another list, and that advances both pointers.
Here is what that would look like:
void copyNode(Node **source, Node **targetTail) {
*targetTail = (*targetTail)->next = new Node((*source)->data);
*source = (*source)->next;
}
void combine(Node **result, Node *head_1, Node *head_2){
Node *sentinel = new Node(0); // Dummy
Node *current = sentinel;
while(head_1 != nullptr && head_2 != nullptr){
if(head_1->data > head_2->data){
copyNode(&head_2, ¤t);
}
else{
copyNode(&head_1, ¤t);
}
}
if (head_1 == nullptr) {
head_1 = head_2;
}
while (head_1 != NULL) {
copyNode(&head_1, ¤t);
}
*result = sentinel->next;
delete sentinel;
}
I am working on a project where I create a double bounded pointer list, delete several elements, and still be able to read off the list. I have a double bounded pointer list, but am having trouble deleting elements and keeping the list double bounded. This then causes issues when trying to print the list.
Below is the IF statement I've placed in a while loop to help delete unwanted elements. I keep getting a segmentation fault (core dumped).
if ((black2 != black)||(white2 != white)) {
dump = help;
help = help ->next;
dump -> before = temp;
temp -> next = help;
help ->before = temp;
delete dump;
}//if
else { temp = help;
help = help->next;
help ->before = temp; }//else
To maintain properly the doubly linked list you should do something like :
void remove(X *elt) {
X* before = elt->before;
X* after = elt->next;
if (before != NULL) { // assuming first element points to NULL
before->next = after;
}
else {
first = after; // assuming first is a pointer to first element of list
}
if (after != NULL) { // assuming last element points to NULL
after->before = before;
}
else {
last = before; // assuming last is a pointer to last element
}
delete elt;
}
That way, you ensure that elements around current correctly point to each other dealing with special cases of removing first or last element.
But you already have a std::list template in Standard Template Library
One logical issue in your code is the line dump->before = temp.
What this does is that it sets the previous node pointer of dump to temp, as opposed to defining temp as the previous node.
The correct line should read temp = dump->before
PS: Your code is correct assuming that the node you are deleting isn't the first or last node (and you haven't padded with dummy nodes). You should introduce checks for these cases if required.
I'm trying to make/create a BST, but it doesn't seem to work properly. I've literally been sitting here for hours trying to figure out what's going on. It's gotten to the point where I've drawn a million diagrams to figure this out, yet my code fails me. I need to pass in a root node into a function. Then I need to traverse through the tree until I find that the parent string parameter of the function coincides with the tree parent node's string. If I do find it, I must insert the string into the parent, and create two new children from that parent. If I can't find the parent string, then I return false.
bool insertNode(BSTNode *n, char* parentQ, char* leftQ, char* rightQ)
{
if(n->Q == parentQ)
{
n->left = new BSTNode(leftQ);
n->right = new BSTNode(rightQ);
return true;
}
else if(n->Q != parent)
{
insertNode(n->left,parentQ,leftQ,rightQ);
insertNode(n->right,parentQ,leftQ,rightQ);
}
else
return false;
}
Also I need to make another method that takes the tree that I have established, and corrects the strings. So the method modifies the parent string, if found, and looks at its children, if found, and replaces those strings with those found in the method parameters. It's sort of like adding a subtree without screwing the entire tree up. Thanks in advance!
bool changeNode(BSTNode *n,char* parentQ, char* leftQ, char* rightQ)
{
if(n->Q == leftQ)
{
n->Q = parentQ;
n->left = new BSTNode(leftQ);
n->right = new BSTNode(rightQ);
return true;
}
else if(n->Q == rightQ)
{
n->Q = parentQ;
n->left = new BSTNode(leftQ);
n->right = new BSTNode(rightQ);
return true;
}
else if(n->Q != leftQ)
{
changeNode(n->left,parentQ,leftQ, rightQ);
}
else if(n->Q != rightQ)
{
changeNode(n->right,parentQ,leftQ,rightQ);
}
return false;
}
You didn't even mention what the error was, example input / expected output, but shouldn't you be checking whether the current node actually has a left and right child, before calling the function with those children?
else if(n->Q != parentQ) // <--- you have a typo in this line, "parent"
{ // (and you don't even need the 'if')
insertNode(n->left,parentQ,leftQ,rightQ);
insertNode(n->right,parentQ,leftQ,rightQ);
// in this case you return nothing! corrupted return value
}
^ this seems very error-prone, especially null-pointer. You should turn it into something like:
else
{
if(n->left != NULL) // take a look at nullptr if you have C++11
if(insertNode(n->left,parentQ,leftQ,rightQ)) return true;
if(n->right != NULL)
if(insertNode(n->right,parentQ,leftQ,rightQ)) return true;
return false;
}
Otherwise your true return never gets propagated back beyond the first return, so then you're always returning false unless in the only case where the root of the tree is actually the node you were searching for.
Also, do not compare two char arrays using ==, unless n->Q is actually an std::string. You should use if(strcmp(n->Q, parentQ) == 0) otherwise.
Your second piece of code, however, is just a mess. You need to take a better look at what exactly will be happening on your else if's and see if it is actually doing what you want (hint: it isn't), as you currently only execute at most 1 of the code blocks, even if more than one condition is true.
I wrote a couple functions for a school project, and I have them working but I don't understand why. they should be identical but they only work if one checks current->link and the other checks current itself. Shouldn't both loops be current != NULL?
The two functions are called in main like so:
customerHead = fillCart(limit, lowLevelInv); //fills linked list
totCart(customerHead, lowLevelInv);
printCart(customerHead, lowLevelInv);
This one only works if the while loop checks current != NULL
int totCart(OrderPtr head, inventory lowLevelInv[])
{
OrderPtr current;
current = head;
int tot = 0;
while(current != NULL)
{
tot += lowLevelInv[current->itemID].cost*current->qtyReceived;
current = current->link;
}
cout<<"Cart total is: "<<tot<<endl;
return tot;
}
This one only works if the while loop checks current->link !=NULL
void printCart(OrderPtr head, inventory lowLevelInv[])
{
OrderPtr current;
current = head;
cout<<"you have ordered: \n";
while(current->link != NULL);
{
cout<<current->orderID<<": "<<current->qtyReceived<<" " <<lowLevelInv[current->itemID].name<<" for "<<lowLevelInv[current->itemID].cost*current->qtyReceived<<endl;
current = current->link;
}
}
Looks like the problem is here:
while(current->link != NULL);
{
cout<<current->orderID<<": "<<current->qtyReceived<<" " <<lowLevelInv[current->itemID].name<<" for "<<lowLevelInv[current->itemID].cost*current->qtyReceived<<endl;
current = current->link;
}
If you look very carefully, you have a spurious semicolon after the controlling statement in the "while" statement. That means that your program will hang if current->link is ever not null, since nothing ever changes current or current->link.
If that's not actually your problem (because of a copy pasta problem, for example) you should show us how you're building your list and what you specifically mean by "doesn't work".
Solved - Problem with constructor
Matthew Flaschen and Michael Burr pointed out the problem of the overloaded constructor of Node(int) calling Node() which doesn't work because...
Thanks guys!
I have built a program (I am debugging it) and have run into a weird problem... A `if` statement is not getting triggered when it should be... This is a school project where we must build an AVL Tree with at least one 'optimizing' feature.
I am sure and have tested that the `rdown` and `ldown` work (as the balancing factors) - the tree is not perfectly balanced. Rather it is based on the hight of the branches (i.e. - `balance()` should only return (1,0,-1) otherwise it is unbalanced.
I hope this is enough information to solve this weird problem... I have never ran into anything like this before with Microsoft Visual Studio 2010.
Node struct:
struct Node {
int data; // the data in the Node
int rdown; // the number of ellements below the node on the right side
int ldown; // the number of ellements below the node on the left side
Node * parrent; // the node's parrent
Node * lchild; // the nodes left child
Node * rchild; // the nodes right child
Node () { rdown = 0, ldown = 0; data = 0; parrent = NULL; lchild = NULL; rchild = NULL; }
Node (int dat) {rdown = 0, ldown = 0; parrent = NULL; lchild = NULL; rchild = NULL; data = dat; }
bool end() { if (lchild == NULL && rchild == NULL) return true; // check if this node is the 'end of the line' - where it doesn't
return false; } // have any children
bool goodToAdd() { if (lchild == NULL || rchild == NULL) return true; // make sture the current node has at least one spot to add
return false; } // a new node to - either lchild or rchild must be NULL
int balance() { return (ldown - rdown); } // get a balance number for the node
};
Search function that is causing the problems
Node * AVL_Tree::search(const Node * num) {
Node * tmpNode = AVL_Tree::root; // tmpNode is a place holder for the search
for (int i = 1; true; i++) { // increment int i to check for excess searching -> pervents endless loop
if (tmpNode == NULL) //****** causing problems******** // the search has reached a dead end (the data is not contained) ==> NULL
return NULL;
if (tmpNode->data == num->data) // if the data of num is the same as tmpNode the data is contained ==> Node *
return tmpNode;
// since the node has not been found yet move down the tree...
if (tmpNode->data > num->data && tmpNode->lchild != NULL) // if the data is smaller than the tmpNode move to the lchild
tmpNode = tmpNode->lchild;
else if (tmpNode->rchild != NULL) // since the node has been proven to not be = to the data to be searched for
tmpNode = tmpNode->rchild; // and it is not smaller... move to the right
if (i > (root->ldown + 1) && i > (root->rdown + 1) ) { // the while loop has searched suffecent time and has not ended
string tmp = "the search incountered a critical error... aborting..."; // to prevent an endless loop the string error
throw tmp; // is thrown (should not happen) - indicates a broken tree
}
}
}
A screen shot of the first encounter with the for loop
A screen shot of the second encounter with the for loop
If you would note in the 'Autos' tab at the bottom that all the data and the node itself's address is NULL - yet in the next screen shot it continues
The program continues!!! what?>!
I pushed F-10 (the 'go to next command' button) ... and it jumps right over the statement? why?
0xcdcdcdcd is not a NULL pointer - that value is used in the debug builds of MSVC for memory that has been allocated but not initialized.
See When and why will an OS initialise memory to 0xCD, 0xDD, etc. on malloc/free/new/delete? for more details.
The root of your problem might be in the constructor that takes an int parameter:
Node (int dat) { Node(); data = dat; }
The Node(); statement ends up doing nothing. This constructor leaves most of the members of the structure uninitialized.
tmpNode is not null in any screenshot.
It's first 0x00294820, then 0xcdcdcdcd. The second is the magic debug value for uninitialized malloced memory.
NULL, in C++, tends to be (but is not guaranteed to be) 0.
In your second/third screenshots, tmpNode = 0xcdcdcdcd, which is not NULL. 0xcdcdcdcd is the value Visual Studio gives to uninitialized variables (when running a debug release).
Make sure to initialize all all your nodes' fields:
Node* root = NULL;
or
Node* root = new Node(); //Don't forget to delete!
Setting fields to NULL is not done automatically in C++ as it is in other languages like Java and C#.
tmpNode is referencing uninitialized memory, which is generally not guaranteed to be null. For instance, the following statement does not guarantee that tmpNode is null.
Node* tmpNode; // or assignment to another uninitialized variable.
You are assigning tmpNode to root and I suspect that root is uninitialized, hence the non-null value of tmpNode. Please check your initialization of root -- I cannot comment on it as you haven't posted this specific code.