The following code is part of my implementation for a class member function that rents lockers and thus creates nodes in a linked list:
void SelfStorageList::rentLocker(Locker e) {
int count = 0;
LockerNode *p = head;
if (isEmpty()) {
head = new LockerNode(e, head);
tail = head;
}
LockerNode *prev = head;
LockerNode *curr = head->next;
for( ; curr != 0 && curr->objLocker.isVip; prev = prev->next, curr = curr->next) {
if(count == 1) {
if (e.isVip) {
if(p->objLocker.isVip) {
LockerNode *p = new LockerNode(e, p->next);
}
else {
LockerNode *p = new LockerNode(e,head);
}
}
//etc...
When I run it, I get two errors that my *p pointers may potentially be uninitialized. I don't think they would pose any sort of run time error issues, but the program will not compile as long as the errors persist. I was wondering what alternative I might have to the current implementation of the
LockerNode *p = new LockerNode(e, p->next);
and
LockerNode *p = new LockerNode(e,head);
lines. All I want them to do is to create new nodes with the passed in info element of e, either before the current listed locker or after, depending on the condition.
Thanks for any help provided! Let me know if it would be useful to post any other particular parts of the code, although it is quite lengthy, so I was hoping to avoid posting it all and isolating the problem into a manageable module.
In this if-else, you are declaring a new pointer p in each block:
if(p->objLocker.isVip) {
LockerNode *p = new LockerNode(e, p->next);
}
else {
LockerNode *p = new LockerNode(e,head);
}
Each one of these is local to the scope. It results in a memory leak, and has no effect on the p from the outer scope.
Related
I need to implement a doubly linked list in c++ for a small animation running on console. The linkedlist stores clouds and then they move through the console and as each cloud hits the end of screen, it needs to be deleted from linked list. As the cloud hits the end, it has a variable called alive which is set to false so it can be deleted.
I can't upload the full game code, but I have recreated the problem in dummy code by creating sample clouds where some of them have alive = true and alive = false. I have also updated the previous and next nodes of the cloud to be deleted but I still get an error:
Exception thrown: read access violation. temp was 0xFFFFFFFFFFFFFFFF.
Code below (include statements removed for simplicity)
Test.cpp
int main() {
Cloud* a = new Cloud('a');
a->alive = false;
Node* a1 = new Node(a);
Cloud* b = new Cloud('b');
b->alive = false;
Node* b1 = new Node(b);
LinkedList list;
list.Insert(a);
list.Insert(b);
Node* temp = list.head;
while (temp != nullptr) {
if (temp->data->alive == false) list.Delete(temp); // throws exception after deleting a single node.
temp = temp->next;
}
return 0;
}
LinkedList.cpp delete function
void LinkedList::Delete(Node* del) {
if (del == head) {
OutputDebugStringA("Cloud in head");
Node* temp = head;
head = head->next;
head->prev = nullptr;
delete temp;
return;
}
else {
Node* temp = head;
while (temp != tail->next) {
if (temp == del) {
if (temp->next != nullptr) {
OutputDebugStringA("Cloud in mid");
temp->prev->next = temp->next;
temp->next->prev = temp->prev;
break;
}
else {
OutputDebugStringA("cloud at tail");
tail = temp->prev;
tail->next = nullptr;
break;
}
}
temp = temp->next;
}
delete temp;
temp = nullptr;
}
}
Node.cpp
#include "Node.h"
#include <iostream>
using namespace std;
Node::Node() {
this->data = nullptr;
}
Node::Node(Cloud* data) {
this->data = data;
}
Someone please point out where am I going wrong. Thanks
if (temp->data->alive == false) list.Delete(temp); // throws exception after deleting a single node.
temp = temp->next;
Here, temp gets passed into the Delete() method. Afterwards temp gets set to temp->next.
In Delete():
delete temp;
temp = nullptr;
The object referenced by the passed-in temp pointer (here, this temp, by the virtue of the preceding logic, is the same pointer that gets passed in) gets deleted.
After returning, temp->next references a deleted object.
This is at least one confirmed instance of undefined behavior in the shown code. This may or may not be the only bug.
As it's been pointed out to you in comments, this overall Delete() logic is fundamentally flawed. It should not involve any kind of iteration, for a doubly-linked list. You will end up fixing this bug while rewriting Delete() from scratch (which includes rethinking how Delete() itself gets called, because after it returns temp is no longer usable for anything).
As #John Zwinck and #Sam Varshavchik pointed out that the implementation of delete method was flawed and temp became useless after the Delete function returned.
I fixed it by using another temp pointer and fixing the delete method to be O(1).
Delete Method
void LinkedList::Delete(Node* del) {
if (del == head) {
head = head->next;
head->prev = nullptr;
}
else if (del == tail) {
tail = del->prev;
tail->next = nullptr;
}
else {
del->prev->next = del->next;
del->next->prev = del->prev;
}
delete del;
}
Node deletion
Node* temp = cloud_list.head;
Node* next;
while (temp != nullptr) {
next = temp->next;
if (temp->data->alive == false) {
cloud_list.Delete(temp);
}
temp = next;
}
The deletion now works fine.
I have been learning C++ for the last couple of months, and after going through an online course I have started doing some challenges with using raw pointers. I have successfully created class that can initiate and iterate through linked list, with lots of struggle I managed to create method that deletes its element(s), but I am struggling to write a method that would remove all the duplicates.
I have a method such as
void linked_list::remove_dups(){
Node *p = first;
Node *g = first;
while(p!=NULL){
int x = 0;
g = new Node;
g = first;
Node *remove = first;
while (g!=NULL){
if(p->data == g->data){
x++;
}
if(x>1){
remove = new Node;
remove = p;
p = p->next;
remove->next = p->next;
delete remove;
x--;
}
g = g->next;
}
p = p->next;
}
}
where Node is standard
struct Node{
int data;
struct Node *next;
};
first is private member
Node *first;
Can anyone point out what is wrong in this function and explain please? I initiated list with pointers that is
int a[] = {3,5,5,7,65,5,65,65,4,4,15};
and it removed most of the duplicates, but not all. If I add more though, I have EXC_BAD_ACCESS error.
Really appreciate any help!
The main issue is:
p = p->next;
remove->next = p->next;
delete remove;
You try to set remove->next to point to the new next element. But remove is going to be deleted. So the element before remove will still point to something deleted. So, after the delete, you'll have a broken list that contains pointer to deleted elements. Next loop iteration, it will break.
Below is the code I edited as I went. Please note that
remove = new Node;
remove = p;
is not only useless, it leaks memory. You can directly do remove = p;
Just draft code as I went. Not fixed. Proper would be keeping a prev pointer or something.
void linked_list::remove_dups()
{
Node *p = first;
Node *g = first;
while(p!=NULL)
{
// int x = 0; remove this
// g = new Node; remove this
g = first;
Node *remove = first;
while (g != NULL)
{
if(p->data == g->data) // test directly, no x
{
// remove = new Node; remove this
remove = p;
p = p->next;
// remove->next = p->next; You are going to delete this, no point modifying it
delete remove;
}
g = g->next;
}
p = p->next;
}
}
Something I wrote for my custom doubly-linked list that will remove duplicates. Not necessarily the most efficient but it gets the job done.
void unique()
{
std::map<int, int> hash;
Node<T>* temp = this->head;
while(temp)
{
hash[temp->data]++;
if(hash[temp->data] > 1)
{
Node<T>* next = temp->next;
Node<T>* prev = temp->prev;
delete temp;
temp = nullptr;
if(!next)
{
temp = prev;
temp->next = nullptr;
hash[temp->data]--;
break;
}
next->prev = prev;
prev->next = next;
temp = next;
hash[temp->data]--;
}
else
{
temp = temp->next;
}
}
}
I have a function:
void initGraph(node_t *node, const int orderedInputNodes[]) {
int index;
for (int i = 0; i < S * 2; i++) {
if (orderedInputNodes[i] == node->number) {
index = i % 2 == 0 ? i + 1 : i - 1;
node_t newNode;
newNode.number = orderedInputNodes[index];
newNode.left = EMPTY;
newNode.right = EMPTY;
if (node->left == EMPTY) {
node->left = &newNode;
}
else if (node->right == EMPTY) {
node->right = &newNode;
}
}
}
.
.
.
}
Everytime I find a corresponding number I create newNode, assign its value to it and pass it either to the left or to the right, however, when the code comes to the part when the right child is being assigned, the left child gets overwritten. How come is that? I thought by stating node_t newNode; a completely new node will be automatically created.
I thought by stating node_t newNode; a completely new node will be automatically created.
Correct. The problem is that the new node can replace the old node. Consider:
for (int j = 0; j < 1000; ++j)
{
int i;
i = 3;
}
You don't think after this loop runs, there's a thousand instances of i still sitting around, do you? Every time this bit of code runs, a new i is created. But every time this bit of code runs, the i from the previous iteration doesn't exist anymore because it goes out of scope.
You have:
{
node_t newNode; // newNode is created here
newNode.number = orderedInputNodes[index];
newNode.left = EMPTY;
newNode.right = EMPTY;
if (node->left == EMPTY) {
node->left = &newNode; // you save a pointer to it here
}
else if (node->right == EMPTY) {
node->right = &newNode;
}
}
// but newNode doesn't exist anymore here
So you've saved a pointer to an object that no longer exists. It winds up pointing to whatever happens to be stored in that memory, likely the next newNode that is created on the next pass in the loop.
Don't store pointers to local objects.
Update: You say you're coding in C++. Why are you using raw pointers then? Do you really want to manually manage the lifetimes of objects? C++ has fantastic tools to make this easy like std::unique_ptr.
I'm trying to remove duplicates from linked list, but I have a bug in the code, I can't figure it out... So it seems there is a logical bug when for example found a duplicated node, the deletion is not correct?
ListNode *deleteDuplicates(ListNode *head) {
if (head == nullptr)
return head;
bool visited[255];
memset(visited, false, sizeof(visited));
ListNode * t = head;
ListNode *p = head;
while (t)
{
if (!visited[t->val])
{
visited[t->val] = true;
}
else{
ListNode *temp = t;
p->next = temp->next;
delete temp;
}
p = t;
t = t->next;
}
return head;
}
The problem is that when you find a duplicate you delete temp which actually equals to t. Then later, when you call t = t->next you're referring to a deleted pointer which is of course illegal.
A simple solution would be to change the while loop to look like:
while (t)
{
ListNode *temp = NULL; // added
if (!visited[t->val])
{
visited[t->val] = true;
}
else{
temp = t; // changed
p->next = temp->next;
// delete temp; // commented out (moved below)
}
p = t;
t = t->next;
if (temp) { // Added - delete temp folder in case it was set
delete temp;
}
}
Your code invokes undefined behavior. When you delete the object pointed by temp, it disqualifies the internal fields of the object, including the next field. Since t points to the same object as temp, t's fields also become invalid. Therefore, the assignment t = t->next will produce non-deterministic result.
I'm trying to incorporate push/pop into a linked list and I can't seem to get it to work. When I run my test function, I set my linked list to zero and I try to push on values but the list keeps getting returned with no values in it. Could anyone possibly tell me what I'm doing wrong?
if (top == NULL){
current = top;
current->next = NULL; //NULL->next : will cause segfault
}
if top is NULL, you set current = top [which is NULL], and then you access current->next, which will cause a segfault, you are trying to access NULL..
EDIT: follow up to comments:
your if statement seems redundant, you should probably only need to set: current->next = head; and head = current; [in addition to the current allocation]
Instead of
if (top == NULL){
current = top;
current->next = NULL;
}
you want
if (top == NULL){
top = current;
current->next = NULL;
}
And of course, after this, you have to make sure that you actually set head to top again.
Now that you've made this change, it should be clear that both cases do the same thing -- so no case distinction is actually necessary. So the function can be simplified to
void push(Data * newPushData){
LinkNode * current = new LinkNode(newPushData);
current->next = head;
head = current;
}
The top variable is local variable for push(...) function. You can use head instead, and I'd rather modify the if statement.
I think that function should look like this:
void push(Data * newPushData){
LinkNode * current = new LinkNode(newPushData);
if (head != NULL){
current->next = head;
head = current;
}
else{
head = current;
current->next = NULL; // if you haven't done it in LinkNode constructor
}
}
can you please specify the attributes of the linked list class ? [ is there slightly chance you are doing something wrong]
Instead of you , I'd do :
void push(Data * newPushData){
if (head == NULL)
head->data = newPushData
tail = head ;
else // regular situation
{
Node * node = new Node() ;
tail->next = node;
node->data = newPushData;
node->next = NULL ;
tail = node ;
}
}
In a linked list you have got to maintain the head pointer point on the head of the list , maintain that the tail pointer is point on the tail of the list ,
You must take care of the 2 cases of enlarging the list.
the best way for learning is to illustrate an insertion on a blank linked list.
Take care
S
void push(Data * newPushData)
{
if( head != NULL )
{
LinkNode current = new LinkNode(newPushData);
current->next = head;
head = current;
}
else
{
head = new LinkNode(newPushData);
}
}
Try this code...
void push(data * newpushdata){
if(head !=null){
linkednode current = new linkednode(newpushdata);
current->next = head;
head = current;
}
else {
head = new linkednode(newpushdata);
}
}
that is my working solution for a Stack containing int elements, but maybe it's better to create a void pushStack using Stack **S instead of Stack *S.
in pop(Stack **S) i created a sentinel, so if the stack is empty -1 is returned.:
typedef struct StackT {
int val;
struct StackT *next;
} Stack;
int isStackEmpty (Stack *S) {
if (S == NULL)
return 1;
else
return 0;
}
int *pop(Stack **S) {
Stack *tmp = *S;
int i = -1;
if (isStackEmpty(tmp) == 0) {
i = tmp->val;
*S = tmp->next;
}
return i;
}
Stack *pushStack (Stack *S, int x) {
Stack *node = (Stack *) malloc (sizeof (Stack));
node->val = x;
node->next = S;
return node;
}
you can call pop and stack easly:
Stack *S = NULL;
int x = somevalue;
int y;
S = pushStack(S, x);
y = pop(&S);