Pointers to structures in C++ - c++

In order to complete my homework I had to implement a list in C++, thus I defined a structure:
struct Node {
int value;
Node * next;
Node * operator [] (int index)//to get the indexed node like in an array
{
Node *current = this;
for (int i = 0; i<index; i++)
{
if (current==NULL) return NULL;
current = current->next;
}
return current;
}
};
When I used it with actual structures, it worked fine:
Node v1, v2, v3;
v1.next = &v2;
v2.next = &v3;
v3.value = 4;
v3.next = NULL;
cout<<v1[2]->value<<endl;//4
cout<<v2[1]->value<<endl;//4
cout<<v3[0]->value<<endl;//4; works just as planned
cout<<v3[1]->value<<endl;//Segmentation fault
But when i tried to use it with pointers, the things got messed up:
Node *v4, *v5, *v6;
v4 = new Node;
v5 = new Node;
v6 = new Node;
v4->next = v5;
v4->value = 44;
v5->next = v6;
v5->value = 45;
v6->next = NULL;
v6->value = 4646;
//cout cout<<v4[0]->value<<endl; compiler says it's not a pointer
cout<<v4[0].value<<endl;//44
cout<<v4[1].value<<endl;//1851014134
cout<<v4[2].value<<endl;//45
cout<<v4[3].value<<endl;//1851014134
cout<<v4[4].value<<endl;//4646
cout<<v4[5].value<<endl;//1985297391;no segmentation fault
cout<<v6[1].value<<endl;//1985297391;no segmentation fault even though the next was NULL
delete v4;
delete v5;
delete v6;
Though it is possible to work with function, I've got some questions:
Why the returned value in pointers example was a structure but not a pointer?
Why elements now have doubled index and what are the elements between them?
Why there was no segmentation fault?
I'd be very thankful if someone explained me these moments or gave me the sources I could learn from

That's because v4[0] (and the rest) aren't actually calling your Node::operator[]. That's because v4 isn't a Node, it's a Node*, and pointers have a builtin meaning behind operator[]: v4[i] == *(v4 + i) (that is, we're just indexing into that "array"). So when you write something like v4[3], that isn't calling operator[](3)... it's instead giving you back a Node three Nodes after v4 in memory somewhere, which is basically just garbage.
To get what you want to happen, you'd have to dereference the pointers first:
(*v4)[0]
(*v6)[1]
// etc

By doing this
v4 = new Node;
cout<<v4[0].value<<endl;//44
cout<<v4[1].value<<endl;//1851014134
cout<<v4[2].value<<endl;//45
cout<<v4[3].value<<endl;//1851014134
cout<<v4[4].value<<endl;//4646
cout<<v4[5].value<<endl;//1985297391;no segmentation fault
You are not calling operator[] of struct Node, you are making pointer dereferencing, v4[1] is equal to ++v4; *v4; So this code is causing unpredicted behavior, because you are dereferencing some garbage.
To make it work as you want, you need to change it to:
cout<<v4->operator[](0).value<<endl;
cout<<v4->operator[](1).value<<endl;
cout<<v4->operator[](2).value<<endl;
...

Related

Deleting Dynamic Struct in C++

I have struct named Linked number
struct LinkedNum{
int num;
LinkedNum * next;
}
Then I allocate a dynamic memory for this structure using new operator.
LinkedNum * first;
first = new LinkedNum;
first->num = 10;
first->next = nullptr;
LinkedNum * base;
base = first;
base->next = new LinkedNum;
base = base->next;
base->num = 20;
base->next = nullptr;
Now how I will free all the memory used by this struct. There are two structures 1 has num = 10 and other has num = 20.
I want to delete all structures so that there will be no memory leak and no dangling pointers.
Thanks in advance...
Okay, so first you want to start deleting memory from the head of your link or struct. You need to create a loop so it works for multiple structs.
Such as:
while( first != nullptr){
LinkedNum* curr = first;
first = first -> next;
delete curr;
}
This code makes a temporary value where the first is stored and it goes along the link deleting each element one by one and updating values as well.
Hopefully this helps you!

Printing unbalanced binary tree

