JohnQuestions
JohnQuestions

Reputation: 11

Create an dynamic array in class member function

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.

Upvotes: 0

Views: 915

Answers (3)

Thomas
Thomas

Reputation: 2259

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;
}

Upvotes: 0

Serge Ballesta
Serge Ballesta

Reputation: 148910

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;
}

Upvotes: 0

Joey Yandle
Joey Yandle

Reputation: 141

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!

Upvotes: 1

Related Questions