I have written a custom string and vector classes. Occasionally (but consistently) when adding the string to the vector, the program tries to delete the char pointer (which should be null), causing a seg fault. Even going step by step through the debugger, I cannot figure out how this pointer is not a nullptr as it normally is.
Here are my three constructors for my string class, as well as the = overload which is where the segfault is occurring. Note, I do have a simple destructor that deletes both data and tempreturn if they are not null.
//default constructor
AString::AString(){
this->length = 0;
this->cap = 0;
this->data = nullptr;
this->tempReturn = nullptr;
}
//constructor with arguments for char*
AString::AString(const char* newData){
this->length = strlen(newData);
this->cap = this->length + 1;
this->data = new char[this->cap];
this->tempReturn = nullptr;
for(int i = 0; i < this->length; i ++){
this->data[i] = newData[i];
}
this->data[length] ='\0';
}
//constructor with arguments for passing a string by reference
AString::AString(const AString& newData){
this->length = newData.length;
this->cap = this->length + 1;
this->data = new char[this->cap];
this->tempReturn = nullptr;
for(int i = 0; i < this->length; i++){
this->data[i] = newData.data[i];
}
this->data[length] ='\0';
}
//called with the = string reference
AString& AString::operator= (const AString& newData){
if(data != nullptr){
delete[] data; //This is where it seg faults.
}
this->length = newData.length;
this->cap = newData.length + 1;
this->data = new char[this->cap];
for(int i = 0; i < this->length; i ++){
data[i] = newData.data[i];
}
this->data[length] ='\0';
return *this;
}
At that line, data should be a nullptr and length should be zero. However, at the same element each time, data is filled with a location that holds no chars and length is 33. tempreturn, which should also be null, appears to be holding nonsensical chars
Also for reference, my vector constructor and pushback method that leads into the seg fault
//default constructor setting number of elements to empty, and give a
//default capacity and initialize array;
template <class T>
AVector<T>::AVector(){
this->cap = 10;
this->numElements = 0;
this->data = new T[cap];
}
template <class T>
void AVector<T>::pushBack(T type){
//add it to the end of the current index
this->data[numElements] = type; //line that leads into the segfault
//increase the tracker for how many elements added
numElements++;
//if new element exceeds previously established array
if(numElements >= cap) {
increaseCapacity(this->cap * 2);
}
}
Related
I tried to implement tower of hanoi using stack but there seems to be some problem when running the program. It runs fine sometimes but sometimes the program terminates.
I created a separate class to work as stack.
class stack{
int* arr;
int stackSize;
public:
stack(int size = 0);
~stack();
void push(int a);
int pop();
};
stack::stack(int size){
this->arr = new int(size);
this->stackSize = 0;
}
stack::~stack(){
delete []this->arr;
}
void stack::push(int a){
this->stackSize++;
int* temp = new int(this->stackSize);
for(int i = 0; i < this->stackSize; i++){
temp[i] = this->arr[i];
}
temp[this->stackSize-1] = a;
delete []this->arr;
this->arr = temp;
}
int stack::pop(){
if(this->stackSize <= 0){
cout << "stack underflow" << endl;
}else{
this->stackSize--;
int popped = this->arr[this->stackSize];
int* temp = new int(this->stackSize);
for(int i = 0; i < this->stackSize; i++) {
temp[i] = this->arr[i];
}
delete []this->arr;
this->arr = temp;
return popped;
}
}
void toh(int n, stack &s, stack &des, stack &aux){
if (n <= 0)
return;
toh(n-1, s, aux, des);
des.push(s.pop());
display();
toh(n-1, aux, des, s);
}
this->arr = new int(size); does not allocate memory for an array, it allocates for a single integer. You want this->arr = new int[size]; you do similar in your push function too.
Also, to add, your push should only allocate a new array when it is full.
Also also, in pop, you do not return a value in the case when the if is true. Should either throw an exception, or return a dummy value.
I have a HashTable, where collisions are handled by chaining (linked lists). The first node of every linked list has a pointer from each array position. Shown below is a regular constructor along with rule of 3 functions.
Although my code is compiling and my functions (add, remove, etc) are producing the right output, I am having an issue with the destructor (the IDE points to it with a Thread 1: signal SIGABRT) and the console displays "pointer being freed was not allocated" after my driver program finishes running. I can't figure out what went wrong so any help would be appreciated. I did not include my code for any of the other functions (add, remove, etc) aside from constructors/destructors.
Even when I comment out the copy and overloaded= constructors, the same issue still arise with the destructor.
specification:
class HashTable {
public:
HashTable(int);
~HashTable();
HashTable(const HashTable &);
HashTable& operator=(const HashTable &);
private:
struct Node {
string word;
int wordCount;
Node * next;
// node constructor
Node(string w, int count) {
word = w;
wordCount = count;
next = nullptr;
}
};
Node** wordList;
int capacity;
int hashFunction(string);
};
Implementation of big 4:
constructor:
HashTable::HashTable(int cap) {
capacity = cap;
wordList = new Node*[capacity];
for (int i = 0; i < capacity; i++)
wordList[i] = nullptr;
}
destructor (where the problem seems to be)
HashTable::~HashTable() {
for (int i = 0; i < capacity; i++) {
Node* curr = wordList[i];
while (curr != nullptr) {
Node* prev = curr;
curr = curr->next;
delete prev;
}
}
delete[] wordList;
}
copy constructor:
HashTable::HashTable(const HashTable &obj) {
capacity = obj.capacity;
wordList = new Node*[capacity];
for (int i = 0; i < capacity; i++) {
if (obj.wordList[i] == nullptr)
continue;
Node * newNode = new Node(obj.wordList[i]->word,
obj.wordList[i]->wordCount);
wordList[i] = newNode;
}
}
copy assignment operator:
HashTable& HashTable::operator=(const HashTable &obj) {
if (this != &obj) {
for (int i = 0; i < capacity; i++) {
Node* curr = wordList[i];
while (curr != nullptr) {
Node* prev = curr;
curr = curr->next;
delete prev;
}
}
delete[] this->wordList;
this->capacity = obj.capacity;
this->wordList = new Node*[capacity];
for (int i = 0; i < this->capacity; i++) {
if (obj.wordList[i] == nullptr)
continue;
Node * newNode = new Node(obj.wordList[i]->word,
obj.wordList[i]->wordCount);
this->wordList[i] = newNode;
}
}
return *this;
}
In your copy constructor and copy assignment operator, you are copying the list pointers from obj into this. This leaves the same pointers in both objects, resulting in double free and other issues once one HashTable has been freed,
When you do the copies, you need to do a Deep Copy, which is to allocate new nodes for the copy of the word list.
I am trying to make a dynamic array in my member function, however, it seems to create a new dynamic array each time I call the function. Is there anyway to create a dynamic array inside a member function so it doesn't remake itself.
class predator
{
private:
string name;
string species;
protected:
string *list;
public:
predator(string theSpecies);
void killsRecorded(string kills); // add a new kill to the end of the predator's list of kills
string *killsList(); // return a pointer to the array of all kills by this predator
int noOfTotalKills(); // how many kills have been recorded
int k;
static int n;
};
//The header file
void predator::killsRecorded(string kills)
{
k = 0;
list = new string[5];
*(list + k) = kills;
k = n++;
cout<< k<< endl;
}
string* predator::killsList()
{
//cout<< (sizeof(list)/sizeof(list[0]))<< endl;
for(int i=0; i<5; i++)
{
cout<< *(list + i)<< endl;
}
}
Above is my class and header file, void killsRecorded(string kills) should add kills to my array, however, when I try that in my main.
predator *prey;
prey = new predator("Cheetah");
prey->killsRecorded("Mouse");
prey->KillsRecorded("Donkey");
prey->killsList();
It prints out
Created a hunter that is a Cheetah
0
1
Donkey
*BLANK LINE
*BLANK LINE
*BLANK LINE
*BLANK LINE
Instead, Mouse should be in the first line and Donkey in the second. Am I doing something wrong? Also, I can't use vectors, it's for an assignment.
In your constructor, assign n a default value, say 5. Then create an array of that size.
predator::predator()
: n(5),
k(0)
{
kills = new string[n];
}
Then recordKills checks to see if there is space in kills, reallocating if necessary:
recordKills(string kill)
{
if(k >= n) {
string* oldKills = kills;
kills = new string[2*n];
// copy
for(int i = 0; i< n: i++) {
kills[i] = oldKills[i];
}
n *= 2;
delete [] oldKills;
}
kills[k++] = kill;
}
It's generally a bad idea to call a variable by the name of a data structure, so I renamed 'list' to 'kills'.
Then when printing the kills, loop until k:
string* listKills()
{
for(int i = 0; i < k; i++) {
cout << kills[i] << endl;
}
return kills;
}
Remember to delete kills in the destructor!
Hmm, your killsRecorded(string kills) method is an example of how not to program...
you erase list losing all previously recorded kill
you lose the pointer obtained by a previous new[] which leads to a memory leak (how could you free them now your program has forgotten what had been allocated)
What should be done (what vector class does under the hood):
define a chunk of slots that you initially allocate
add the recorded strings to this simple array until it is full
when it is full allocate another array say of twice the size, carefully copy the values from the old array, release the old array and only them affect the new array to the saved pointer
do not forget to release the allocated array in class destructor
and store in the class the current size (number of kills) and the maximum size (allocated size)
Code could be:
class predator
{
private:
string name;
string species;
protected:
string *list;
size_t max_size;
size_t cur_size;
public:
predator(string theSpecies);
void killsRecorded(string kills); // add a new kill to the end of the predator's list of kills
string *killsList(); // return a pointer to the array of all kills by this predator
int noOfTotalKills(); // how many kills have been recorded
/*int k; what it that???
static int n;*/
};
//The implementation file
predator(string theSpecies): species(species) {
list = new string[5];
max_size = 5;
cur_size = 0;
// what do you do with name ?
}
void predator::killsRecorded(string kills)
{
if (cur_size >= max_size) { /* need a bigger array */
max_size *= 2;
temp = new string[max_size];
for(int i=0; i<cursize; i++) { // copy previous recorded values
temp[i] = list[i];
}
delete[] list; // free previous allocated array
list = temp; // ok list is now big enough
}
list[cur_size++] = kills;
}
You should use std::vector...
to do that you have to
#include <vector>
with the command
std::vector<string> kills;
you can create a new vector of strings
with the command
kills.pushback(stringvalue);
you can add a new string into your vector "list" also you don't have to count your kills... you can use
kills.size();
to get the number of strings back.
To get the values (strings) back you can use the vector like an array
string name = kills[3];
btw: you should save the vector as a member... to do that you have to save it in your class definition (header)
If you arn't allowed to use std::vector, you can write your own list...
class list
{
private:
node* head;
int size = 0;
struct node
{
node* next;
string value;
}
public:
list();
~list();
void PushBack(string);
string GetElement(int index);
int GetSize();
};
list::list()
{
head = new list();
head->next = nullptr;
}
list::~list()
{
node* temp = head;
node* temp2 = temp;
do //delete hole list
{
temp2 = temp->next;
delete temp;
temp = temp2;
}while(temp != nullptr);
}
void list::PushBack(string item)
{
node* temp = head;
while(temp->next != nullptr)
{
temp = temp->next;
}
//found the end of the list
node* newNode = new node();
newNode->value = item;
newNode->next = nullptr;
temp->next = newNode;
size++;
}
int list::GetSize()
{
return size;
}
string list::GetElement(int index)
{
node* temp = head;
while(temp->next != nullptr)
{
temp = temp->next;
if(index == 0)
{
return temp->value;
}
index--;
}
//index out of bounds
return "";
}
I can not check if the code is correct at the moment, because on this computer is no IDE... but I think it should word ;)
BTW: you can use this list instead of an array to do that you have to write:
list kills;
kills.PushBack("Peter");
kills.PushBack("Thomas");
kills.PushBack("Alex");
for(int i = 0; i< kills.GetSize();i++)
{
std::cout<<kills.GetElement(i)<<std::endl;
}
Does anyone see something overtly wrong with my expand function below? I've included the private section of the class and my vertex_node struct to give some context. I'm not sure why it isn't expanding properly. Any help would be appreciated.
private:
//list is pointers to vertex nodes;
struct vertex_node {
string name;
set <string> edges;
};
vertex_node **list;
void Graph:: expand()
{
int new_cap = capacity * 2+1;
//creates new larger array
vertex_node **larger_array = new vertex_node*[new_cap];
//loop through all elements of old array
for(int i = 0; i<capacity; i++){
if(list[i] != NULL){
//rehash each element and place it in new array
int a = hash_string(list[i]->name) % new_cap;
larger_array[a] = new vertex_node;
larger_array[a]->name = list[i] -> name;
larger_array[a]->edges = list[i] -> edges;
}
//delete old list
delete[] list;
list = larger_array;
capacity = new_cap;
}
}
as I mentioned in my comment above you're invalidating the whole array at the end of the 1st iteration. Your attempt at avoiding a memory leak is commendable but it has to be done in 2 places.
for(int i = 0; i<capacity; i++){
if(list[i] != NULL){
//rehash each element and place it in new array
int a = hash_string(list[i]->name) % new_cap;
larger_array[a] = new vertex_node;
larger_array[a]->name = list[i] -> name;
larger_array[a]->edges = list[i] -> edges;
}
//clean up every memory location once you're done with it
delete list[i];
list = larger_array;
capacity = new_cap;
}
//clean the whole array at the very end
delete[] list;
I am having following code. Following code is crashing when I am deleting the allocated memory i.e., Rational::deleteMemPool();
Getting output as
mempool value is 00000000 mempool value is 003462E8 mempool value is 003462E8
// Here for delete crashing though we have valid pointer.
Can any one please help me what is bug here?
#include <string>
#include <iostream>
template < class T >
class MemoryPool {
public:
MemoryPool (size_t size = EXPANSION_SIZE);
~MemoryPool ();
inline void* alloc (size_t size); // Allocate a T element from the free list.
inline void free (void *someElement); // Return a T element to the free list.
private:
MemoryPool<T> *next; // next element on the free list.
enum { EXPANSION_SIZE = 32}; // If the freeList is empty, expand it by this amount.
void expandTheFreeList(int howMany = EXPANSION_SIZE); // Add free elements to the free list
};
template < class T > MemoryPool < T > :: MemoryPool (size_t size) {
expandTheFreeList(size);
}
template < class T > MemoryPool < T > :: ~MemoryPool () {
MemoryPool<T> *nextPtr = next;
for (nextPtr = next; nextPtr != NULL; nextPtr = next) {
next = next->next;
delete [] nextPtr;
}
}
template < class T > inline void* MemoryPool < T > :: alloc (size_t) {
if (!next) {
expandTheFreeList();
}
MemoryPool<T> *head = next;
next = head->next;
return head;
}
template < class T > inline void MemoryPool < T > :: free (void *doomed) {
MemoryPool<T> *head = static_cast <MemoryPool<T> *> (doomed);
head->next = next;
next = head;
}
template < class T > void MemoryPool < T > :: expandTheFreeList(int howMany) {
// We must allocate an object large enough to contain the next pointer.
size_t size = (sizeof(T) > sizeof(MemoryPool<T> *)) ? sizeof(T) : sizeof(MemoryPool<T> *);
void *pNewAlloc = new char[size];
MemoryPool<T> *runner = static_cast <MemoryPool<T> *> (pNewAlloc);
next = runner;
for (int i = 0; i < howMany ; i++) {
void *pNewAlloc = new char[size];
runner->next = static_cast <MemoryPool<T> *> (pNewAlloc);
runner = runner->next;
}
runner->next = 0;
}
class Rational {
public:
Rational (int a = 0, int b = 1 ) : n(a), d(b) {}
void *operator new(size_t size) { return memPool->alloc(size); }
void operator delete(void *doomed,size_t size) { memPool->free(doomed); }
static void newMemPool() {
std::cout << "mempool value is " << Rational::memPool << std::endl;
memPool = new MemoryPool <Rational>;
std::cout << "mempool value is " << Rational::memPool << std::endl;
}
static void deleteMemPool() {
std::cout << "mempool value is " << Rational::memPool << std::endl;
delete memPool;
}
private:
int n; // Numerator
int d; // Denominator
static MemoryPool <Rational> *memPool;
};
MemoryPool <Rational> *Rational::memPool = 0;
int main() {
Rational *array[1000];
Rational::newMemPool();
// Start timing here
for (int j = 0; j < 1; j++) {
for (int i = 0; i < 10; i++) {
array[i] = new Rational(i);
}
for (int i = 0; i < 10; i++) {
delete array[i];
}
}
// Stop timing here
Rational::deleteMemPool();
}
Stacktrace:
Stack trace:>
ReadParsing.exe!Rational::deleteMemPool() Line 75 C++
ReadParsing.exe!main() Line 107 C++
ReadParsing.exe!__tmainCRTStartup() Line 586 + 0x19 bytes C
ReadParsing.exe!mainCRTStartup() Line 403 C
kernel32.dll!7c817077()
You have a problem with how you're deleting the blocks in your memory pool. When you allocate blocks, you use new char[size] in expandTheFreeList(i).
But when you delete those blocks, you use delete [] nextPtr:
template < class T > MemoryPool < T > :: ~MemoryPool () {
MemoryPool<T> *nextPtr = next;
for (nextPtr = next; nextPtr != NULL; nextPtr = next) {
next = next->next;
delete [] nextPtr; // <-- problem
}
}
And since nextPtr is a memoryPool<T>*, you're freeing the wrong thing (and it ends up recursing into this destrcutor to boot).
Changing that problem line to:
delete [] reinterpret_cast<char*>(nextPtr);
seems to make thing not crash. Of course, there may be other problems.