Error when deallocating double pointer in c++ - c++

I am having to build a Cuckoo Hash table. When deallocating my "full" hash tables so that I can resize them and rehash all of my values (from an external file of ints), I get the error:
*** glibc detected *** ./a.out: free(): invalid pointer: 0x09c83c7c ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x75002)[0x6b1002]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZdlPv+0x18)[0x918fa8]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZdaPv+0x18)[0x919008]
./a.out[0x8049678]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0x655533]
./a.out[0x8048b11]
I am not all that familiar with double pointers but the code was working fine with them untill I tried to deallocate, which I do as follows:
for(int j = 0; j < currentSize; j++)
{
if(HT1[j] != NULL)
{
delete [] HT1[j];
}
if(HT2[j] != NULL)
{
delete [] HT2[j];
}
}
delete [] HT1;
delete [] HT2;
I have a line in the code (cout.ignore()) to pause everytime the program rehashes so I can see whats going on every time it does so. Hit enter to continue the code.
Thanks for any help!
#include <iostream>//cin and cout
#include <fstream>//file stream
using namespace std;
/***********************************
/Function:
/Arguments:
/Return:
***********************************/
class Value
{
public:
Value();
Value(int newValue);
~Value();
int value;
bool h1;
bool h2;
};
/***********************************
/Function:Default constructor for Value class
/Arguments:
/Return:
***********************************/
Value::Value()
{
value = 0;
h1 = 0;
h2 = 0;
}
/***********************************
/Function:Overloaded constructor for Value class
/Arguments:
/Return:
***********************************/
Value::Value(int newValue)
{
value = newValue;
h1 = 0;
h2 = 0;
}
Value::~Value(){};
/***********************************
/Function: Print the hash tables
/Arguments: Value HT1[]
Value HT2[]
int tableSize
/Return:None
***********************************/
void printArrays(Value **table1, Value **table2, int tableSize)
{
//print out hash table 1 and 2
cout << "Hash Table 1 Hash Table 2" << endl;
cout << "------------ ------------" << endl;
for(int i = 0; i < tableSize; i++)
{
cout.width(2);
cout << right << i << ". ";
if(table1[i] == NULL)
{
std::cout.width(8);
cout << std::left << '0';
}
else
{
std::cout.width(8);
cout << std::left << table1[i]->value;
}
cout << " ";
cout.width(2);
cout << right << i << ". ";
if(table2[i] == NULL)
{
cout << "0" << endl;
}
else
{
cout << table2[i]->value << endl;
}
}
cout << endl;
}
/***********************************
/Function:
/Arguments:
/Return:
***********************************/
int hash1(int value, int currentSize)
{
return value % currentSize;
}
/***********************************
/Function:
/Arguments:
/Return:
***********************************/
int hash2(int value, int currentSize)
{
return (value/currentSize)%currentSize;
}
/***********************************
/Function:Finds the smallest prime number
greater than 2* tableSize
/Arguments: int tableSize
/Return: prime int
***********************************/
int findPrime(int size)
{
int rehashSize = (size) * 2 + 1;
bool prime = 1;
for(int i = 2; i < rehashSize/2; i++)
{
if(rehashSize % i == 0)
{
rehashSize++;
i = 2;
}
}
return rehashSize;
}
int main()
{
int next;//Stores value from file stream
int const tableSize = 11;//Size of the hash table
int currentSize = tableSize;//Stores the current HT size
int rehashSize;//Holds the size of a rehashed table
int hash; //Holds the hash value
int hashTable = 1;//Governor of the switch statement
Value **HT1 = new Value* [tableSize];//Hash Table 1
Value **HT2 = new Value* [tableSize];//Hash Table 2
Value *current;//Stores the value currently being hashed
Value *temp;//Temporarily holds a Value object if booted from its hash table
ifstream ifs;//file steam object
ifs.open("raw_int.txt");//open file stream to file
while(!(ifs.eof()))
{
for(int i = 0; i < currentSize; i++)
{
HT1[i] = NULL;
HT2[i] = NULL;
}
printArrays(HT1, HT2, currentSize);
ifs >> next;
current = new Value(next);
while(!(current->h1 == 1 && current->h2 == 1))
{
cout << "BEFORE - next / hashTable / current / h1 / h2 :: " << next << " " << hashTable << " " << current->value << " " <<
current->h1 << " " << current->h2 << endl;
cout << "ARRAY BEFORE" << endl;
printArrays(HT1, HT2, currentSize);
switch(hashTable)
{
case 1:
cout << "IN CASE 1\n\n";
hash = hash1(current->value, currentSize);
cout << "HASH 1: " << hash << endl;
if(HT1[hash] == NULL)
{
HT1[hash] = current;
HT1[hash]->h1 = 1;
ifs >> next;
current = new Value(next);
}
else
{
temp = HT1[hash];
HT1[hash] = current;
HT1[hash]->h1 = 1;
current = temp;
hashTable = 2;
}
break;
case 2:
cout << "IN CASE 2\n\n";
hash = hash2(current->value, currentSize);
cout << "HASH 2: " << hash << endl;
if(HT2[hash] == NULL)
{
HT2[hash] = current;
HT2[hash]->h2 = 1;
ifs >> next;
current = new Value(next);
hashTable = 1;
}
else
{
temp = HT2[hash];
HT2[hash] = current;
HT2[hash]->h2 = 1;
current = temp;
hashTable = 1;
}
break;
}
cout << "AFTER - next / hashTable / current / h1 / h2 :: " << next << " " << hashTable << " " << current->value << " " <<
current->h1 << " " << current->h2 << endl;
cout << "ARRAY AFTER: " << endl;
printArrays(HT1, HT2, currentSize);
}
rehashSize = findPrime(currentSize);
for(int j = 0; j < currentSize; j++)
{
if(HT1[j] != NULL)
{
delete [] HT1[j];
}
if(HT2[j] != NULL)
{
delete [] HT2[j];
}
}
delete [] HT1;
delete [] HT2;
currentSize = rehashSize;
Value **HT1 = new Value* [currentSize];
Value **HT2 = new Value* [currentSize];
//printArrays(HT1, HT2, currentSize);
ifs.seekg(0, ifs.beg);
cout << "\n\n\n\n\n";
cout << "---------------------------------------REHASHED:NEW SIZE / CURRENT: " << currentSize << " " << current->value << " ----------------------------------------------" << endl;
cout << "\n\n\n\n\n";
cin.ignore();
}
printArrays(HT1, HT2, currentSize);
return 0;
}