I'm intentionally creating a wrong and unbalanced binary tree in this code:
void createlist (tree*& node) {
node = new tree;
node->num = 1;
node->left = new tree;
node->left ->num = 2;
node->right = new tree;
node->right->num = 3;
node->left->left = new tree;
node->left->left->num = 4;
node->left->right = new tree;
node->left->right->num = 5;
node->right->left = new tree;
node->right->left->num = 6;
node->left->left->left = new tree;
node->left->left->left->num = 7;
}
Then, when I am trying to print it using an ordinary function for that:
void print (tree* node) {
if (node!= 0) {
print (node->left);
cout << node->num << " ";
print (node->right);
}
}
It throws out an error:
Access violation reading location 0xcdcdcdd5.
at this location:
print (node->left);
I'm just starting with trees and don't quite follow the reason for this error. Could you help with that?
This is an excellent chance for you to learn how to debug your programs. I suggest you run the program in a debugger and see what the values of node and node->left is when the segfault happens.
An access violation is when you are accessing memory that your program is not allowed to access.
Your problem is not trees your problem is using pointers correctly and not initializing your variables properly.
I suspect your problem is that the constructor for tree is not properly doing:
left = NULL;
right = NULL;
Remember in C/C++ that the compiler does not set any specific values into variables when they are created, it is up to you to initialize variables.
It is custom to use NULL (or nullptr in C++11) to rather than 0 to test/set pointers.
Link to C++ pointers tutorial
Hard to tell without the source of your tree class, but perhaps making a new tree doesn't initialize the left and right members to null pointers? In that case, some of your trees will contain uninitialized pointer data.

Deleting elements from doubly bounded pointer list

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.

Circular Singly Linked List: Remove a particular Node from List

I wrote the code to remove a particular node from list according to user
choice, code works perfectly fine for a particular value but if i make
several calls to it meaning if I call it 2 times continuously then one of my
another function pointer_to_node(index) gives an out of bounds error which
was also implemented by me to record such conditions,
Actually, why I need several calls is that I have to write a separate function
to remove all the nodes. I am trying to accomplish that task using this
function by using a for loop up to the size of my Circular Singly Linked list.
But in that case it also returns me a NULL pointer and gives me out of bounds
message (implemented by me in code). I have included both my functions down
here
void remove_from_index(int index){
Node*temptr;
temptr = new Node;
int tempdata;
if (index==1)//means remove from first
{
temptr = firstptr;
tempdata= temptr->data;
firstptr = firstptr->nextptr;
lastptr->nextptr=firstptr;
delete(temptr);
} else if(index==size_of_list()) //means last node
{
temptr = pointer_to_node(index);
index--; //get pointer of 2nd last position
lastptr = pointer_to_node(index);//setting 2nd last as last postion
temptr->nextptr=NULL;
temptr=NULL;
lastptr->nextptr=firstptr;
delete (temptr);
} else // any position of node
{
temptr = pointer_to_node(index);
tempdata = temptr->data;
index--; // to get address of back
Node* temp2ptr;
temp2ptr = new Node;
temp2ptr = pointer_to_node(index);
index = index+2;
Node* temp3ptr;
temp3ptr = new Node;
temp3ptr = pointer_to_node(index);
temp2ptr->nextptr = temp3ptr;
temptr->nextptr=NULL;
delete (temptr);
}
}
Node* pointer_to_node(int index){
Node*temptr;
temptr = new Node;
temptr = firstptr;
Node*temptr2;
temptr2 = new Node;
temptr2 = NULL;
int count = 1;
while (temptr!=temptr2){
if (count==index)
{
return temptr;
}
count++;
temptr2=firstptr;
temptr=temptr->nextptr;
}
if (index>size_of_list())
{
temptr=NULL;
cout<< "Can't You think in bounds. Take your NULL Pointer ";
return temptr;
delete temptr;
delete temptr2;
}
}
You have several memory leaks:
temptr->nextptr=NULL;
temptr=NULL; // BAD!! BAD!! Remove it otherwise you will not actually free
lastptr->nextptr=firstptr;
delete (temptr);
And here too (actually you have this in four places of the code):
Node* temp2ptr;
temp2ptr = new Node; // BADD!! Why do you allocate if you are going to reassign?
temp2ptr = pointer_to_node(index);
Remove the bads and you will avoid the memory leaks.
Still, this is not going to fix your problem.
Also you have operations after return here:
return temptr;
delete temptr;
delete temptr2;
These are never going to be executed.
EDIT Your pointer_to_node function is too complex please change it with
Node* pointer_to_node(int index) {
Node* tempPtr = firstptr;
for (int i = 0; i < index; i++) {
tempPtr = tempPtr->nextptr;
}
return tempPtr;
}
And see if this will fix your problem. More lines of code very rarely means better programming skills, do not artificially try to increase their count.
I think another possible issue here, aside from all the memory leaks and style issues which are already well documented, is that your code does not seem to handle the case of there only being one thing in the list.
If that happens, it will delete that node, but leave firstptr and lastptr pointing at random memory.
If your size_of_list() function is just counting nodes in the list, it will probably still think there are non-zero nodes remaining, and you might then attempt to remove or otherwise access another node.

