I'm trying to execute the following code, everything is fine except one thing and that is tellerArray[2] is never initialized properly, it always creates problems for me, and I don't why. It creates problem for me: I came to know this fact when I debugged the code multiple times.
#include <iostream>
#include <stddef.h>
using namespace std;
class Customer {
public:
void setTime(int time) { this->_time = time; }
int getTime() { return this->_time; }
void setNextCustomer(Customer *next) { this->_next = next; }
Customer* getNextCustomer() { return this->_next;}
private:
int _time;
Customer *_next;
};
class Teller {
public:
Teller();
~Teller();
void addCustomer(Customer *customer);
int totalCustomers();
int totalTime();
private:
Customer *head;
Customer *tail;
};
Teller::Teller() {
this->head = NULL;
this->tail = NULL;
}
Teller::~Teller() {
delete head;
delete tail;
head = NULL;
tail = NULL;
}
void Teller::addCustomer(Customer *customer) {
customer->setNextCustomer(NULL);
if(head == NULL) {
head = customer;
} else {
tail->setNextCustomer(customer);
}
tail = customer;
}
int Teller::totalTime() {
int totalTime = 0;
Customer *tempCust = new Customer;
for(tempCust = head; tempCust != NULL; tempCust = tempCust->getNextCustomer()) {
totalTime += tempCust->getTime();
}
return totalTime;
}
int Teller::totalCustomers() {
int totalCustomers = 0;
Customer *tempCust = new Customer;
for(tempCust = head; tempCust != NULL; tempCust = tempCust->getNextCustomer()) {
totalCustomers += 1;
}
return totalCustomers;
}
int getLeast(int, int, int, int);
int getMax(int, int, int, int);
int main(int argc, const char*argv[]) {
Teller *tellerArray[4];
// creating four tellers ( counters )
Teller *tellerOne = new Teller();
Teller *tellerTwo = new Teller();
Teller *tellerThree = new Teller();
Teller *tellerFour = new Teller();
tellerArray[0] = tellerOne;
tellerArray[1] = tellerTwo;
tellerArray[2] = tellerThree;
tellerArray[3] = tellerFour;
char wannaBuyAnother = 'n';
int duration = 0, minTime = 0, maxTime = 0, index = 0;
do {
cout<<"Enter duration of your transaction: ";
cin>>duration;
Customer *customer = new Customer;
customer->setTime(duration);
minTime = getLeast( tellerOne->totalTime(),
tellerTwo->totalTime(),
tellerThree->totalTime(),
tellerFour->totalTime() );
for(index = 0; index < 4; index++) {
if( (tellerArray[index]->totalTime()) == minTime ) {
break;
}
}
tellerArray[index]->addCustomer(customer);
cout<<"You can stand in Queue "<<index + 1<<"\n";
cout<<"Do you want to buy another Ticket(Y/N)? ";
cin>>wannaBuyAnother;
} while ( wannaBuyAnother == 'y' || wannaBuyAnother == 'Y' );
cout<<"Number of Customers Deal By Every Teller\n";
for(index = 0; index < 4; index++) {
cout<<"T"<<index<< "= \t"<<tellerArray[index]->totalCustomers()<<"\n";
}
maxTime = getMax( tellerOne->totalTime(),
tellerTwo->totalTime(),
tellerThree->totalTime(),
tellerFour->totalTime() );
for(index = 0; index < 4; index++) {
if( (tellerArray[index]->totalTime()) == maxTime ) {
cout<<"TELLER "<<index+1<<" Deal Maximum Customers of the Day\n";
break;
}
}
return 0;
}
int getLeast(int first, int second, int third, int fourth) {
int min = first;
if( second < min ) {
min = second;
} else if ( third < min ) {
min = third;
} else if ( fourth < min ) {
min = fourth;
}
return min;
}
int getMax(int first, int second, int third, int fourth) {
int max = first;
if( second > max ) {
max = second;
} else if ( third > max ) {
max = third;
} else if ( fourth > max ) {
max = fourth;
}
return max;
}
Here is output when I debug my code.
tellerArray[0] Teller * 0xbffff308
tellerArray[1] Teller * 0x8048c64
tellerArray[2] Teller * 0x1
tellerArray[3] Teller * 0xffff
What my code is actually doing is using a linked list ( customer class ) to create a queue ( teller class ) and then based upon the time of each queue, it determines in which queue to put the next customer?
The initialisation looks fine. Those values are odd, but unless you have a specific debug build, you can't always rely on a reported pointer value being correct. However, it's possible they are being corrupted because of the following undefined behaviour in your program:
I notice that you never initialise the _next pointer on Customer to NULL, nor to you set it when you add it to the list. So your list tail always has an undefined _next pointer. This is very likely to give you problems.
You should create a default constructor on Customer and initialise _next to NULL.
One unrelated thing I will mention is that your getLeast and getMax functions do not work. Why don't you try this:
cout << getLeast(4, 3, 2, 1) << endl;
cout << getMax(1, 2, 3, 4) << endl;
The code is a bit bizarre, I don't see how the code matches the description of what it is supposed to do.
But bugs aren't hard to find, look at this code
int Teller::totalTime() {
int totalTime = 0;
Customer *tempCust = new Customer;
for(tempCust = head; tempCust != NULL; tempCust = tempCust->getNextCustomer()) {
totalTime += tempCust->getTime();
}
return totalTime;
}
At no point does your code set a value for tempCust->_next so tempCust->getNextCustomer() returns a garbage value and so from this point all bets are off, and your code could end up doing anything.
Frankly I can't see any logic to your code so I'm not sure what to do to fix it. At the very least I'd advise to to set _next to NULL in the Customer constructor.
class Customer {
public:
Customer() { this->_next = NULL; }
...
private:
...
Customer *_next;
};
Related
I need some help, I'm learing data structers and I got a task to write a programm based on array of pointers to structres which can add elements and do other task with array.I have next model of levels:
first level --> net of shops
second level --> shop
third level --> goods
I've written types for this
typedef struct
{
QString date;
QString prod_code;
QString name;
}goods;
typedef struct
{
QString address;
QString number;
void **sublevel;
}shop;
typedef struct
{
QString website;
QString name;
QString owner;
QString address;
void **sublevel;
}net;
Then I've created global variable void **Start which points to array of pointers:
// init list
void ** init_list()
{
void** p = new void*[SIZE_AR];
p = p+2;
((int*)p)[COUNT_POS] = 0;
((int*)p)[SIZE_POS] = SIZE_AR;
return p;
}
void ** Start = init_list();
COUNT_POS - index of elements where I store count of currently used elemnets
SIZE_POS - size of array allocated in dynamic memory
SIZE_AR - default size for array
But I get segmentation fault when I try to add to element to the last level
(for previous two ones works fine):
// expand array if it overfilled
void ExpandArrPtr (void **&ar, int &SizeAr, int Cnt)
{
void **arW;
arW = new void*[SizeAr+DELTA+2];
for (int K = SizeAr-1; K >= 0; K--) {
arW[K+2] = ar[K];
}
SizeAr = SizeAr + DELTA;
ar=ar-2;
delete []ar;
ar=arW+2;
((int*)ar)[COUNT_POS] = Cnt;
((int*)ar)[SIZE_POS] = SizeAr;
}
// binary search
void bin_search(void **start, QString key, int &pos, bool &find, Cmpmethod func)
{
int mid;
int high, low;
find = false;
if((int*)start[COUNT_POS] == 0)
{
pos = 0;
qDebug()<<"zero elem\n";
return;
}
low = 0;
high = ((int*)start)[COUNT_POS] - 1;
do
{
mid = (high + low) / 2;
int result = func(start[mid], key);
if(result == 0)
{
pos = mid;
find = true;
return;
}
else if(result == 1)
{
high = mid - 1;
}
else
{
low = mid + 1;
}
}while(low <= high);
pos = low;
}
// function for adding in any level
void addtosort(void **&start, void *pnew, int pos)
{
int count = ((int*)start)[COUNT_POS];
int size = ((int*)start)[SIZE_POS];
if(count == size)
{
ExpandArrPtr(start, size, count);
}
if(pos == count)
{
start[pos] = pnew;
}
else
{
for(int i = count;i >= pos;i--)
{
start[i+1] = start[i];
}
start[pos] = pnew;
}
count++;
((int*)start)[COUNT_POS] = count;
}
void add_goods(void **&Start, goods * Pnew)
{
int pos;
bool find;
bin_search((((shop*)(Start))->sublevel), Pnew->name, pos, find, compare_goods);
addtosort((((shop*)(Start))->sublevel), Pnew, pos);
}
// finding the item in second level to add
void find_place(QString key)
{
int pos;
bool find;
int count = ((int*)Start)[COUNT_POS];
for(int i = 0;i < count;i++)
{
bin_search(((net*)(Start)[i])->sublevel, key, pos, find, compare_shop);
if(find)
{
goods * Pnew = new goods;
Pnew->date = "foo"
Pnew->name = "bar"
add_goods(((net*)(Start)[pos])->sublevel, Pnew);
break;
}
}
}
What can cause such problem?
I got these two structs
struct CamelZombie{
int hp;
int attack;
CamelZombie *next;
};
struct list_of_cz{
CamelZombie *head;
};
I've made a function to create linked list with given value:
void createCamelZombie(list_of_cz *&pZ, int z_hp, int z_attack, int N){
pZ = new list_of_cz;
pZ->head->hp = z_hp;
pZ->head->attack = z_attack;
CamelZombie *temp1 = pZ->head;
CamelZombie *temp2 = NULL;
for (int i = 0; i < N - 1 ; i++){
temp2 = new CamelZombie;
temp2->hp = z_hp;
temp2->attack = z_attack;
temp1->next = temp2;
temp1 = temp2;
}
}
Then i put it in function main like this, but then the propram crashed, don't know why.
list_of_cz *pZ = NULL;
createCamelZombie(pZ, z_hp, z_attack, N);
while (pList->head != NULL && pZ != NULL){
atPlant(numPlant(pList) - 1, pList)->hp -= pZ->head->attack;
if (atPlant(numPlant(pList) - 1, pList)->hp <= 0) deletePlant(numPlant(pList) - 1, pList);
int count = 0;
CamelZombie *z_temp;
z_temp = pZ->head;
while (z_temp){
if (count == 0) z_temp->hp -= allPlantAttack(pList, numPlant(pList) - 1);
else z_temp->hp -= allLaserAttack(pList); //trouble right here
if (z_temp->hp <= 0) deleteCamelZombie(pZ, count);
z_temp = z_temp->next;
count++;
}
Seem like i miss something when writing void createCamelZombie() 'cause the compiler tells me that z_temp->hp don't have a value. Please help me!
Preferably use an existing container like std::vector or std::list
#include <iostream>
#include <string>
#include <list>
struct CamelZombie{
std::string name; //added for demonstration purposes
int hp;
int attack;
//pointer to next zombie not required
};
std::list<CamelZombie> createCamelZombie2(int z_hp, int z_attack, int N) {
std::list<CamelZombie> result;
for (int i = 0; i < N; i++){
CamelZombie newZombie;
newZombie.name = "Zombie"+std::to_string(i);
newZombie.hp = z_hp;
newZombie.attack = z_attack;
newZombie.next = NULL;
result.push_back(newZombie);
}
return result;
}
Use the code like this.
int main() {
std::list<CamelZombie> listOfZombies2 = createCamelZombie2(10,20,10);
for(std::list<CamelZombie>::iterator list_iter = listOfZombies2.begin();
list_iter != listOfZombies2.end(); list_iter++)
{
std::cout<<list_iter->name<<std::endl;
}
}
If you really want to use your own linked list try the code below.
A seperate struct (list_of_cz) for the list is not required. Each zombie links to the next zombie. So just keep a pointer to the first zombie.
createCamelZombie function returns a pointer to the first zombie in the list (no need to use the function parameter (list_of_cz *&pZ) to get the zombie list)
Too many underscores and Z makes the code hard to read.
If you use pointers you need to clean up memory yourself.
.
struct CamelZombie{
std::string name; //added for demonstration purposes
int hp;
int attack;
CamelZombie *next;
};
CamelZombie* createCamelZombie(int z_hp, int z_attack, int N){
CamelZombie *result = NULL;
CamelZombie *work = NULL; //keep track of the last node in the list
for (int i = 0; i < N; i++){
//create new zombie
CamelZombie *newZombie = new CamelZombie();
newZombie->name = "Zombie"+std::to_string(i);
newZombie->hp = z_hp;
newZombie->attack = z_attack;
newZombie->next = NULL;
if (result==NULL) {
result = newZombie;
work =result;
} else {
work->next = newZombie;
work = newZombie;
}
}
return result;
}
Example of how to use the code.
int main() {
CamelZombie *listOfZombies = createCamelZombie(10,20,10);
CamelZombie *work = listOfZombies;
// print zombie names to screen ---------
while (work!=NULL) {
std::cout << work->name << std::endl;
work = work->next;
}
And free memory.
work = listOfZombies;
while (work!=NULL) {
CamelZombie *temp =work->next;
delete work;
work = temp;
}
I'm trying to implement AVL Tree in C++, but I'm stuck with the insertion, I have changed some things but nothing seemed to effectively solve the problem. I used Xcode's Address Sanitizer and I'm getting that error after inserting a second element into the tree:
Thread 1: Use of deallocated memory detected.
==3822==ERROR: AddressSanitizer: heap-use-after-free on address.....
This is the implementation of the tree so far:
RoadTree.hpp
#ifndef RoadTree_hpp
#define RoadTree_hpp
#include "Road.hpp"
class RoadTree {
private:
struct TreeNode {
Road *key;
TreeNode *rightChild;
TreeNode *leftChild;
int height;
TreeNode() : key(NULL), rightChild(NULL), leftChild(NULL), height(0) { }
TreeNode(Road *r) : key(r), rightChild(NULL), leftChild(NULL), height(0) { }
};
TreeNode *root;
int numberOfRoads;
int GetHeight(TreeNode *n) const;
void SimpleRightRotation(TreeNode *&n);
void DoubleRightRotation(TreeNode *&n);
void SimpleLeftRotation(TreeNode *&n);
void DoubleLeftRotation(TreeNode *&n);
void Insert(TreeNode *&n, Road *r);
void ClearTree(TreeNode *&n);
void PreOrder(TreeNode *n) const;
public:
RoadTree();
~RoadTree();
void Insert(Road *r);
Road *FindRoad(string destination);
void ListRoads();
void ClearTree();
void PreOrder();
inline int RoadCount() {
return numberOfRoads;
}
};
#endif /* RoadTree_hpp */
RoadTree.cpp
#include "RoadTree.hpp"
RoadTree::RoadTree() : root(NULL), numberOfRoads(0) { }
RoadTree::~RoadTree() {
ClearTree(root);
}
void RoadTree::Insert(Road *r) {
Insert(root, r);
}
int RoadTree::GetHeight(TreeNode *n) const {
if (n == NULL)
return -1;
else
return n->height;
}
void RoadTree::SimpleRightRotation(TreeNode *&n) {
TreeNode *tempNode = n->rightChild;
n->rightChild = tempNode->leftChild;
tempNode->leftChild = n;
n->height = 1 + max(GetHeight(n->leftChild), GetHeight(n->rightChild));
n = tempNode;
tempNode->height = 1 + max(n->height, GetHeight(tempNode->rightChild));
}
void RoadTree::DoubleRightRotation(TreeNode *&n) {
SimpleLeftRotation(n->rightChild);
SimpleRightRotation(n);
}
void RoadTree::SimpleLeftRotation(TreeNode *&n) {
TreeNode *tempNode = n->leftChild;
n->leftChild = tempNode->rightChild;
tempNode->rightChild = n;
n->height = 1 + max(GetHeight(n->leftChild), GetHeight(n->rightChild));
n = tempNode;
tempNode->height = 1 + max(n->height, GetHeight(n->leftChild));
}
void RoadTree::DoubleLeftRotation(TreeNode *&n) {
SimpleRightRotation(n->leftChild);
SimpleLeftRotation(n);
}
void RoadTree::ClearTree(TreeNode *&n) {
if (n != NULL) {
ClearTree(n->rightChild);
ClearTree(n->leftChild);
delete n;
}
n = NULL;
}
void RoadTree::Insert(TreeNode *&n, Road *r) {
if (n == NULL) {
n = new TreeNode(r);
numberOfRoads++;
} else {
if (r->GetDestination() < n->key->GetDestination()) {
Insert(n->leftChild, r);
if ((GetHeight(n->leftChild) - GetHeight(n->rightChild)) == 2) {
if (r->GetDestination() < n->leftChild->key->GetDestination())
SimpleLeftRotation(n);
else
DoubleLeftRotation(n);
}
} else if (r->GetDestination() > n->key->GetDestination()) {
Insert(n->rightChild, r);
if ((GetHeight(n->rightChild) - GetHeight(n->leftChild)) == 2) {
if (r->GetDestination() > n->rightChild->key->GetDestination())
SimpleRightRotation(n);
else
DoubleRightRotation(n);
}
} else if (r->GetDestination() == n->key->GetDestination())
n->key->SetRoad(r->GetDestination(), r->GetCost(), r->GetInfo());
}
n->height = 1 + max(GetHeight(n->leftChild), GetHeight(n->rightChild));
}
Road *RoadTree::FindRoad(string destination) {
TreeNode *n = root;
while (n != NULL) {
string current = n->key->GetDestination();
if (destination < current)
n = n->leftChild;
else if (destination > current)
n = n->rightChild;
else if (destination == current)
return n->key;
}
return NULL;
}
void RoadTree::PreOrder(TreeNode *n) const {
if (n != NULL) {
cout << " " << n->key->GetDestination() << " ";
PreOrder(n->leftChild);
PreOrder(n->rightChild);
}
}
void RoadTree::PreOrder() {
PreOrder(root);
}
void RoadTree::ListRoads() {
}
void RoadTree::ClearTree() {
ClearTree(root);
}
And this is the implementation of Road:
Road.hpp
#ifndef Road_hpp
#define Road_hpp
#include <iostream>
using namespace std;
class Road {
private:
string destination;
int cost;
string info;
public:
Road();
Road(string destination, int cost, string info);
inline string GetDestination() {
return destination;
}
inline int GetCost() {
return cost;
}
inline string GetInfo() {
return info;
}
};
#endif /* Road_hpp */
Road.cpp
#include "Road.hpp"
Road::Road() {
destination = "";
cost = 0;
info = "";
}
Road::Road(string destination, int cost, string info) {
this->destination = destination;
this->cost = cost;
this->info = info;
}
The only way I can insert more than 1 element is leaving the destructor blank, then no error shows, so I don't know what's causing it to fail. The error is showing up at the Insertion method, in the line that compares the elements in order to advance in the tree.
Update: Since this is part of a bigger project, I'm almost 100% sure that the problem isn't from the tree's implementation (I put the tree and Road class in a separate project and everything worked as intended). The full project has a class called Place, it has a name and info, as well as an AVL Tree for each place (where I store the place's roads). Those places are stored in a Hash Table (that I have implemented myself).
This is the implementation of the Place class:
Place.hpp
#ifndef Place_hpp
#define Place_hpp
#include <iostream>
#include "Road.hpp"
#include "RoadTree.hpp"
using namespace std;
class Place {
private:
string name;
string info;
RoadTree adjacentRoads;
public:
Place();
Place(string name, string info);
void InsertRoad(Road *r);
Road *FindRoad(string destination);
void ListRoads();
inline string GetName() {
return name;
}
inline string GetInfo() {
return info;
}
inline void SetPlace(string newName, string newInfo) {
name = newName;
info = newInfo;
}
inline void Write() {
cout << name << endl;
cout << "Info: " << info << endl;
}
};
Place.cpp
#include "Place.hpp"
Place::Place() {
name = "";
info = "";
}
Place::Place(string name, string info) {
this->name = name;
this->info = info;
}
void Place::InsertRoad(Road *r) {
adjacentRoads.Insert(r);
}
Road *Place::FindRoad(string destination) {
return adjacentRoads.FindRoad(destination);
}
void Place::ListRoads() {
adjacentRoads.ListRoads();
}
This is how I get a pointer from the Hash Table (if the full code is needed tell me):
Place *HashTable::Find(string key) {
unsigned long hashedKey = HashFunction(key);
list<Place>::iterator current;
for (current = table[hashedKey].begin(); current != table[hashedKey].end(); current++) {
Place currentPlace = *current;
if (currentPlace.GetName() == key)
return &*current;
}
return NULL;
}
And this is an example of a main that gives me the Thread 1: Use of deallocated memory detected. error
int main(int argc, const char * argv[]) {
//Declare a HashTable to store Places
HashTable map;
//Declare some places
Place p1("Murcia", "10");
Place p2("Lorca", "11");
Place p3("Cartagena", "12");
Place p4("Zaragoza", "13");
Place p5("Madrid", "14");
Place p6("Galicia", "15");
//Insert those places into the HashTable
map.Insert(p1);
map.Insert(p2);
map.Insert(p3);
map.Insert(p4);
map.Insert(p5);
map.Insert(p6);
//Declare some roads
Road *r1 = new Road(p2.GetName(), 20, "asdgasdg");
Road *r2 = new Road(p3.GetName(), 61, "asdgsw2");
//Get a pointer of a place from the HashTable to insert roads in it
Place *p1f = map.Find(p1.GetName());
//Check if it's not null, if it's not then insert the first road,
//get a pointer of it and print the name
if (p1f != NULL) {
p1f->InsertRoad(r1);
Road *r1f = p1f->FindRoad(p2.GetName());
cout << r1f->GetDestination() << endl;
}
//Get pointer of a place again (each time you want to insert a road
//in a place you must get it's pointer from the HashTable
Place *p2f = map.Find(p1.GetName());
//Checks again and insert second road, then throws error after that
if (p2f != NULL) {
p2f->InsertRoad(r2);
Road *r2f = p1f->FindRoad(p3.GetName());
cout << r2f->GetDestination() << endl;
}
return 0;
Update 2: Added HashTable implementation
HashTable.hpp
#ifndef HashTable_hpp
#define HashTable_hpp
#include "Place.hpp"
#include <list>
class HashTable {
private:
list<Place> *table;
int numberOfEntries;
int currentTableSize;
float maxLoadFactor;
unsigned int HashFunction(string key);
bool LoadFactorExceeded();
void ResizeTable();
bool IsPrime(int number);
int NextPrime(int number);
public:
HashTable();
~HashTable();
void Insert(Place p);
Place *Find(string key);
void EmptyTable();
void ListPlaces();
inline int Count() {
return numberOfEntries;
}
};
#endif /* HashTable_hpp */
HashTable.cpp
#include "HashTable.hpp"
#include <algorithm>
const int START_SIZE = 101;
HashTable::HashTable() {
table = new list<Place>[START_SIZE];
numberOfEntries = 0;
maxLoadFactor = 2.0f;
currentTableSize = START_SIZE;
for (int i = 0; i < START_SIZE; i++) {
table[i].clear();
}
}
HashTable::~HashTable() {
delete [] table;
}
unsigned int HashTable::HashFunction(string key) {
unsigned long hashValue = 0;
for (int i = 0; i < key.length(); i++)
hashValue = 47 * hashValue + key[i];
return (hashValue % currentTableSize);
}
bool HashTable::LoadFactorExceeded() {
float currentLoadFactor = numberOfEntries / currentTableSize;
if (currentLoadFactor > maxLoadFactor)
return true;
else
return false;
}
void HashTable::ResizeTable() {
list<Place> *oldTable = table;
int oldTableSize = currentTableSize;
currentTableSize *= 2;
currentTableSize = NextPrime(currentTableSize);
table = new list<Place>[currentTableSize];
for (int i = 0; i < currentTableSize; i++)
table[i].clear();
numberOfEntries = 0;
for (int i = 0; i < oldTableSize; i++) {
list<Place>::iterator current;
for (current = oldTable[i].begin(); current != oldTable[i].end(); current++)
Insert(*current);
}
delete [] oldTable;
}
bool HashTable::IsPrime(int number) {
if (number % 2 == 0 || number % 3 == 0)
return false;
int divisor = 6;
while (divisor * divisor - 2 * divisor + 1 <= number) {
if (number % (divisor - 1) == 0)
return false;
if (number % (divisor + 1) == 0)
return false;
divisor += 6;
}
return true;
}
int HashTable::NextPrime(int number) {
while (!IsPrime(++number)) {}
return number;
}
void HashTable::Insert(Place p) {
unsigned long hashedKey = HashFunction(p.GetName());
list<Place>::iterator current = table[hashedKey].begin();
if (!table[hashedKey].empty()) {
for (current = table[hashedKey].begin(); current != table[hashedKey].end(); current++) {
Place ¤tPlace = *current;
if (currentPlace.GetName() == p.GetName()) {
currentPlace.SetPlace(p.GetName(), p.GetInfo());
break;
} else if (current == --table[hashedKey].end()) {
table[hashedKey].push_back(p);
numberOfEntries++;
}
}
} else {
table[hashedKey].push_back(p);
numberOfEntries++;
}
if (LoadFactorExceeded())
ResizeTable();
}
Place *HashTable::Find(string key) {
unsigned long hashedKey = HashFunction(key);
list<Place>::iterator current;
for (current = table[hashedKey].begin(); current != table[hashedKey].end(); current++) {
Place currentPlace = *current;
if (currentPlace.GetName() == key)
return &*current;
}
return NULL;
}
void HashTable::EmptyTable() {
for (int i = 0; i < currentTableSize; i++) {
table[i].clear();
}
table = new list<Place>[START_SIZE];
numberOfEntries = 0;
currentTableSize = START_SIZE;
}
void HashTable::ListPlaces() {
list<string> places;
for (int i = 0; i < currentTableSize; i++) {
list<Place>::iterator current;
for (current = table[i].begin(); current != table[i].end(); current++)
places.push_back(current->GetName());
}
places.sort();
for (list<string>::iterator current = places.begin(); current != places.end(); current++)
cout << *current << endl;
cout << "Total: " << numberOfEntries << " lugares" << endl;
}
What could be causing the problem?
I'm not sure if this is it, but I noticed something: it looks like a linked list, and your recursive ClearTree function will attempt to free items repeatedly:
void RoadTree::ClearTree(TreeNode *&n) {
if (n != NULL) {
ClearTree(n->rightChild);
ClearTree(n->leftChild);
delete n;
}
n = NULL;
}
Assuming there are 2 elements in the list, and we call it with the first element:
ClearTree( firstElement );
It will then first
ClearTree(n->rightChild); // 2nd element
which in turn will first call
ClearTree(n->rightChild); // non-existing 3rd element: NOP
and proceed with
ClearTree(n->leftChild); // first element again
Maybe if you didn't get the error, this would recurse until you get a stack overflow?
You could simply remove the call to ClearTree(n->leftChild) to fix it; the function will recurse across the rightChild until it reaches the end, then delete the nodes from last to first when it backtracks.
Perhaps it's better to just iterate over the list: (untested, hope this works)
TreeNode * cur = n;
while ( cur != NULL )
TreeNode * next = n->rightChild;
delete cur;
cur = next;
}
n = NULL;
UPDATE
I've found the problem. Here's my debug output:
> g++ -O0 -g *cpp && gdb ./a.out
(gdb) r
Starting program: /home/kenney/roadtree/a.out
= INITIALIZING PLACES =
--> RoadTree[0x7fffffffe1a0] CONSTRUCTOR root: 0
--> RoadTree[0x7fffffffe1c0] CONSTRUCTOR root: 0
--> RoadTree[0x7fffffffe1e0] CONSTRUCTOR root: 0
--> RoadTree[0x7fffffffe200] CONSTRUCTOR root: 0
--> RoadTree[0x7fffffffe220] CONSTRUCTOR root: 0
--> RoadTree[0x7fffffffe240] CONSTRUCTOR root: 0
= INSERTING PLACES =
<-- RoadTree[0x7fffffffe340] DESTRUCTOR! root: 0
<-- RoadTree[0x7fffffffe360] DESTRUCTOR! root: 0
<-- RoadTree[0x7fffffffe380] DESTRUCTOR! root: 0
<-- RoadTree[0x7fffffffe3a0] DESTRUCTOR! root: 0
<-- RoadTree[0x7fffffffe3c0] DESTRUCTOR! root: 0
<-- RoadTree[0x7fffffffe3e0] DESTRUCTOR! root: 0
= CREATING ROADS =
These are the p1..p6 and the map.Insert(p1..p6). There's already a hint that something is wrong. Next this code is run:
cout << "= p1 =\n";
Place *p1f = map.Find(p1.GetName());
cout << "found " << p1f << " for " << p1.GetName() << "\n";
Producing this debug output:
= p1 =
<-- RoadTree[0x7fffffffe110] DESTRUCTOR! root: 0
found 0x6098f0 for Murcia
Then,
if (p1f != NULL) {
p1f->InsertRoad(r1);
Road *r1f = p1f->FindRoad(p2.GetName());
cout << r1f->GetDestination() << endl;
}
outputting this debug from RoadTree::Insert, indicating that the first if statement's 'then' is executed, assigning a new TreeNode to n:
n null, allocating.
--> TreeNode[0x609ad0] CONSTRUCTOR
allocated TreeNode 0x609ad0 key: 0x609a60 dest: Lorca
Lorca
So far so good, now the same again for p2. First the output of map.Find:
= p2 =
FINDING Murcia
<-- RoadTree[0x7fffffffe110] DESTRUCTOR! root: 0x609ad0
!!! RoadTree::ClearTree:: delete 0x609a60
<-- TreeNode[0x609ad0] DESTRUCTOR
found 0x6098f0 for Murcia
Next we continue to p2f->InsertRoad(r2); which is basically Place.adjacentroads.Insert aka RoadTree.insert:
n not null: 0x609ad0 key: 0x609af0
Note the address of n: this is the deleted TreeNode.
Here, the 'else' of the 'if' in RoadTree::Insert is taken since n != NULL:
if (r->GetDestination() < n->key->GetDestination()) {
is executed, causing:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7b9126b in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
(gdb) bt
#0 0x00007ffff7b9126b in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1 0x00000000004046b3 in Road::GetDestination (this=0x609af0) at Road.hpp:20
#2 0x0000000000405121 in RoadTree::Insert (this=0x609900, n=#0x609900: 0x609ad0, r=0x609ab0) at RoadTree.cpp:75
#3 0x0000000000404c0d in RoadTree::Insert (this=0x609900, r=0x609ab0) at RoadTree.cpp:15
#4 0x0000000000404845 in Place::InsertRoad (this=0x6098f0, r=0x609ab0) at Place.cpp:14
#5 0x000000000040401d in main (argc=1, argv=0x7fffffffe5f8) at main.cpp:63
(gdb)
The fault is apparent in the n->key->GetDestination() which attempts to return a copy of a string that is already deleted, causing a segfault because some pointers are already overwritten.
The problem is in HashTable::Find, which does this:
Place currentPlace = *current;
if (currentPlace.GetName() == key)
return &*current;
which constructs a Place copy on the stack that gets destroyed when the method returns. The private fields of Place also get destroyed, including the string name, which was attempted to be returned by Road::GetDestination().
Replacing it with this with this solves it:
if (current->GetName() == key)
return &*current;
I'm not sure this is the only fix needed, but it's a step.
Below is my implementation to keep track of the size of each tree in the disjoint set forest.
Can you please tell me what is wrong with it ? I am trying to solve UVa problem https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3638
#include <iostream>
#include <cstdio>
#include <unordered_map>
using namespace std;
class Node {
public :
int id;
Node *parent;
unsigned long long rank;
Node(int id) {
this->id = id;
// this->data = data;
this->rank =1; //size here
this->parent = this;
}
friend class DisjointSet;
};
class DisjointSet {
unordered_map<int,Node*> nodesMap;
Node *find_set_helper(Node *aNode) {
if (aNode == aNode->parent) {
return aNode->parent;
}
return find_set_helper(aNode->parent);
}
void link(Node *xNode,Node *yNode) {
if( xNode->rank > yNode->rank) {
yNode->parent = xNode;
xNode->rank += yNode->rank;
}
// else if(xNode-> rank < yNode->rank){
// xNode->parent = yNode;
// yNode->rank += xNode->rank;
// }
else {
xNode->parent = yNode;
yNode->rank += xNode->rank;
}
}
public:
DisjointSet() {
}
void AddElements(int sz) {
for(int i=0;i<sz;i++)
this->make_set(i);
}
void make_set(int id) {
Node *aNode = new Node(id);
this->nodesMap.insert(make_pair(id,aNode));
}
void Union(int xId, int yId) {
Node *xNode = find_set(xId);
Node *yNode = find_set(yId);
if(xNode && yNode)
link(xNode,yNode);
}
Node* find_set(int id) {
unordered_map<int,Node*> :: iterator itr = this->nodesMap.find(id);
if(itr == this->nodesMap.end())
return NULL;
return this->find_set_helper(itr->second);
}
~DisjointSet(){
unordered_map<int,Node*>::iterator itr;
for(itr = nodesMap.begin(); itr != nodesMap.end(); itr++) {
delete (itr->second);
}
}
};
int main() {
int n,m,k,first,cur;
//freopen("in.in","r",stdin);
scanf("%d %d",&n,&m);
while(n != 0 || m != 0) {
DisjointSet *ds = new DisjointSet();
ds->AddElements(n); // 0 to n-1
//printf("\n n = %d m = %d",n,m);
for(int i=1;i<=m;i++) {
scanf("%d",&k);
//printf("\nk=%d",k);
if ( k > 0 ) {
scanf("%d",&first);
for(int j=2;j<=k;j++) {
scanf("%d",&cur);
ds->Union(first,cur);
}
}
}
Node *zeroSet = ds->find_set(0);
// unsigned long long count = ds->getCount(zeroSet->id);
printf("%llu\n",zeroSet->rank);
delete ds;
scanf("%d %d",&n,&m);
}
return 0;
}
The link function in the above code does the job of updating the tree size.
The solution to the problem is to find the set which elements 0 belongs to and get the size of the representative element of the set.
But I am getting wrong answer with this code.
Can you please help me
In your Union function, check if both nodes are already in the same set.
if(xNode && yNode && xNode != yNode)
link(xNode,yNode);
As an exercise (largely an exercise in trying to write something using pointers), I'm writing a cache simulation, specifically of the pseudo least recently used system from the old 486. I'm getting an "Access violation reading location" error on the line:
int min = treeArray[set]->root->findPLRU();
Initially the treeArray seems to be initialised properly (if I pause the program at the start and take a look, it's all as should be), but when the programme breaks and I delve in to examine things the root of the tree in question isn't defined.
I feel it's quite probable that I'm making some sort of very elementary pointer mistake, which is causing the pointer to the node to be "lost" somewhere, but I've no clue what it might be. Is there something in particular I need to do to "hold on" to a pointer value?
#include "stdafx.h"
#include "stdlib.h"
#include <conio.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <io.h>
#include "main.h"
//char fn[80]; // trace filename
int tf; // trace file
trace buf[BUFSZ / sizeof(trace)]; // buffer SIZE
int LRUHits = 0;
int pLRUHits = 0;
int randomHits = 0;
int height;
int cachelinenumber;
//log2 helper function
int log2(int n)
{
int i = 0;
while (n)
{
n = n >> 1;
i++;
}
return i - 1;
}
class CacheLine{
public:
int tag;
int access;
CacheLine();
};
class Cache;
class Node{
public:
bool goRight;
Node* left;
Node* right;
int leftCacheLine;
int rightCacheLine;
Node(int depth) // constructor
{
goRight = false;
if (depth < height - 1)
{
left = new Node(depth + 1);
right = new Node(depth + 1);
leftCacheLine = -1;
rightCacheLine = -1;
}
else
{
leftCacheLine = cachelinenumber;
cachelinenumber++;
rightCacheLine = cachelinenumber;
cachelinenumber++;
}
//printf("Depth: %d, Height: %d, Left: %d, Right: %d\n", depth, height, leftCacheLine, rightCacheLine);
}
~Node()
{
delete left;
delete right;
}
int findPLRU()
{
if (leftCacheLine < 0 || rightCacheLine < 0)
{
if (goRight)
{
goRight = false;
return right->findPLRU();
}
else
{
goRight = true;
return left->findPLRU();
}
}
else
{
if (goRight)
{
goRight = false;
return rightCacheLine;
}
else
{
goRight = true;
return leftCacheLine;
}
}
}
};
class Tree{
public:
Node* root;
Tree()
{
root = new Node(0);
}
~Tree()
{
delete root;
}
};
//cache class
class Cache
{
public:
CacheLine *cache;
int l, k, n, replacementPolicy;
int log2l, log2n;
int access;
Tree** treeArray;
//constructor
Cache(int ll, int kk, int nn, int _replacementPolicy)
{
l = ll;
k = kk;
n = nn;
replacementPolicy = _replacementPolicy;
log2l = log2(l);
log2n = log2(n);
cache = (CacheLine*)malloc(sizeof(CacheLine)*k*n);
for (int i = 0; i < k*n; i++)
{
cache[i].tag = 0x80000000;
cache[i].access = 0;
}
if (replacementPolicy == 1)
{
cachelinenumber = 0;
treeArray = new Tree*[n];
for (int i = 0; i < n; i++)
{
treeArray[i] = new Tree();
}
}
access = -1;
}
//destructor
~Cache()
{
free(cache);
}
//test for hit
void hit(int a)
{
access++;
int set = (a >> log2l) & (n - 1);
int tag = a >> (log2n + log2l);
CacheLine* c = &cache[set*k];
for (int i = 0; i < k; i++)
{
if (c[i].tag == tag)
{
c[i].access = access;
if (replacementPolicy == 0)
LRUHits++;
else if (replacementPolicy == 1)
pLRUHits++;
else if (replacementPolicy == 2)
randomHits++;
break;
}
}
if (replacementPolicy == 0) //LRU
{
int min = 0;
int minv = c[0].access;
for (int i = 1; i < k; i++)
{
if (c[i].access < minv)
{
minv = c[i].access;
min = i;
}
}
c[min].tag = tag;
c[min].access = access;
}
else if(replacementPolicy == 1) // pseudoLRU
{
int min = treeArray[set]->root->findPLRU();
c[min].tag = tag;
c[min].access = access;
}
else // random
{
srand(clock());
int randomNumber = rand()%k;
c[randomNumber].tag = tag;
c[randomNumber].access = access;
}
return;
}
};
void analyse (int l, int k, int n)
{
height = log2(k) + 1;
char fn[] = "ico0.trace";
if ((tf = open(fn, _O_RDONLY | _O_BINARY )) == -1) {
printf("unable to open file %s\n", fn);
exit(0);
}
LRUHits = 0;
pLRUHits = 0;
randomHits = 0;
Cache *cache0 = new Cache(l, k, n, 0); // LRU
Cache *cache1 = new Cache(l, k, n, 1); // pseudoLRU
Cache *cache2 = new Cache(l, k, n, 2); // random
int bytes, word0, a, type, burstcount;
int hits = 0;
int tcount = 0;
while (bytes = read(tf, buf, sizeof(buf)))
{
for (int i = 0; i < bytes / (int) sizeof(trace); i++, tcount++)
{
word0 = buf[i].word0;
a = (word0 & ADDRESSMASK) << 2;
type = (word0 >> TYPESHIFT) & TYPEMASK;
burstcount = ((word0 >> BURSTSHIFT) & BURSTMASK) + 1;
cache0->hit(a);
cache1->hit(a);
cache2->hit(a);
}
}
printf("Hits: %d Total: %d\n", LRUHits, tcount);
printf("Hits: %d Total: %d\n", pLRUHits, tcount);
printf("Hits: %d Total: %d\n\n\n", randomHits, tcount);
delete cache0;
delete cache1;
delete cache2;
}
int _tmain(int argc, _TCHAR* argv[])
{
//analyse(16, 1, 8);
analyse(16, 2, 512);
//analyse(16, 4, 256);
//analyse(16, 8, 128);
//analyse(16, 1024, 1);
_getch();
return 0;
}
Your question hasn't yet been pounced upon, probably because your code still doesn't compile since you've not provided main.h.
And even then it would annoy most folks trying to help you because you make no mention of the ico0.trace file that is required to prevent the code from immediately exiting.
You say int min = treeArray[set]->root->findPLRU(); access violates.
1) the value of set can never exceed the size n of your treeArray since you & n-1 the range of input values.
2) since your ~Tree() destructor is never called there will always be a treeArray[set]->root
3) since you *always create new left & right nodes whenever leftCacheLine = -1 or rightCacheLine = -1 it cannot be due to recursive findPLRUs
So, the pointer to the node is not being "lost" somewhere; it is being stomped on.
Try replacing:
int min = treeArray[set]->root->findPLRU();
c[min].tag = tag;
c[min].access = access;
with:
int min = treeArray[set]->root->findPLRU();
if (min >= k*n)
{
printf("ook\n");
}
else
{
c[min].tag = tag;
c[min].access = access;
}
and I think you will discover what's doing the stomping. ;)