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;
}
Related
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 creating a trie and am having trouble at the time of compiling.
The warningI get is:
"Reading invalid data from 'currNode->dict': the readable size is '104' bytes, but '388' bytes may be read."
#pragma once
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
const int SIZE = 26;
struct Node {
bool isWord;
Node* dict[SIZE];
};
class Dictionary
{
public:
Dictionary();
Dictionary(string file);
void addWord(string word);
private:
Node *root;
int numWords;
};
Dictionary::Dictionary()
{
numWords = 0;
root = new Node;
for (int i = 0; i < SIZE; i++)
root->dict[i] = nullptr;
}
Dictionary::Dictionary(string file)
{
numWords = 0;
root = new Node;
for (int i = 0; i < SIZE; i++)
root->dict[i] = nullptr;
ifstream inFile;
string word;
inFile.open(file);
while (inFile >> word) {
addWord(word);
numWords++;
}
}
void Dictionary::addWord(string word)
{
int len = word.length(); // size of word
char letter;
int pos;
Node *currNode = root;
for (int i = 0; i < len; i++) {
letter = word[i]; // takes character at position i
pos = letter - 'a'; // finds the position of the character in the array (0 through 25)
// with 'a' being 0 and 'z' being 25
if (!currNode->dict[pos]) {
currNode->dict[pos] = new Node;
currNode->isWord = false;
}
currNode = currNode->dict[pos];
}
currNode->isWord = true;
}
What could be causing this? I'm pretty sure that I'm not trying to access invalid memory. Perhaps it's the way I setup my node and class?
One mistake is that you fail to initialize Node to default values. In your Dictionary default constructor, you have code that really should be part of what Node should be doing:
root = new Node ;
for (int i = 0; i < SIZE; i++)
root->dict[i] = nullptr;
This should be Node's job, not the job of Dictionary.
Instead, you have this:
struct Node {
bool isWord;
Node* dict[SIZE];
};
So every time you do this:
if (!currNode->dict[pos]) {
currNode->dict[pos] = new Node;
You are creating an uninitialized Node object. That entire Node::dict array contains uninitialized pointers, which you later try to access.
The easiest solution is to zero-initialize the Node object.
if (!currNode->dict[pos]) {
currNode->dict[pos] = new Node(); // <-- Note the parentheses
This will automatically set the dict pointers to nullptr.
The other method is to make sure Node objects are created with default values:
#include <algorithm>
struct Node {
bool isWord;
Node* dict[SIZE];
Node() : isWord(false) { std::fill_n(dict, SIZE, nullptr); }
};
With this, even new Node; will create nodes that are initialized.
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;
Well, i've read many different posts about this topic, but none could solve my question.
How can i dynamically create objects, and store them in a linked list.
i've this code that an object saves a number, and then it has a pointer that points to the next number, for representation only.
For example: 17
One->next = seven. Boths are objects of the same class.
class Class{
private:
int value;
Class *pNext; //Points to the next object in the linked list.
public:
Class(){value = 0; }
~Class(){;}
void setV(int x){ value = x;}
int getV(){return value;}
//void setP(Class *p){ pNext = p;} ?? Is this right?
};
int main(){
Class *pFirst; //pointer to first element
Class *pLast; //pointer to last element
Class *pCurrent; //pointer to current element
for(int i = 0; i < 4;i++){
pCurrent = new Class;
pCurrent->setV(i);
//pCurrent->setP(NULL);
}
for(int i = 0; i < 4;i++){
cout << pCurrent->getV() << " ";
}
return 0;
}
Thanks
To make the list permanent, you first have to declare your head node and then for each iteration in your for loop, add on to that list.
int main()
{
Class *pFirst; //pointer to first element
pFirst->setV(0);
Class *pLast; //pointer to last element
Class *pCurrent; //pointer to current element
pFirst->pNext = pCurrent; // To keep track of the list via head
for(int i = 0; i < 4;i++)
{
pCurrent = new Class;
pCurrent->setV(i);
pCurrent->pNext = NULL;
}
for(int i = 0; i < 4;i++)
{
cout << pCurrent->getV() << " ";
}
return 0;
}
Hi everyone: Here i have created a queue from two stacks: You add to the one and remove from the other - when you want to remove the first stack dumps all its data into the second one, and it works perfectly - BUT
whenever i try to execute this loop without the bottom for loop or cin
the program receives a segmentation fault, i mean the most bottom for loop doesn't even execute but take it out and see what happens. Could this be some sort of buffer overflow
and Gcc needs time to manage the memory?
=====================================================================
struct Node
{
int DataMember;
Node* Next;
};
class Que
{
public:
Que();
~Que();
void Add(int);
void Pop();
int getSize();
void Purge();
private:
Node* Head;
bool StackOrQue; //True = Que False = Stack
int Size;
int Remove();
void Reverse();
};
void Que::Purge()
{
while(Head != NULL)
Pop();
if(StackOrQue)
StackOrQue = false;
}
int Que::getSize()
{
return Size;
}
Que::Que()
{
Head = NULL;
Size = 0;
StackOrQue = false;
}
Que::~Que()
{
Head = NULL;
}
void Que::Add(int q)
{
if(StackOrQue)
Reverse();
Size += 1;
Node* Temp = new Node;
Temp->DataMember = q;
Temp->Next = Head;
Head = Temp;
}
int Que::Remove()
{
int i = Head->DataMember;
Node* Temp = Head->Next;
delete Head;
Size -= 1;
Head = Temp;
return i;
}
void Que::Pop()
{
if(!StackOrQue)
Reverse();
cout << Remove();
}
void Que::Reverse()
{
Que TempStack;
int k = Size;
for(int i = 0; i < k; i++)
TempStack.Add(this->Remove());
delete this;
*this = TempStack;
if(!StackOrQue)
StackOrQue = true;
else
StackOrQue = false;
}
=====================================================================
Que q;
char a = NULL;
while(a != 'x')
{
q.Purge();
q.Add(1);
q.Add(2);
q.Add(3);
q.Add(4);
q.Add(5);
q.Add(6);
q.Add(7);
q.Add(8);
int size = q.getSize();
for(int i = 0; i < size; i++)
q.Pop();
//cin >> a;
for(int i = 0; i < 0; i++)
;
}
Thanks in-advance
delete this;
*this = TempStack;
There are some extreme corner cases in which delete this; actually does the right thing. This is not one of them. Specially since your Queue is placed in the stack, and you further try to delete it. If you intend to call the destructor instead do this->~Queue(), however after a manual destruction the only sensible thing to do next is a placement new. Assigning to *this is almost always a bad idea (if you bring inheritance into the picture, you have just caused a slice object to be created and more problems ahead the road). Also, your class should be implementing a copy constructor and an assignment operator, to correctly handle the resources allocated.