I think one of the the issues might be in this segment:
delete [] HT1;
delete [] HT2;
currentSize = rehashSize;
Value **HT1 = new Value* [currentSize];
Value **HT2 = new Value* [currentSize];
You are (always) deleting the HT1 and HT2 allocated at the beginning of main, but the new then assigns to newly created local variables (but on next iteration the original arrays get deleted again, not the new ones).
Try to remove the Value ** when doing new (to assign to the existing variables):
delete [] HT1;
delete [] HT2;
currentSize = rehashSize;
HT1 = new Value* [currentSize];
HT2 = new Value* [currentSize];
which could fix the deletion of the same pointer multiple times.
(and the same also applies for the for loop, where you are again deleting the items multiple times in next iterations)
Also, if you are rehashing, normally you would allocate the new tables before getting rid of the old ones and putting the old items to the new tables first.
EDIT
When looked closer at the for loop, the items should not be deleted by the delete[], because they are allocated via new, not via new[], try to change to:
for(int j = 0; j < currentSize; j++)
{
delete HT1[j];
delete HT2[j];
}
(no need to check for NULL, because delete called on NULL pointer skips the deletion automatically)

Related

Wrong output for an array of a class

So, I have been provided the following classes along with the member variables and methods ( the constructors included . NO extra variables and methods should be added ). I wrote the following codes for the methods provided:
Container Class
# define INTEGER 1
# define INT_ARRAY 2
# define INT_MATRIX 3
class Container{
int *value;
int *valueArray;
int **valueMatrix;
int firstDim, secondDim;
int storedType;
void reset(){
if (value != NULL){
delete value;
value=NULL;
}
if (valueArray != NULL){
delete[] valueArray;
valueArray=NULL;
}
if (valueMatrix != NULL){
for(int i=0;i<firstDim;i++){
delete[] valueMatrix[i];
}
delete[] valueMatrix;
valueMatrix=NULL;
}
firstDim = 0;
secondDim = 0;
storedType = -1;
}
public:
Container(){
cout << "Constructing Container with empty parameter" << endl;
cout << "___________________________________________" << endl;
value = NULL;
valueArray = NULL;
valueMatrix = NULL;
firstDim = 0;
secondDim = 0;
storedType = -1;
}
Container (int val){
cout << "Constructing Container with a single integer parameter" << endl;
cout << "______________________________________________________" << endl;
value=new int(val);
valueArray = NULL;
valueMatrix = NULL;
firstDim = 0;
secondDim = 0;
storedType = INTEGER;
}
Container (int *valArr, int len){
cout << "Constructing Container with integer array parameter" << endl;
cout << "___________________________________________________" << endl;
valueArray=new int[len];
value=NULL;
valueMatrix=NULL;
for(int i=0;i<len;i++) valueArray[i]=valArr[i];
firstDim = len;
secondDim = 0;
storedType = INT_ARRAY;
}
Container (int **valMat, int r, int c){
cout << "Constructing Container with integer matrix parameter" << endl;
cout << "____________________________________________________" << endl;
valueMatrix=new int*[r];
value=NULL;
valueArray=NULL;
for(int i=0;i<r;i++){
valueMatrix[i]=new int[c];
for(int j=0;j<c;j++){
valueMatrix[i][j]=valMat[i][j];
}
}
firstDim=r;
secondDim=c;
storedType=INT_MATRIX;
}
Container(const Container &obj){
cout << "Calling copy constructor of Container" << endl;
cout << "_____________________________________" << endl;
firstDim=obj.firstDim;
secondDim=obj.secondDim;
storedType=obj.storedType;
value=new int;
value=obj.value;
valueArray=new int[firstDim];
valueArray=obj.valueArray;
valueMatrix=new int*[firstDim];
for(int k=0;k<obj.firstDim;k++){
valueMatrix[k]=new int[secondDim];
}
valueMatrix=obj.valueMatrix;
}
void setItem (int val){
reset();
value=new int(val);
firstDim = 0;
secondDim = 0;
storedType = INTEGER;
valueArray=NULL;
valueMatrix=NULL;
}
void setItem(int *valArr, int len){
reset();
valueArray=new int[len];
for(int i=0;i<len;i++) valueArray[i]=valArr[i];
firstDim = len;
secondDim = 0;
storedType = INT_ARRAY;
value=NULL;
valueMatrix=NULL;
}
void setItem(int **valMat, int r, int c){
reset();
valueMatrix=new int*[r];
for(int i=0;i<r;i++){
valueMatrix[i]=new int[c];
for(int j=0;j<c;j++){
valueMatrix[i][j]=valMat[i][j];
}
}
firstDim=r;
secondDim=c;
storedType=INT_MATRIX;
value=NULL;
valueArray=NULL;
}
void * getItem(){
if (value != NULL) return value;
if (valueArray != NULL) return valueArray;
if (valueMatrix != NULL) return valueMatrix;
return NULL;
}
int getFirstDim(){
return firstDim;
}
int getSecondDim(){
return secondDim;
}
int getStoredType(){
return storedType;
}
void print(){
if (value != NULL){
cout << "There is only an integer value in the container object" << endl;
cout << "The value is: " << *value << endl;
}
else if (valueArray != NULL){
cout << "There is an integer array in the container object" << endl;
cout << "The values stored in the array are:" << endl;
for (int i=0; i<firstDim; i++){
cout << valueArray[i] << " ";
}
cout << endl;
}
else if (valueMatrix != NULL){
cout << "There is an integer matrix in the container object" << endl;
cout << "The values stored in the matrix are:" << endl;
for (int i=0; i<firstDim; i++){
for (int j=0; j<secondDim; j++){
cout << valueMatrix[i][j] << " ";
}
cout << endl;
}
}
else{
cout << "The object has no elements" << endl;
}
}
~Container(){
if (value != NULL){
cout << "Freeing allocated memory for a single integer" << endl;
delete value;
value = NULL;
}
if (valueArray != NULL){
cout << "Freeing allocated memory for integer array" << endl;
delete[] valueArray;
valueArray = NULL;
}
if (valueMatrix != NULL){
cout << "Freeing allocated memory for integer matrix" << endl;
for(int i=0;i<firstDim;i++){
delete[] valueMatrix[i];
}
delete[] valueMatrix;
valueMatrix = NULL;
}
firstDim = 0;
secondDim = 0;
storedType = -1;
cout << "_____________________" << endl;
cout << "Destructing Container" << endl;
}
};
ContainerArray Class
class ContainerArray{
Container *arrayOfContainers;
int allocatedSize;
public:
ContainerArray(){
allocatedSize = 0;
arrayOfContainers = NULL;
}
ContainerArray(int size){
allocatedSize=size;
arrayOfContainers=new Container[size];
}
void setAllocatedSize(int sz){
if(allocatedSize){
delete[] arrayOfContainers;
}
allocatedSize=sz;
arrayOfContainers=new Container[sz];
}
int getAllocatedSize(){
return allocatedSize;
}
Container getItemAt(int index){
if (index >= allocatedSize){
cout << "Cannot get item, Exception: Container Array index out of bound";
exit(0);
}
return arrayOfContainers[index];
}
void setItemAt(Container p,int x){
if(x >= allocatedSize) cout << "Exception: Container Array index out of bound";
else{
if(p.getStoredType() == 1) arrayOfContainers[x].setItem(*(int*)p.getItem());
else if(p.getStoredType() == 2) arrayOfContainers[x].setItem((int*)p.getItem(),p.getFirstDim());
else if(p.getStoredType() == 3) arrayOfContainers[x].setItem((int**)p.getItem(),p.getFirstDim(),p.getSecondDim());
}
}
~ContainerArray(){
delete[] arrayOfContainers;
allocatedSize=0;
arrayOfContainers=NULL;
}
};
main() function
int main()
{
Container a;
Container b(100);
int *arr = new int[3];
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
Container c(arr, 3);
int **mat = new int*[2];
mat[0] = new int[3];
mat[0][0] = 1;
mat[0][1] = 2;
mat[0][2] = 3;
mat[1] = new int[3];
mat[1][0] = 4;
mat[1][1] = 5;
mat[1][2] = 6;
Container d(mat, 2, 3);
int firstObjArraySize = 3, secondObjArraySize = 4;
ContainerArray containerArray1;
ContainerArray containerArray2(secondObjArraySize);
cout << secondObjArraySize << " constructors with empty parameters are called" << endl;
containerArray1.setAllocatedSize(firstObjArraySize);
cout << firstObjArraySize << " constructors with empty parameters are called" << endl;
containerArray1.setItemAt(a, 0);
containerArray1.setItemAt(b, 2);
containerArray1.setItemAt(c, 1);
containerArray2.setItemAt(c, 0);
containerArray2.setItemAt(d, 1);
for (int i=0; i<3; i++){
cout << i << "-th element of 1st container array:" << endl;
containerArray1.getItemAt(i).print();
}
for (int i=0; i<2; i++){
cout << i << "-th element of 2nd container array:" << endl;
containerArray2.getItemAt(i).print();
}
return 0;
}
The Problem:
The object containerArray1 prints well . But the array initialized in the main() function is used again in the object containeraArray2 . Due to the destructor freeing the memory of the previous object , the array's contents aren't printed as wanted . But the other contents are printed as wanted . I know there might have been any problem in dynamic memory allocation of mine . But I can't understand . Any help would be appreciated .
Thanks ...
EXPECTED OUTPUT
Output for the containerArray1 object :
0-th element of 1st container array:
Calling copy constructor of Container
_____________________________________
The object has no elements
_____________________
Destructing Container
1-th element of 1st container array:
Calling copy constructor of Container
_____________________________________
There is an integer array in the container object
The values stored in the array are:
10 20 30
Freeing allocated memory for integer array
_____________________
Destructing Container
2-th element of 1st container array:
Calling copy constructor of Container
_____________________________________
There is only an integer value in the container object
The value is: 100
Freeing allocated memory for a single integer
_____________________
Destructing Container
Output for containerArray2 object :
0-th element of 2nd container array:
Calling copy constructor of Container
_____________________________________
There is an integer array in the container object
The values stored in the array are:
10 20 30
Freeing allocated memory for integer array
_____________________
Destructing Container
1-th element of 2nd container array:
Calling copy constructor of Container
_____________________________________
There is an integer matrix in the container object
The values stored in the matrix are:
1 2 3
4 5 6
Freeing allocated memory for integer matrix
_____________________
Destructing Container
The problem lies in the 0th element of the 2nd container object . The array prints abrupt numbers .
Your copy-constructor does not copy the values but just bends the pointers.
You allocated the memory but then you overwrite the pointer to the allocated memory.
So instead of this
value=new int;
value=obj.value;
valueArray=new int[firstDim];
valueArray=obj.valueArray;
valueMatrix=new int*[firstDim];
for(int k=0;k<obj.firstDim;k++){
valueMatrix[k]=new int[secondDim];
}
valueMatrix=obj.valueMatrix;
You need to do something like this:
value = nullptr;
valueArray = nullptr;
valueMatrix = nullptr;
storedType = obj.storedType;
switch (storedType)
{
case INTEGER:
value = new int;
*value = *(obj.value);
break;
case INT_ARRAY:
valueArray = new int[firstDim];
std::copy(obj.valueArray, obj.valueArray + firstDim, valueArray);
break;
case INT_MATRIX:
valueMatrix = new int* [firstDim];
for (int k = 0; k < obj.firstDim; k++) {
valueMatrix[k] = new int[secondDim];
std::copy(obj.valueMatrix[k], obj.valueMatrix[k] + secondDim, valueMatrix[k]);
}
break;
}
Since you are just dealing with int values you can just use memcpy instead std::copy, but I just thought I'd mention the general case.