Deep Copy Linked List - O(n)

I'm trying to deep copy a linked list . I need an algorithm that executes in Linear Time O(n). This is what i have for now , but i'm not able to figure out what's going wrong with it. My application crashes and i'm suspecting a memory leak that i've not been able to figure out yet. This is what i have right now
struct node {
struct node *next;
struct node *ref;
};
struct node *copy(struct node *root) {
struct node *i, *j, *new_root = NULL;
for (i = root, j = NULL; i; j = i, i = i->next) {
struct node *new_node;
if (!new_node)
{
abort();
}
if (j)
{
j->next = new_node;
}
else
{
new_root = new_node;
}
new_node->ref = i->ref;
i->ref = new_node;
}
if (j)
{
j->next = NULL;
}
for (i = root, j = new_root; i; i = i->next, j = j->next)
j->ref =i->next->ref;
return new_root;
}
Can anyone point out where i'm going wrong with this ??
This piece alone:
struct node *new_node;
if (!new_node)
{
abort();
}
Seems good for a random abort() happening. new_node is not assigned and will contain a random value. The !new_node expression could already be fatal (on some systems).
As a general hint, you should only require 1 for-loop. Some code upfront to establish the new_root.
But atruly deep copy would also require cloning whatever ref is pointing to. It seems to me the second loop assigns something from the original into the copy. But I'm not sure, what is ref ?
One thing I immediately noticed was that you never allocate space for new_node. Since auto variables are not guaranteed to be initialized, new_node will be set to whatever value was in that memory before. You should probably start with something like:
struct node *new_node = (new_node *) malloc(sizeof(struct node));
in C, or if you're using C++:
node* new_node = new node;
Copying the list is simple enough to do. However, the requirement that the ref pointers point to the same nodes in the new list relative to the source list is going to be difficult to do in any sort of efficient manner. First, you need some way to identify which node relative to the source list they point to. You could put some kind of identifier in each node, say an int which is set to 0 in the first node, 1 in the second, etc. Then after you've copied the list you could make another pass over the list to set up the ref pointers. The problem with this approach (other that adding another variable to each node) is that it will make the time complexity of the algorithm jump from O(n) to O(n^2).
This is possible, but it takes some work. I'll assume C++, and omit the struct keyword in struct node.
You will need to do some bookkeeping to keep track of the "ref" pointers. Here, I'm converting them to numerical indices into the original list and then back to pointers into the new list.
node *copy_list(node const *head)
{
// maps "ref" pointers in old list to indices
std::map<node const *, size_t> ptr_index;
// maps indices into new list to pointers
std::map<size_t, node *> index_ptr;
size_t length = 0;
node *curn; // ptr into new list
node const *curo; // ptr into old list
node *copy = NULL;
for (curo = head; curo != NULL; curo = curo->next) {
ptr_index[curo] = length;
length++;
// construct copy, disregarding ref for now
curn = new node;
curn->next = copy;
copy = curn;
}
curn = copy;
for (size_t i=0; i < length; i++, curn = curn->next)
index_ptr[i] = curn;
// set ref pointers in copy
for (curo = head, curn = copy; curo != NULL; ) {
curn->ref = index_ptr[ptr_index[curo->ref]];
curo = curo->next;
curn = curn->next;
}
return copy;
}
This algorithm runs in O(n lg n) because it stores all n list elements in an std::map, which has O(lg n) insert and retrieval complexity. It can be made linear by using a hash table instead.
NOTE: not tested, may contain bugs.