So I've been trying to create a class that handles 1000 linked lists, and initially declares pointers to them.
This is the code that deals directly with my issues:
struct node
{
char name[40];
char numb[12];
node * next;
};
class hashTable
{
public:
//Creates a table of 1000 pointers to linked-list nodes
node * table[1000];
//Functions
void addNode(char name[40], char numb[12])
{
node * temp; //Initializes temp node as pointer
temp = new node; //Points temp node to a new node
int hash = h(g(name)); //The hash of the key (name) used to check nodes
temp = table[hash]; //sets the temporary node to the first node of the list
while (temp->next != 0)
{
//...
Right at the while loop is where I get the error "Access violation reading location 0xcccccd00"
I'm not sure why it can't access the table member, unless perhaps it is because these values have not been initialized or anything?
You're likely not doing two things. First make sure your hash table is properly initialized to contain all-NULL-pointers. Secondly, make sure any pointer retrieved from the hash table is valid prior to dereferencing it:
For the first issue:
hashTable::hashTable() : table()
{
}
Also, you want to make sure this thing cleans up properly
hashTable::~hashTable()
{
for (size_t i=0;i<sizeof(table)/sizeof(table[0]); ++i)
{
node *temp = table[i];
while (temp)
{
node *victim = temp;
temp = temp->next;
delete victim;
}
}
}
For the second issue:
void addNode(const char *name, const char *numb)
{
int hash = h(g(name)); //The hash of the key (name) used to check nodes
node *temp = table[hash]; //sets the temporary node to the first node of the list
if (temp)
{
// preexisting entry. walk that list looking for matching key.
node **pp = &temp->next;
while (temp)
{
if (0 == strcmp(temp->name, name))
break;
pp = &temp->next;
temp = temp->next;
}
// link to last node if not found in list
if (!temp)
*pp = new node(name, numb);
}
else
{ // no prior entry. create a new one and store it at table[hash].
table[hash] = new node(name, numb);
}
}
Note: the above code assumes the node class is implemented as
struct node
{
char name[40];
char numb[12];
node * next;
node(const char* name_, const char *numb_)
: next()
{
strncpy(name, name_, sizeof(name)/sizeof(name[0])-1);
name[ sizeof(name)/sizeof(name[0])-1 ] = 0;
strncpy(numb, numb_, sizeof(numb)/sizeof(numb[0])-1);
numb[ sizeof(numb)/sizeof(numb[0])-1 ] = 0;
}
};
Personally, I'd use std::string
If the value of hash is greater than (or equal to) 1000, temp will point to an invalid area.
And you are leaking the memory allocated by new node since you are overwriting the temp variable.
Related
I'm having trouble correctly initializing a dynamic array of nodes with nullptr.
HashMap::HashMap(int size)
{
this->sizeOfArray = size;
this->hashArray = new Node*[this->sizeOfArray];
for (int i = 0; i < this->sizeOfArray; i++)
{
hashArray[i] = nullptr;
}
}
this is what my 'hashArray' looks like in the header.
Node **hashArray;
the forloop completes all 500 loops but when I am looking at the data in the array, I can only see the first element before I get 'Unable to read memory'.
Here is an image of what I mean
https://ibb.co/d0GLw9
Here is what Node looks like
Node()
{
value = 0;
}
Node(std::string input)
{
key = input;
value = 1;
next = nullptr;
}
Node(std::string input, int count)
{
key = input;
this->value = count;
next = nullptr;
}
Node(std::string input, int count, Node *next)
{
key = input;
this->value = count;
this->next = next;
}
Node *next;
std::string key;
unsigned int value;
I suspect this problem is contributing to me not being able to add any new nodes to the hashArray later on.
All of your 500 Node pointers are NULL, however the type of the hashArray is Node **, that's why the debugger shows you only one element as if it's a pointer to one Node pointer. In other words, since your array is dynamic, the debugger doesn't know how many elements to show.
The error you're getting is in regard to viewing the contents of the first Node whose pointer is NULL, which is naturally can't be read.
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 currently learning some C++ for a course I am taking in school. I have basic understanding of lvalues and rvalues, but I am unable to determine why I am receiving a compiler error.
I am creating a singly linked list and need to be able to reverse it. As per my assignment I have two classes. The first is the node and just holds an int as well as a pointer.
class Node {
int data;
Node *next;
public:
//Constructor
Node(int d) {
data = d;
next = NULL;}
//Set to next Node
void SetNext(Node *nextOne) {
next = nextOne;}
//Returns data value
int Data(){return data;}
//Returns next Node
Node *Next() {return next;}
};
Then I have a linked list class that has a header pointer and then a number of functions for adding, printing etc. the list.
class LinkedList {
Node *head;
public:
//Constructor
LinkedList(){head = NULL;}
void AddNode(int d) {
//Create a new Node
Node *newNode = new Node(d);
//Create a temporary pointer
Node *temp = head;
//If there are already nodes in the list
if(temp != NULL) {
//Parse through to the end of the list
while(temp->Next() != NULL) {
temp = temp->Next();}
//Point the last Node in the list to the new Node
temp->SetNext(newNode);
}
//If adding as the first Node
else{
head = newNode;}
}
void PrintList() {
//Temporary pointer
Node *temp = head;
//If there are no nodes in the list
if(temp == NULL) {
std::cout << "The list is empty" << std::endl;}
//If there is only one node in the list
if(temp->Next() == NULL) {
std::cout << temp->Data() << std::endl;}
//Parse through the list and print
else {
do {
std::cout << temp->Data();
temp = temp->Next();
}
while(temp != NULL);
}
}
//Returns the number of nodes in the list
int CountList() {
//Temporary pointer
Node *temp = head;
//Counter variable
int counter = 0;
//If the list is empty
if(temp == NULL) {
return counter;}
//Parse through Nodes counting them
else {
do {counter++;
temp = temp->Next();
}
while(temp != NULL);
}
return counter;
}
//Reverses the list
Node *ReverseList() {
//Initially set to NULL then tracks the new head
Node *marker = NULL;
//Tracks the next one in the list
Node *nextOne;
//Sets the first Node to NULL and then sets the last Node to point to
//the first one and rotates through the list pointing the last to the
//first
while(head != NULL) {
nextOne = head->Next();
head->Next() = marker;
marker = head;
head = nextOne;
}
//Setting the head back to the start again
head = marker;
}
};
One of those functions is supposed to reverse the list. The line "head->Next() = marker;" in the ReverseList function is causing a "lvalue required as left operand of assignment" error when compiling.
Any insight as to why this is occurring and how I can correct the problem?
Thank you in advance!
The return from the call to Next() is an rvalue. As you are in a class function, you don't need to call the Next function to get at the private next pointer, you can just use it directly.
head->next = marker;
Your Next() function returns a pointer, and you then do this:
head->Next() = marker;
You're changing the pointer to marker and not what it's pointing at. To solve this you need to dereference that pointer:
*head->Next() = marker;
your signature for next is:
Node *Next() {return next;}
This makes a copy of next pointer at return and hence it is treated as r-value and not l-value.
One way of overcoming this would be to use a pointer-to-pointer:.
Node **Next() {return &next;}
And then use it as:
int main()
{
Node* marker=new Node(89);
Node* nod=new Node(9);
*(nod->Next())= marker;
cout<<(nod->next)->data<<endl;
cout << "Hello World" << endl;
return 0;
}
This makes it more complicated to use.
I am a beginner in C++ and need help in many things. Well, for the starters, I have been working on Linked List and not really getting why my header(the first pointer which points towards first node) keep on rotating. I am just pointing it towards first node plus my display node is just displaying last node, why is it so?. Please tell me where I am wrong. Thank you in advance
#include <iostream>
#include <conio.h>
using namespace std;
struct Node
{
int data;
Node *link;
};
Node* create_Node()
{
int no_of_nodes;
Node *header = new Node;
Node *ptr = new Node;
header = ptr;
cout << "Enter no of nodes:";
cin >> no_of_nodes;
cout << "Enter data:";
for(int n = 0; n < no_of_nodes; n++)
{
cin >> ptr->data;
Node *temp = new Node;
ptr->link = temp;
temp = ptr;
}
ptr->link = NULL;
return ptr;
}
void display_link_list(Node * list)
{
Node *temp = new Node;
temp = list;
while(temp != NULL)
{
if(temp->link != NULL)
{
cout << "List:" << list->data << endl;
temp = temp->link;
}
}
}
int main()
{
Node *n = new Node;
n = create_Node();
display_link_list(n);
getch();
return 0;
}
Welcome to C++. My advice here is to break the Linked list into two. First the Nodes and then a List struct.
struct Node
{
int data;
Node *next;
Node(int data) : data(data), next(NULL) {}
};
struct List {
Node* tail;
Node* head;
List() : head(NULL), tail(NULL) {}
void insert(int data) {
if(head==NULL) {
head = new Node(data);
tail = head;
} else {
tail->next = new Node(data);
tail = tail->next;
}
}
};
Now you can insert one element into the list at a time and use head to print the list from beginning to end.
Something basic that you need to understand:
When you do Node* p = new Node, you are setting variable p to point to the start address of a piece of memory, the size of which being equal to sizeof(Node).
Now, when you then do p = something else (which often appears in your code), you are essentially overriding the previous value of p with some other value. It is like doing:
int i = 5;
i = 6;
So your code does not do what you're expecting to begin with.
In addition to that, what's bad about overriding the first value with a second value in this case, is the fact that the first value is the address of a dynamically-allocated piece of memory, that you will need to delete at a later point in your program. And once you've used p to store a different value, you no longer "remember" that address, hence you cannot delete that piece of memory.
So you should start by fixing this problem in each of the following places:
Node *header = new Node; // Variable 'header' is assigned
header = ptr; // Variable 'header' is reassigned
Node *temp = new Node; // Variable 'temp' is assigned
temp = list; // Variable 'temp' is reassigned
Node *n = new Node; // Variable 'n' is assigned
n = create_Node(); // Variable 'n' is reassigned
I'm learning C++ language and I'm trying to write BST, but something goes wrong.
I try to add element to empty tree, root is NULL, but after adding element root is still NULL despite of the fact that addiing was successful (I saw it in debug mode, node is set as tmp). I have no idea why it happens.
struct Node
{
int data;
Node* left;
Node* right;
};
struct Tree
{
Node* root;
};
Tree createTree()
{
Tree tmp;
tmp.root = NULL;
return tmp;
}
void addToNode(Node* node, int value)
{
Node* tmp = new Node;
tmp->data = value;
tmp->left = NULL;
tmp->right = NULL;
if(node == NULL)
node = tmp;
else if(value >= node->data)
addToNode(node->right, value);
else
addToNode(node->left, value);
}
void add(Tree* tree, int value)
{
addToNode(tree->root, value);
}
int _tmain(int argc, _TCHAR* argv[])
{
Tree tree = createTree();
add(&tree, 10);
printf("%d", tree.root->data);
scanf("%*s");
return 0;
}
When you are passing your pointer into the function, you create a local version of the pointer. This local variable (node) does indeed point into the same memory that the outer pointer you were passing. However, any attempt to change this variable (not the memory it points to, but the pointer variable itself) will only change the local variable.
So your node points to the same memory location as your tree, but the node variable itself isn't equal to the tree variable, so your changes are not visible from the outer function.
It sounds complicated, sorry, but it's exacly the same thing as in this:
void foo( int a )
{
a++;
}
int main()
{
int var = 5;
foo( var );
std::cout << var;
}
Of course in this case the var will not change, it's the a that is being changed inside the function.
To fix the issue, pass a reference to the pointer instead of the pointer itself:
void addToNode(Node*& node, int value)
In the function addToNode when you assign to node, that assignment is not visible in the function calling addToNode because node is a local variable.
You should pass it as a reference instead:
void addToNode(Node*& node, int value)
{
...
}
Joachim already beat me to the answer, but I'll add this observation in anyway.
Your code leaks memory.
void addToNode(Node* node, int value)
{
Node* tmp = new Node;
tmp->data = value;
tmp->left = NULL;
tmp->right = NULL;
if(node == NULL)
node = tmp;
else if(value >= node->data)
addToNode(node->right, value);
else
addToNode(node->left, value);
}
Every call to addToNode creates a new Node instance in tmp, but if the parameter Node* node is not NULL, this new Node is not deleted and does not become accessible by the rest of the application.
There are a number of ways to avoid this. The simplest would be to check if node is NULL before creating a new instance.