C++ changing object in vector doesn't work

I want to implement a trie using a vector to store the nodes but somehow my insert method doesn't work. I've managed to build the trie data structure using a different implementation but I would like to understand why my current implementation doesn't work.
Works (not index based storing of childs/references):
struct Trie {
struct Trie *references[26];
bool end; //It is true if node represents end of word.
};
DOESN'T WORK (index based storing of childs/references):
struct node {
int references[26] = {0};
bool end;
};
It doesn't work because of a faulty insert function.
void insert_word(string s){
node *current_node = &trie[0];
// current_node->references[4] = 9999 WORKS! Node in Trie is UPDATED
for(int i=0;i<s.size();i++){
print_trie();
int letter_num = static_cast<int>(tolower(s[i])) - static_cast<int>('a');
int next_index = current_node->references[letter_num];
cout << "letter num: " << letter_num << " next index: " << next_index << endl;
if(next_index == 0){
node new_node;
trie.push_back(new_node);
current_node->references[letter_num] = trie.size()-1; // DOESN'T WORK! Node in Trie is NOT UPDATED
cout << "new value: ";
for(auto c:current_node->references)
cout << c << " ";
cout << endl;
cout << "in for" << endl;
print_trie();
current_node = &trie.back();
} else{
current_node = &trie[next_index];
}
}
current_node->end = true;
}
The problem is that when I access current_node as a reference to an object ob the trie vector and I change its value. The object/node in the trie vector isn't always updated. It works in the second line but further down it somehow stops working. I would like to understand why.
Here is a short debug program I wrote to simplify the problem. Here everything seems to work fine.
n1.references[0] = 1;
n2.references[0] = 2;
n3.references[0] = 3;
trie.push_back(n1);
trie.push_back(n2);
trie.push_back(n3);
node *n = &trie[0];
n->references[0] = 10; // Tree is updated properly
n = &trie[1];
n->references[0] = 11; // Tree is updated properly
Can you help me understand why the insert function doesn't work properly?
EDIT: Minimal working example
#include <vector>
#include <string>
#include <iostream>
using namespace std;
struct node
{
int num_words;
int references [26] = {0};
bool end;
};
vector<node> trie;
int n;
void print_trie(){
cout << "#### NEW PRINT TRIE ##### " << endl;
for(int i=0;i<trie.size();i++){
cout << "node " << i << ": ";
for(int j=0;j<26;j++)
cout << trie[i].references[j] << " ";
cout << endl;
}
}
void insert_word(string s){
node *current_node = &trie[0];
// current_node->references[4] = 9999 WORKS! Node in Trie is UPDATED
for(int i=0;i<s.size();i++){
print_trie();
int letter_num = static_cast<int>(tolower(s[i])) - static_cast<int>('a');
int next_index = current_node->references[letter_num];
cout << "letter num: " << letter_num << " next index: " << next_index << endl;
if(next_index == 0){
node new_node;
trie.push_back(new_node);
current_node->references[letter_num] = trie.size()-1; // DOESN'T WORK! Node in Trie is NOT UPDATED
cout << "new reference value of node: ";
for(auto c:current_node->references)
cout << c << " ";
cout << endl;
current_node = &(trie[trie.size()-1]);
} else{
current_node = &trie[next_index];
}
}
current_node->end = true;
}
int main()
{
node root;
trie.push_back(root);
insert_word("hallohallo");
return 0;
}
Anytime a std::vector<T> undergoes a resizing operation all iterators and pointers to elements are invalidated. Using your mcve as an example of where this goes off the rails, consider the marked lines:
void insert_word(string s){
node *current_node = &trie[0]; // **HERE
for(int i=0;i<s.size();i++){
print_trie();
int letter_num = static_cast<int>(tolower(s[i])) - static_cast<int>('a');
int next_index = current_node->references[letter_num];
cout << "letter num: " << letter_num << " next index: " << next_index << endl;
if(next_index == 0){
node new_node;
trie.push_back(new_node); //** RESIZE
current_node->references[letter_num] = trie.size()-1;
cout << "new reference value of node: ";
for(auto c:current_node->references)
cout << c << " ";
cout << endl;
current_node = &(trie[trie.size()-1]); // **HERE
} else{
current_node = &trie[next_index]; // **HERE
}
}
current_node->end = true;
}
In each location marked with // **HERE, you're storing a pointer to an object hosted in your vector. but the line marked with // **RESIZE can (and will) resize via copy/move/etc the entire vector once the capacity is reached. This means current_node no longer points to a valid object, is a dangling pointer, but your code is none-the-wiser and marches on into undefined behavior.
There are a couple of ways to address this. You could reserve the capacity from inception if you know it ahead of time, but for a more robust solution don't use pointers to begin with. if you enumerate via index instead of pointer your solution becomes the following:
void insert_word(std::string s)
{
size_t idx = 0;
for(int i=0;i<s.size();i++){
print_trie();
int letter_num = static_cast<int>(tolower(s[i])) - static_cast<int>('a');
size_t next_index = trie[idx].references[letter_num];
std::cout << "letter num: " << letter_num << " next index: " << next_index << std::endl;
if(next_index == 0){
trie.emplace_back();
trie[idx].references[letter_num] = trie.size()-1;
std::cout << "new reference value of node: ";
for(auto c : trie[idx].references)
std::cout << c << ' ';
std::cout << std::endl;
idx = trie.size()-1;
} else{
idx = next_index;
}
}
trie[idx].end = true;
}
Notice how all instances of current_node have been replaced with trie[idx]. And changing the "current node" is now just a matter of changing the value of idx, which is relevant even when the underlying vector resizes.
that might be caused by type mismatch int is assigned size_t
try ... = (int)trie.size()-1
#include <vector>
#include <iostream>
using namespace std;
struct node{
int num_words;
int references [26] = {}; //........... int
bool end;
};
vector<node> trie;
int n;
void print_trie(){
cout << "#### NEW PRINT TRIE ##### " << endl;
for(int i=0;i<trie.size();i++){
cout << "node " << i << ": ";
for(int j=0;j<26;j++)
cout << trie[i].references[j] << " ";
cout << endl;
}
}
void insert_word(const string& s){
node *current_node = &trie[0];
// current_node->references[4] = 9999 WORKS! Node in Trie is UPDATED
for(int i=0;i<s.size();i++){
print_trie();
int letter_num = int(tolower(s[i]) - 'a');
int next_index = current_node->references[letter_num];
cout << "letter num: " << letter_num << " next index: " << next_index << endl;
if(next_index == 0){
node new_node;
trie.push_back(new_node);
current_node->references[letter_num] = (int)trie.size()-1; //....size_t DOESN'T WORK! Node in Trie is NOT UPDATED
cout << "new reference value of node: ";
for(auto c:current_node->references)
cout << c << " ";
cout << endl;
current_node = &(trie[trie.size()-1]);
} else{
current_node = &trie[next_index];
}
}
current_node->end = true;
}
int main()
{
node root;
trie.push_back(root);
insert_word("hallohallo");
return 0;
}

