i've got an own implemented list:
struct NodeComposition {
Int32 index;
Int8 address;
char* label;
NodeComposition* next;
};
and I am creating new structs with the following method, whereas the label of the root element is initialized with NULL and is changed later on.
NodeComposition ListManager::getNewNode(char* label, Int8 address)
{
NodeComposition* newNode = new NodeComposition;
newNode->address = address;
newNode->label = label;
newNode->next = 0;
newNode->index = -1;
return *newNode;
}
In order to check if a specific "label" exists I have implemented following method:
NodeComposition* ListManager::labelExists(char* label)
{
UInt32 i = 0;
NodeComposition* conductor = &rootNode;
// Traverse through list
while(i < elements)
{
// Label has been found
if (strcmp(conductor->label, label) == 0)
{
return conductor;
}
/* Advancing in list */
else
{
if(conductor->next != 0)
{
conductor = conductor->next;
}
else
{
/* Error: Null reference found in conductor->next */
return NULL;
//return Errors::NULL_REFERENCE;
}
}
i++;
}
/* label not found */
return NULL;
}
And here comes my problem:
I called the labelExists(char* label) method (With a linked list of two elements)
After it compares the two strings it changes the value of the member label of the second element inside of the first iteration
This data is some random trash out of my main memory and I do not have any idea why it behaves like that. Additionally, exactly this code worked just an hour before. At least I think that it did because I can not remember changing any code.
Does anybody has an idea?
Thank you!
Edit:
here is some additional code
NodeComposition newNode = getNewNode(label, address);
ListManager::addNode(newNode);
Int32 ListManager::addNode(NodeComposition node)
{
node.index = elements;
lastNode->next = &node;
lastNode = &node;
elements++;
return lastNode->index;
}
It is definitely not strmcp, so let's not focus on that. You should clean up this code first. There are memory leak and corruption going on.
To start with:
NodeComposition ListManager::getNewNode(char* label, Int8 address)
{
NodeComposition* newNode = new NodeComposition; // $#!^!memory allocated
newNode->address = address;
newNode->label = label; // $#!^! is label allocated on stack or heap? possible leak & corruption
newNode->next = 0;
newNode->index = -1;
return *newNode; // $#!^!return by value. newNode is now lost! memory leak
}
Then in your additional code:
NodeComposition newNode = getNewNode(label, address); // $#!^! getting a copy of the "newNode" only. This copy is allocated in stack.
ListManager::addNode(newNode); //$#!^! adding a stack object onto linked list
Int32 ListManager::addNode(NodeComposition node)
{
node.index = elements;
lastNode->next = &node;
lastNode = &node; //node is actually allocated from stack, not heap! likely memory corruption here!
elements++;
return lastNode->index;
}
I got the answer .. I modified my code like this:
Int32 ListManager::addNode(NodeComposition* node)
{
node->index = ++elements;
lastNode->next = node;
lastNode = node;
return lastNode->index;
}
NodeComposition* ListManager::getNewNode(char* label, Int8 address)
{
NodeComposition* newNode = new NodeComposition;
newNode->address = address;
newNode->label = label;
newNode->next = 0;
newNode->index = -1;
return newNode;
}
NodeComposition* ListManager::labelExists(char* label)
The use of pointers helped me out - Thank you guys.
Related
I'm just getting back into coding. It's been a few years. I can not figure out why this is throwing a nullptr access violation. I've condensed it into a single line of code. The violation is thrown when I try to set my second entry (newNode's pLast pointer) to head.
I'm trying to create a doubly linked list with a bubble sort based off of searches performed (aka countVar). Any help would be great.
#include <iostream>
#include <stdlib.h>
using namespace std;
//build class that has a private function to inc count.
class LinkedListCount {
private:
struct CountNode {
int data;
int countVar; //Make the variable "countVar" private to protect integrity.
CountNode* pNext = NULL;
CountNode* pLast = NULL; //Needed for bubbling back through list.
};
//Keep track of head
CountNode* head;
CountNode* current;
CountNode* temp;
public:
//Constructor Function (Set default values for head, current, and temp)
LinkedListCount() {
head = NULL;
current = NULL;
temp = NULL;
}
void AddNode(int dataIn) { //Addnode Function
//Create and populate list.
CountNode* newNode = new CountNode;
newNode->pNext = NULL;
newNode->pLast = NULL;
newNode->data = dataIn;
temp = head;
newNode->countVar = 0;
if (temp != NULL) { //We already have data entery.
if (temp->pNext == NULL) {
newNode = temp->pNext;
newNode->pLast = head; //****THIS IS WHERE ACCESS VIOLATION OCCURES
}
//Set variables with the understanding that the head is the only data point.
else {
current = temp->pNext; //Set it equal to head.
}
while (current->pNext != NULL) {//This could be eliminated with keeping track of a tail.
current = current->pNext; //Attach this to the end of the list.
}
current->pNext = newNode; //And newMode->pNext = to Null so next time I add data I'll get to the end of the list.
newNode->pLast = current;
}
else if (head == NULL) {
head = newNode;
}
}
};
void addNodes(LinkedListCount &DataList) { //Populates list.
for (int i = 0; i < 20; i++) {
DataList.AddNode(i);
}
}
int main(void)
{
addNodes(DataList);
}
if (temp->pNext == NULL) { // temp->pNext is NULL
newNode = temp->pNext; // newNode is now NULL too
newNode->pLast = head; // attempt to use pLast of NULL
}
I've put comments in your code to see why you have the access violation.
I'm working on a C++ assignment where I'll create a search engine on a linked list of linked lists. As per the requirements, I can't use other libraries nor STL.
Basically it will be like this (I removed the variables from small list since they are irrelevant):
My structs are these:
struct small
{
int data;
struct small *next;
};
struct big
{
int playerID;
string playerName;
string playerTeam;
struct small *goals;
struct big *next;
};
Here's the relevant code snippet, I think the problem is at addGoals(...) where I'm failing to assign the small element to the temp->goals.
class biglist
{
private:
big *head, *tail;
public:
biglist()
{
head = NULL;
tail = NULL;
}
. . .
void createbig(int ID, string name, string team)
{
big *temp = new big;
temp->playerID = ID;
temp->playerName = name;
temp->playerTeam = team;
temp->goals = NULL;
temp->next = NULL;
if (head == NULL)
{
head = temp;
tail = temp;
temp = NULL;
}
else
{
tail->next = temp;
tail = temp;
}
}
void addGoals(int id, small *s)
{
big *temp = head;
while (temp != NULL)
{
if (temp->playerID == id)
{
temp->goals = s;
break;
}
temp = temp->next;
}
}
void test()
{
big *temp = head;
while (temp != NULL)
{
if (temp->playerID == 1)
{
if (temp->goals !=NULL)
{
cout << temp->goals->data << endl;
}
else
{
cout << "goals null" << endl;
}
}
temp = temp->next;
}
}
}
. . .
class smalllist
{
private:
small *head, *tail;
public:
smalllist()
{
head = NULL;
tail = NULL;
}
void createsmall(int ID, biglist b)
{
small *temp = new small;
temp->data = ID;
temp->next = NULL;
if (head == NULL)
{
head = temp;
tail = temp;
temp = NULL;
}
else
{
tail->next = temp;
tail = temp;
}
b.addGoals(1, temp);
}
};
Finally, my main code:
int main()
{
biglist obj;
obj.createbig(1, "Player1", "Team1");
obj.createbig(2, "Player2", "Team2");
obj.displaybig();
smalllist sml;
sml.createsmall(9, obj);
sml.displaysmall();
obj.displaybig();
obj.test();
}
Debugging throws an exception at:
cout << temp->goals->data << endl;
saying that
Exception thrown: read access violation. temp->goals was nullptr.
I'm 90% sure I messed up something with pointers; but other stuff I've tried gave errors before compiling. I checked out some books / tutorials but couldn't figure it out.
Also if you have a better approach or saw one of the horrible mistakes that I'm making, please don't hold back :)
Thanks.
EDIT I changed my createbig() like this.
Currently it works with following codes:
void createbig(int ID, string name, string team, small *s)
{
big *temp = new big;
temp->playerID = ID;
temp->playerName = name;
temp->playerTeam = team;
temp->goals = s;
temp->next = NULL;
if (head == NULL)
{
head = temp;
tail = temp;
temp = NULL;
}
else
{
tail->next = temp;
tail = temp;
}
}
and added this to small
small getsmall(int i)
{
small *temp = head;
while (temp != NULL)
{
if (temp->data == i)
{
return *temp;
}
}
}
My final main function is
int main()
{
smalllist sml;
sml.createsmall(9);
sml.displaysmall();
biglist obj;
small s = sml.getsmall(9);
obj.createbig(1, "Player1", "Team1", &s);
//obj.createbig(2, "Player2", "Team2");
obj.displaybig();
obj.test();
}
While it ends successfully now, it gives the address of goals and I get this in debug section:
Let's look at what your code does, going through the main function. (Being able to walk through code like this is a useful skill. You can also use a debugger to help out, stepping through your function line-by-line.)
biglist obj;
Default construct a biglist. The head and tail are null. (By the way, nullptr is C++'s replacement for C's NULL.)
obj.createbig(1, "Player1", "Team1");
obj.createbig(2, "Player2", "Team2");
Add entries in obj for players with IDs 1 and 2. Their goals are null.
obj.displaybig();
Presumably an output of obj?
smalllist sml;
sml.createsmall(9);
sml.displaysmall();
These lines do something with a smalllist, but do not reference obj, so they are not relevant to this issue.
obj.displaybig();
Presumably an output of obj? Kind of redundant since nothing affected obj since the last display.
obj.test();
Call the test code, which finds the element for player ID 1 and outputs the data of that player's first goal. However, if you look up where that player was added, the goal is null, so you get a crash.
Separate from the above, there is probably some confusion in createsmall. Inside that function, a new biglist is created (not obj), and that list is told to add a goal to the player with ID 1. However, this has no effect the biglist in the main function.
You don't seem to have added any goals, so I'm assuming the code initializes with null.
and so the nullptr exception.
call addgoals() with the goals to player before test().
the other suggestions would be
to add a null check before printing goals
temp pointers need not be initialized with new big or small just the head of the list would be enough
I have been working on a linked list problem, using two pointers to the head and the tail of the list respectively. The issue I have is the following:
When I want to remove from the front or the back of the list, I get memory leaks when the corresponding class methods are implemented using temporary dynamically allocated node pointer and I can't find out what exactly is the problem that is causing the leak.
#include <iostream>
class Node {
public:
Node():data(0),ptrNode(nullptr){};
~Node() {};
// declaring the getters and setters
float getData() const {return data;};
void setData(float d) {data = d;};
Node* getNodePtr() const {return ptrNode;};
void setNodePtr(Node* n){ptrNode = n;};
private:
float data;
Node* ptrNode;
};
class List {
private:
Node * ptrHead;
Node * ptrTail;
public:
List():ptrHead(nullptr),ptrTail(nullptr) {};
~List() {};
void insertAtFront(float x) {
Node * temp = new Node();
temp->setData(x);
if (ptrHead == nullptr) {
ptrHead = temp;
ptrTail = temp;
} else {
temp->setNodePtr(ptrHead);
ptrHead = temp;
}
};
void insertAtBack(float x) {
Node * temp = new Node();
temp->setData(x);
if (ptrHead == nullptr) {
ptrHead = temp;
ptrTail = temp;
} else {
ptrTail->setNodePtr(temp);
ptrTail = temp;
}
};
void removeFromFront() {
if (ptrHead==nullptr) { // if list is empty
std::cout << "List is already empty" << std::endl;
return;
}
if (ptrHead==ptrTail) { // if list has one element
delete ptrHead;
ptrHead = nullptr;
ptrTail = nullptr;
return;
}
// assign current Head to temp, assign next node to head
// delete temp
Node * temp = new Node();
temp = ptrHead;
ptrHead = ptrHead->getNodePtr();
delete temp;
temp = nullptr;
};
void removeFromBack() {
if (ptrHead==nullptr) { // if list is empty
std::cout << "List is already empty" << std::endl;
return;
}
if (ptrHead==ptrTail) { // if list has one element
delete ptrHead;
ptrHead = nullptr;
ptrTail = nullptr;
return;
}
// create two temp Node pointers for this one
Node * sec2last = new Node();
Node * last = new Node();
sec2last = ptrHead;
last = ptrTail;
// locate second to last element and assign it to sec2last
while (sec2last->getNodePtr() != ptrTail) {
sec2last = sec2last->getNodePtr();
}
ptrTail = sec2last;
ptrTail->setNodePtr(nullptr);
delete last;
delete sec2last;
last = nullptr;
sec2last = nullptr;
};
};
I run the following in main():
// global function that dynamically allocates memory in its scope
// for a linked list
void generateList(int x) {
if (x<=0) {
cout << "Give a positive integer!" << endl;
return;
}
List * aList = new List();
for (int i = 0;i<x;i++) {
aList->insertAtFront(i+1);
}
aList->removeFromBack(); // this causes leaks
delete aList;
}
// MAIN
int main() {
for (int i = 0;i<80000000;i++)
generateList(1); // just repeatedly generate dynamic list
// with one element
return 0;
}
I should point out that if we don't use dynamically allocate memory for the temporary nodes within the removeFromFront() and removeFromBack() methods, then the program works fine. But, like I said, It kills me that I can't see why we have leaks with the code above.
Thanks!
Node * temp = new Node();
temp = ptrHead;
This is a memory leak right here. You allocate a new Node and store a pointer to it in temp. Then you overwrite that pointer and leak the node you just allocated.
// create two temp Node pointers for this one
Node * sec2last = new Node();
Node * last = new Node();
sec2last = ptrHead;
last = ptrTail;
And here you do it again. Why are you allocating new Nodes here?
So I've been doing a home assignment on data structures and for more than a couple hours I'm in a dead end. To explain, I have to text files ListJava and ListDS where i take information in the format : Name Surname NUM grade . Both of the files contain the same names but not the same order. The assignment basically wants us to merge sort the files.
These are my structures:
typedef struct student
{
string name;
string surname;
int am;
int grade;
}StudentFile;
typedef struct node {
StudentFile element;
struct node* next;
}Node;
typedef struct stud
{
string name;
string surname;
int am;
int grade;
int grade2;
struct stud* next;
}Student;
And here is my function where I merge them:
/*Merge Lists into one*/
Student* MergeLists(Node* headDS, Node* headJava, Student* head)
{
bool flag = false;
Student *a = new Student;
Student *prev = NULL;
Student *temp = NULL;
Node *tempDS = headDS;
Node *tempJava = headJava;
Node *prevJava = NULL;
if (head == NULL)
{
head = a; //mermory alocation for head<Student>
temp = head;
// temp->next = NULL;
}
while (tempDS != NULL)
{
if(head != NULL)
{
if (tempDS->element.surname.compare(tempJava->element.surname) == 0) // if surnames are equal
{
prev = temp;
temp->name = tempDS->element.name;
temp->surname = tempDS->element.surname;
temp->am = tempDS->element.am;
temp->grade = tempDS->element.grade;
temp->grade2 = tempJava->element.grade;
tempJava = tempJava->next;
tempDS = tempDS->next;
temp = temp->next;
flag = false; //meaning that prevJava can get a new value again.
}
else // if DS > Java
{
/*Keep tempJava in mermory while iterating through the next nodes to find the temp that is equal to DS*/
if (flag == false)
{
prevJava = tempJava;
tempJava = tempJava->next;
flag = true;
}
else
{
tempJava = tempJava->next;
}
}
/*temp = temp->next;
tempJava = tempJava->next;
tempDS = tempDS->next;*/
}
prev->next = a;
}
a->next = NULL;
return a;
}
The problem is on temp = temp->next line. Although the first run is perfectly fine and then correctly searches for the ListJava to find an equal name to ListDS temp value is 0xcdcdcdcd {...} and it throws me an exception:
Exception thrown at 0x00C38EF0 in Exercise3_zitima2.exe: 0xC0000005: Access violation reading location 0xCDCDCDE5.
How can i counter this error, I have really searched around tried things here and there but nothing seems to work out. I know this isn't a place to ask for someone to solve my assignment of course, just need a tad guidance.
Your Student struct doesn't have a constructor, so when you allocate one and assign it to a in MergeLists, a->next will have garbage in it. (The 0xCDCDCDCD is what MSVC fills allocated memory with so you can see these sorts of uninitialized usage.)
You either need to have a constructor set the next pointer to NULL or manually set it to NULL after you allocate it.
A merge list function is normally used to merge two already sorted lists. No allocation of nodes is involved. The first node from one list is compared to the first node of the other list. The smaller node is removed from it's list and appended to what is an initially empty list that will end up with the merged nodes. The only node members that are changed are the next pointers. The process is repeated until the end of one of the lists is reached, and then the next pointer of the last node added to the merged list is set to point to the first node of the remainder of the other list, and the merge is done.
I am working on unsorted linked list check full currently, below is my specification and implementation.
Specification:
#ifndef UNSORTEDLIST_H
#define UNSORTEDLIST_H
#include <iostream>
using namespace std;
struct Node {
float element;
Node* next;
};
class UnsortedList
{
public:
UnsortedList();
bool IsEmpty();
bool IsFull();
void ResetList();
void MakeEmpty();
int LengthIs();
bool IsInTheList(float item);
void InsertItem(float item);
void DeleteItem(float item);
float GetNextItem();
private:
Node* data;
Node* currentPos;
int length;
};
#endif
And implemetation:
UnsortedList::UnsortedList()
{
length = 0;
data = NULL;
currentPos = NULL;
}
bool UnsortedList:: IsEmpty(){
if(length == 0)
{
return true;
}
else
{
return false;
}
}
bool UnsortedList::IsFull(){
Node* ptr = new Node();
if(ptr == NULL)
return true;
else
{
delete ptr;
return false;
}
}
void UnsortedList::ResetList(){
currentPos = NULL;
}
void UnsortedList::MakeEmpty()
{
Node* tempPtr = new Node();
while(data != NULL)
{
tempPtr = data;
data = data->next;
delete tempPtr;
}
length = 0;
}
int UnsortedList::LengthIs(){
return length;
}
bool UnsortedList:: IsInTheList(float item){
Node* location = new Node();
location = data;
bool found = false;
while(location != NULL && !found)
{
if(item == location->element)
found = true;
else
location = location->next;
}
return found;
}
void UnsortedList:: InsertItem(float item){
Node* location = new Node();
location->element = item;
location->next=data;
data = location;
length++;
}
void UnsortedList:: DeleteItem(float item){
Node* location = data;
Node* tempPtr;
if(item == data->element){
tempPtr = location;
data = data->next;
}
else{
while(!(item == (location->next) ->element) )
location = location->next;
tempPtr = location->next;
location->next = (location->next)->next;
}
delete tempPtr;
length--;
}
float UnsortedList::GetNextItem(){
if(currentPos == NULL)
currentPos = data;
else
currentPos = currentPos->next;
return currentPos->element;
}
1.In the constructor, why don't assign currentPos as null?
2.In the IsInTheList function, Why points to pointer "next" ? Isn't next is a null pointer since it has been declared in struct as Node* next?
The pointer value is not set to NULL value by default, you should set to to null explicitly. Also instead of using NULL, choose using nullptr.
This code is rather incomplete, so it is difficult to answer your questions.
This does not contain the code to insert an item in the list, which is where I would expect both the next and currentPos pointers to be set. However, that's based on a number of assumptions.
However, I don't see where next is used in the "check full function" at all, so that question is a bit confusing.
I'll also point out that this code has a glaring memory leak. The first line in IsInTheList allocates memory for a new Node, which is immediately lost with location = data.
Pointers (like any other basic type) need to be initialized before use. A value of NULL is still a value.
The code you provided seems to be very incomplete. Is data supposed to be the head of your list? I am not sure how you define "fullness". If you want to test if the list is empty, you can see if your "head" of the list is null:
bool UnsortedList::IsEmpty() {
if (data == NULL) {return true;} // if there is no first element, empty
else {return false;} // if there is ANY element, not empty
}
Or more compactly:
bool UnsortedList::Empty() {
return (data == NULL);
}
When a node is added to a linked list, we usually add the node as a whole and modify the element that came before it. For example, we might create a new node and add it using code like the following:
// implementation file
void UnsortedList::InsertItem(const float& item) {
if (data == NULL) { // no elements in list, so new node becomes the head
data = new Node; // allocate memory for new node
data->element = item; // fill with requested data
data->next = NULL; // there is no element after the tail
}
else {
new_node = new Node; // allocate memory
new_node->element = item // set data
new_node->next = NULL; // new end of the list, so it points to nothing
tail->next = new_node; // have the OLD end node point to the NEW end
tail = new_node; // have the tail member variable move up
}
}
// driver file
int main() {
UnsortedList my_list;
float pie = 3.14159;
my_list.AddNode(pie);
return 0;
}
Please note that I made use of a Node* member variable called tail. It is a good idea to keep track of both where the list begins and ends.
In your IsFull function, it will always return false since it can always create a new Node*. Except perhaps if you run out of memory, which is probably more problematic.
Your functions are rather confusing and your pointer work leaves many memory leaks. You might want to review the STL list object design here.