Why does cout fail to output strings sometimes, but printf has no problem?

Problem: when printing items in a hash table, non top-level items do not print correctly.
I add items line-by-line from a text file. First, number of lines are determined, and then, the hash table is constructed, with the size found in the first loop of the file.
hash constructor
hash::hash(unsigned int tSize)
{
this->tableSize = tSize;
hashTable.resize(tableSize);
for (int i = 0; i < tableSize; i++)
{
hashTable[i] = new item;
hashTable[i]->firstLetters = "__";
hashTable[i]->str = "____";
hashTable[i]->next = NULL;
}
}
adding items, setting values, and printing them
void hash::add(std::string key)
{
int index = hafn(key);
if (hashTable[index]->str == "____")
{
hashTable[index]->str = key;
setFirstLetters(index,key[0],key[1]);
}
else
{
item *iter = hashTable[index];
item *n_ptr = new item;
n_ptr->str = key;
setFirstLetters(n_ptr, key[0], key[1]);
n_ptr->next = NULL;
while (iter->next != NULL)
{
iter = iter->next;
}
iter->next = n_ptr;
}
}
void hash::setFirstLetters(item *n_ptr, char a, char b)
{
n_ptr->firstLetters[0] = a;
n_ptr->firstLetters[1] = b;
}
void hash::setFirstLetters(int index, char a, char b)
{
hashTable[index]->firstLetters[0] = a;
hashTable[index]->firstLetters[1] = b;
}
void hash::print()
{
int num;
for (int i = 0; i < tableSize; i++)
{
num = numInIndex(i);
printer(num, i);
if (num > 1)
{
int c = 0;
for (int j = num - 1; j > 0; j--)
{
printer(c, num, i);
c++;
}
}
}
}
void hash::printer(int num, int i)
{
item *iter = hashTable[i];
cout << "-------------------------------" << endl;
cout << "index = " << i << endl;
cout << iter->str << endl;
cout << iter->firstLetters << endl;
cout << "# of items = " << num << endl;
cout << "-------------------------------" << endl;
cout << endl;
}
void hash::printer(int numIn, int num, int i)
{
item *iter = hashTable[i];
for (int j = 0; j < numIn; j++)
{
iter = iter->next;
}
cout << "-------------------------------" << endl;
cout << "index = " << i << endl;
cout << iter->str << endl;
cout << std::flush;
cout << iter->firstLetters << endl; //this does not work, though the pointer is pointing to the correct values
//printf("%s\n", iter->firstLetters.c_str()); //this works, even without flushing
cout << "# of items = " << num << endl;
cout << "-------------------------------" << endl;
cout << endl;
}
struct item
{
std::string str;
std::string firstLetters;
item *next;
};
The problem is that firstLetters does not print correctly. firstLetters is set correctly. However, in third- and later level items (ie, using the same hash index), firstLetters does not print at all.
In order to be more clear, here is an output example:
-------------------------------
index = 15
will
wi
# of items = 3
-------------------------------
-------------------------------
index = 15
will
wi
# of items = 3
-------------------------------
-------------------------------
index = 15
good
# of items = 3
-------------------------------
Notice, under the heading "adding items, setting values, and printing them," and in the method hash::add(std::string key), I use setFirstLetters() to access the elements inside std::string firstLetters without first initializing them. This causes any change of these values to be lost, essentially. When accessing iter->firstLetters when it's time to print the values, no actual data can be accessed. To avoid this undefined behavior, I changed the definition of hash::add(std::string key) to set the value of firstLetters before attempting to change them.
New definition of hash::add()
void hash::add(std::string key)
{
int index = hafn(key);
if (hashTable[index]->str == "____")
{
hashTable[index]->str = key;
setFirstLetters(index,key[0],key[1]);
}
else
{
item *iter = hashTable[index];
item *n_ptr = new item;
n_ptr->firstLetters = "__"; //here
n_ptr->str = key;
setFirstLetters(n_ptr, key[0], key[1]);
n_ptr->next = NULL;
while (iter->next != NULL)
{
iter = iter->next;
}
iter->next = n_ptr;
}
}
Adding this line fixes the output.
This is the new output:
-------------------------------
index = 15
will
wi
# of items = 3
-------------------------------
-------------------------------
index = 15
will
wi
# of items = 3
-------------------------------
-------------------------------
index = 15
good
go
# of items = 3
-------------------------------
This type of behavior counts as "undefined behavior." There are several moving parts here and the only cause of this behavior is due to lack of initialization. In cases where std::cout fails, but printf() does not, make sure any members/variables are initialized before attempting to access them. In specific cases using std::string, the [] operator can only function properly after initializing normally, using the = operator or other member functions of std::string.

Segmentation Fault (Core Dump) - Code works in VS but not in the Linux Terminal [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
So, I can run this program in Visual Studio with absolutely no problems, producing correct output. However, after compiling in the Linux terminal, I get a seg fault when trying to run the same code. Upon debugging using GDB, the information given is not very helpful (will be provided below). The program consists of two header files and three .cpp files. I will provide all of them below, along with the debugging information given. (If the indenting is weird, it is because of the 4-space code indent rule for submission). I have been trying to find the issue for hours on end to no avail. I have a feeling it is a small, minor mistake. Thank you all very much in advance.
Song.h
#ifndef Song_h
#define Song_h
#include <iostream>
#include <fstream>
#include <string>
#include <ctime>
#include <stdlib.h>
using namespace std;
class Song
{
private:
string artist;
string title;
int size;
public:
Song(); //declares blank song array
Song(string _title, string _artist, int _size); //initializes object with given parameters for Song instance
string getArtist() const
{
return artist;
}
string getTitle() const
{
return title;
}
int getSize() const
{
return size;
}
void setArtist(string _artist)
{
artist = _artist;
}
void setTitle(string _title)
{
title = _title;
}
void setSize(int _size)
{
size = _size;
}
bool operator == (Song const &rhs);
bool operator != (Song const &rhs);
bool operator > (Song const &rhs);
bool operator < (Song const &rhs);
};
#endif
TsuPod.h
#ifndef TsuPod_h
#define TsuPod_h
#include "Song.h"
//TsuPod class declaration
class TsuPod
{
private:
struct SongNode
{
Song data;
SongNode *next;
};
SongNode *songs; //the head pointer
static const int MAX_SIZE = 512;
static const int SUCCESS = 0;
static const int FAILURE = 1;
static const int NO_MEMORY = -1;
static const int NOT_FOUND = -2;
int getNumSongs();
int memSize;
public:
TsuPod();
TsuPod(int size);
~TsuPod();
int addSong(Song const &s);
int removeSong(Song const &s);
void shuffle();
void showSongList();
void sortSongList();
int getRemainingMemory();
int getTotalMemory()
{
return memSize;
}
};
Song.cpp
#endif
#include "TsuPod.h"
#include "Song.h"
Song::Song() //default constructor, initializes a blank song
{
artist = "";
title = "";
size = 0;
}
Song::Song(string _artist, string _title, int _size) //constructor for song when arguments are given by user
{
artist = _artist;
title = _title;
size = _size;
}
bool Song::operator == (Song const &rhs) //overloaded for sorting
{
return (title == rhs.title &&
artist == rhs.artist &&
size == rhs.size);
}
bool Song::operator != (Song const &rhs) //overloaded for sorting
{
return (title != rhs.title ||
artist != rhs.artist ||
size != rhs.size);
}
bool Song::operator > (Song const &rhs) //overloaded for sorting
{
if (artist != rhs.artist)
return (artist > rhs.artist);
else
if (title != rhs.title)
return (title > rhs.title);
else
if (size != rhs.size)
return (size > rhs.size);
else
return false;
}
bool Song::operator < (Song const &rhs) //overloaded for sorting
{
if (artist != rhs.artist)
return (artist < rhs.artist);
else
if (title != rhs.title)
return (title < rhs.title);
else
if (size != rhs.size)
return (size < rhs.size);
else
return false;
}
TsuPod.cpp
#include "TsuPod.h"
#include "Song.h"
TsuPod::TsuPod() //default constructor
{
memSize = MAX_SIZE;
}
TsuPod::TsuPod(int _size) //constructor for when user specifies their prefered memory size, prevents input of a size greater than MAX_SIZE or less than 0
{
if (_size > MAX_SIZE || _size <= 0)
memSize = MAX_SIZE;
else
memSize = _size;
}
TsuPod::~TsuPod() //destructor
{
SongNode *p;
while (songs != NULL)
{
p = songs;
songs = songs->next;
delete p;
}
}
int TsuPod::getRemainingMemory() //finds remaining memory, returns int value
{
int memSum = 0;
SongNode *p = songs;
while (p != NULL)
{
memSum += p->data.getSize();
p = p->next;
}
return memSize - memSum;
}
int TsuPod::addSong(Song const &s) //adds song to TsuPod, returns int number to display result, 0 = success, 1 = failure, -1 = not enough memory
{
if (s.getSize() > getRemainingMemory()) //ensures there is enough unsused memory for song
return NO_MEMORY;
if (s.getSize() > 0) //ensures song is valid
{
SongNode *temp = new SongNode;
temp->data = s;
temp->next = songs;
songs = temp;
return SUCCESS;
}
else
return FAILURE;
}
int TsuPod::removeSong(Song const &s) //removes song, returns int value to display result, 0 = success, 1 = failure, -2 = not found
{
if (songs != NULL)
{
SongNode *prev = NULL;
SongNode *p = songs;
if (p->data == s)
{
songs = p->next;
return SUCCESS;
}
while (p != NULL && p->data != s)
{
prev = p;
p = p->next;
if (songs->data == s)
{
songs = p->next;
delete p;
return SUCCESS;
}
else
if (p->data == s)
{
prev->next = p->next;
delete p;
return SUCCESS;
}
else
{
}
}
}
return NOT_FOUND;
}
int TsuPod::getNumSongs() //calculates number of songs, returns int value
{
SongNode *p1 = songs;
int i = 0;
while (p1 != NULL)
{
i++;
p1 = p1->next;
}
return i;
}
void TsuPod::shuffle() //shuffles TsuPod song list, void return value
{
srand((unsigned)time(NULL));
for (int j = 0; j < getNumSongs() * 2; j++)
{
int r1 = rand() % getNumSongs();
int r2 = rand() % getNumSongs();
SongNode *p1 = songs;
SongNode *p2 = songs;
for (int i = 0; i < r1; i++)
p1 = p1->next;
for (int i = 0; i < r2; i++)
p2 = p2->next;
Song temp = p1->data;
p1->data = p2->data;
p2->data = temp;
}
cout << endl << " PLAYLIST SHUFFLED" << endl << endl;
}
void TsuPod::sortSongList() //sorts song list by artist, title, and size respectively, void return value
{
for (SongNode *p1 = songs; p1 != NULL; p1 = p1->next)
{
SongNode *small = p1;
for (SongNode *p2 = p1->next; p2 != NULL; p2 = p2->next)
{
if (small->data > p2->data)
{
small = p2;
}
}
if (p1 != small)
{
Song temp = small->data;
small->data = p1->data;
p1->data = temp;
}
}
cout << endl << " PLAYLIST SORTED" << endl;
}
void TsuPod::showSongList() //shows song list, void return value
{
cout << " ___________________________________________________ " << endl << " TsuPod 2.0" << endl << endl;
cout << " Memory ---- Total: " << getTotalMemory() << " MB" << " -- Remaining: " << getRemainingMemory() << " MB" << endl;
SongNode *p = songs;
int i = 0;
while (p != NULL)
{
i++;
cout << endl << " " << i << ". " << p->data.getArtist();
int artistLength = p->data.getArtist().length();
for (int j = 0; j < (24 - artistLength); j++) //This loop is implemented to evenly space the artist from the song
cout << " ";
cout << p->data.getTitle();
int titleLength = p->data.getTitle().length();
for (int j = 0; j < (24 - titleLength); j++) //This loop is implemented to evenly space the song title from the song size
cout << " ";
cout << p->data.getSize() << " (MB)" << endl;
p = p->next;
}
cout << endl;
}
TsuPod_Driver.cpp
#include <cstdlib>
#include <iostream>
#include "Song.h"
#include "TsuPod.h"
using namespace std;
int main(int argc, char *argv[])
{
TsuPod t;
Song s1("Animals As Leaders", "Another Year", 4);
int result = t.addSong(s1);
cout << " add result = " << result << endl;
Song s2("Gorillaz", "Stylo", 6);
result = t.addSong(s2);
cout << " add result = " << result << endl;
Song s3("August Burns Red", "Meridian", 6);
result = t.addSong(s3);
cout << " add result = " << result << endl;
Song s4("The Ink Spots", "If I Didn't Care", 7);
result = t.addSong(s4);
cout << " add result = " << result << endl;
Song s5("Beatles", "I Feel Fine", 241);
result = t.addSong(s5);
cout << " add result = " << result << endl;
Song s6("Fine Constant", "Sea", 3);
result = t.addSong(s6);
cout << " add result = " << result << endl;
Song s7("Human Abstract", "Nocturne", 9);
result = t.addSong(s7);
cout << " add result = " << result << endl;
Song s8("August Burns Red", "Meridian", 4);
result = t.addSong(s8);
cout << " add result = " << result << endl;
Song s9("Frank Sinatra", "My Way", 5);
result = t.addSong(s9);
cout << " add result = " << result << endl;
t.showSongList();
t.shuffle();
t.showSongList();
t.sortSongList();
t.showSongList();
result = t.removeSong(s1);
cout << " delete result = " << result << endl;
result = t.removeSong(s2);
cout << " delete result = " << result << endl;
result = t.removeSong(s3);
cout << " delete result = " << result << endl;
t.showSongList();
result = t.removeSong(s4);
cout << " delete result = " << result << endl;
result = t.removeSong(s5);
cout << " delete result = " << result << endl;
result = t.removeSong(s6);
cout << " delete result = " << result << endl;
result = t.removeSong(s7);
cout << " delete result = " << result << endl;
result = t.removeSong(s8);
cout << " delete result = " << result << endl;
result = t.removeSong(s9);
cout << " delete result = " << result << endl;
t.showSongList();
cout << " memory = " << t.getRemainingMemory() << endl << endl << endl << endl;
for (int i = 1; i < 33; i++) //tests to ensure that user cannot add a song when there is not enough space available
{
Song s1("August Burns Red", "Meridian", i);
result = t.addSong(s1);
cout << " add result = " << result << endl;
}
t.showSongList();
cin.get();
return EXIT_SUCCESS;
Debugging Info From Linux Terminal
Program received signal SIGSEGV, Segmentation fault.
0x0000000000402d50 in Song::getSize() const ()
(gdb) backtrace
#0 0x0000000000402d50 in Song::getSize() const ()
#1 0x00000000004024ac in TsuPod::getRemainingMemory() ()
#2 0x00000000004024fb in TsuPod::addSong(Song const&) ()
#3 0x000000000040112e in main ()
I don't see any sign of TsuPod::songs being initialized. There is no guarantee that it's going to be NULL in the empty list case, so your
while (p != NULL)
test in TsuPod::getRemainingMemory() may pass with an insane value from the stack and blow up when you use p on the next line.
I recommend
TsuPod::TsuPod():songs(NULL) //default constructor
{
memSize = MAX_SIZE;
}
TsuPod::TsuPod(int _size):songs(NULL) //constructor for when user specifies their prefered memory size, prevents input of a size greater than MAX_SIZE or less than 0
{
if (_size > MAX_SIZE || _size <= 0)
memSize = MAX_SIZE;
else
memSize = _size;
}
to ensure that songs starts with your end of list condition.
Also, consider using std::list to do your list management in place of the roll-your-own linked list.

C++ Tree pointer Error

I am trying to figure out how to create a tree in C++. I have tried debugging this for hours and I thought it was time I got another set of eyes on it. My question is if my treeNodeClass looks correct. Right now I am getting a stack explosion because I'm double removing items from my node. The tree itself will be parsing a simple xml file. Here is my code.
#include "treeNodeClass.h"
TreeNodeClass::TreeNodeClass()
{
cout << "TREENODECLASS::TREENODECLASS()" << endl;
attributes.clear();
children.clear();
data = "";
height = 0;
parent = NULL;
tag = "";
cout << "EXIT TREENODECLASS::TREENODECLASS()" << endl;
}
TreeNodeClass::TreeNodeClass(const TreeNodeClass& other)
{
cout << "TREENODECLASS::TREENODECLASS(const other)" << endl;
parent = NULL;
CopyIntoMe(other);
cout << "EXIT TREENODECLASS::TREENODECLASS(const other)" << endl;
}
TreeNodeClass::~TreeNodeClass()
{
cout << "TREENODECLASS::~TREENODECLASS()" << endl;
if(parent)
delete parent;
parent = NULL;
children.clear();
attributes.clear();
cout << "EXIT TREENODECLASS::~TREENODECLASS()" << endl;
}
void TreeNodeClass::CreateAttrib(string root, string val)
{
string attrib = root + "=" + val;
attributes.push_back(attrib);
}
void TreeNodeClass::CreateTag(string data, string name)
{
tag = name;
this->data = data;
}
list<string> TreeNodeClass::ReturnAttrib()
{
return this->attributes;
}
string TreeNodeClass::ReturnTag(string tag)
{
string retTag = "";
if(this->tag == tag)
retTag = this->tag;
return retTag;
}
void TreeNodeClass::AddChildren(TreeNodeClass* c)
{
if(c != NULL)
children.push_back(c);
}
TreeNodeClass& TreeNodeClass::operator=(const TreeNodeClass& other)
{
cout << "TREENODECLASS& TREENODECLASS OPERATOR = " << endl;
if(&other != this)
{
if(parent)
delete parent;
parent = NULL;
attributes.clear();
children.clear();
CopyIntoMe(other);
}
return *this;
}
void TreeNodeClass::CopyIntoMe(const TreeNodeClass& other)
{
cout << "Copy into me" << endl;
tag = other.tag;
data = other.data;
attributes = other.attributes;
children = other.children;
parent = new TreeNodeClass;
parent = other.parent;
height = other.height;
}
void TreeNodeClass::AddParent(TreeNodeClass* p)
{
if(p)
{
parent = new TreeNodeClass;
parent = p;
}
}
std::vector< TreeNodeClass* > TreeNodeClass::ReturnChildren()
{
return children;
}
ostream& operator<<(ostream& out, const TreeNodeClass& treeNode)
{
out << "NODE: " << treeNode.tag << " " << treeNode.data << endl;
out << "CHILDREN: " << treeNode.children.size() << endl;
out << "HEIGHT: " << treeNode.height << endl;
out << "Attributes: ";
for(list<string>::const_iterator iter = treeNode.attributes.begin(); iter != treeNode.attributes.end(); iter++)
{
out << *iter << " ";
}
out << endl;
}
void TreeNodeClass::SetHeight(int h)
{
height = h;
}
/*void function(TreeNodeClass* node)
{
cout << node << " " << *node << endl;
}
TreeNodeClass* function2(TreeNodeClass* node)
{
return node;
}
int main()
{
cout << "STARTING PROGRAM" << endl;
cout << "CREATING A TREE NODE CLASS " << endl;
TreeNodeClass* newNode;
TreeNodeClass* tempNode;
list<string> attribs;
newNode = new TreeNodeClass;
tempNode = new TreeNodeClass;
newNode->SetHeight(10);
cout << *tempNode << " " << *newNode << endl;
tempNode->SetHeight(20);
cout << *tempNode << "\n " << *newNode << endl;
cout << "Setting equal " << endl;
*tempNode = *newNode;
cout << *tempNode << " " << *newNode << endl;
tempNode->SetHeight(40);
cout << *tempNode << " " << *newNode << endl;
tempNode->AddChildren(newNode);
newNode->AddParent(tempNode);
cout << *tempNode << "\n " << *newNode << endl;
return 0;
}
*/
And I'm trying to use this code on a simple state machine. I basically set up a vector of lists to return the states. This is what I believe is giving me a majority of my errors. I've been staring at this as well for a while, but I'm kind of lost.The machine will create the tree (supposedly). When the state machine finishes (state 10) it returns and the calling function will just make another call to yylex(). Thanks for the help so far!
TreeNodeClass* ProcessTree(TokenT token, vector <list <stateAssoc> >& vecTree, int depth)
{
int state = 1; //Assume this is a new record.
bool noState = false;
bool update = true;
int dex = 0;
string root, value, data, tag;
TreeNodeClass* treeNode;
treeNode = new TreeNodeClass; //Assume a new node per state machine visit.
while(state != 10)
{
switch(state)
{
case 1: dex = 1;
break;
case 2: state = 3;
noState = true;
root = yylval;
break;
case 3: state = 4;
noState = true;
break;
case 4: dex = 3;
value = yylval;
//cout << value << endl;
treeNode->CreateAttrib(root, value);
break;
case 5: dex = 2;
data = yylval;
//cout << 5 << " " << yylval << " " << token << endl;
//If its data store as data; if tag its a start tag.
break;
case 6: dex = 4;
//cout << token << " " << yylval << endl;
break;
case 7: state = 9;
noState = true;
tag = yylval;
//cout << tag << token << endl;
if(data != "" and data != "authors")
treeNode->CreateTag(data, tag);
break;
case 8: {
TreeNodeClass* childNode = new TreeNodeClass;
childNode = ProcessTree(token, vecTree, depth+1);
cout << "BEFORE PARENT" << endl;
childNode->AddParent(treeNode);
childNode->SetHeight(depth);
treeNode->AddChildren(childNode);
delete childNode;
childNode = NULL;
}
token = TokenT(yylex()); //Get a new token to process.
dex = 5;
break;
case 9: state = 10;
noState = true;
update = false;
break;
case 10: noState = true;
update = false;
break;
default: cout << "Error " << endl;
cout << state << endl;
cin.get();
break;
}
if(!noState)
state = FindMatch(vecTree[dex], token);
else
noState = false;
if(update)
token = TokenT(yylex());
else
update = true;
}
return treeNode;
}
1.A children shouldn`t delete a parent:
TreeNodeClass::~TreeNodeClass()
{
cout << "TREENODECLASS::~TREENODECLASS()" << endl;
/* Delete next 2 lines
if(parent)
delete parent;
*/
parent = NULL;
children.clear();
attributes.clear();
cout << "EXIT TREENODECLASS::~TREENODECLASS()" << endl;
}
2.Containers will not delete a pointer -- you should take it in mind always. Easy way to delete, for example:
for (vector<TreeNodeClass*>::iterator child = children.begin(); child != children.end(); ++child)
delete *child;
But best way -- not use native pointers and use some smart pointers or shared pointers.
3.Main function do not delete pointers tempNode and newNode.
4.If you'll use native pointers, you should recursively create and copy each children. In other way you'll catch memory leak.
5.Example of method CopyIntoMe:
void TreeNodeClass::CopyIntoMe(const TreeNodeClass& other)
{
cout << "Copy into me" << endl;
tag = other.tag;
data = other.data;
attributes = other.attributes;
// delete each pointer to Nodes
foreach (vector<TreeNodeClass*>::iterator child = children.begin(); child != children.end(); ++child)
delete *child;
children.clear();
// Copy recursively each child
foreach (vector<TreeNodeClass*>::iterator child = other.children.begin(); child != other.children.end(); ++child) {
TreeNodeClass* new_child = new TreeNodeClass;
new_child->CopyIntoMe(*child);
children.push_back(new_child);
}
parent = other.parent;
height = other.height;
}
This is bad:
parent = new TreeNodeClass;
parent = p;
This is a memory leak. Since you are allocating memory and pointing parent to it, then immediately pointing parent to something else, you can never delete that allocated memory. The memory will be allocated and lost every time AddParent() is called.