Iterating over pointer array C++
I am new to C++ but I have an experience in C. Now I am trying to iterate over an array of objects but I am getting segmentation fault because it runs out of the range of the array.
I have a class ZombieHorede which keeps a pointer to an array of zombies.
#pragma once
#include "Zombie.hpp"
class ZombieHorde {
private:
static std::string namepool[7];
static std::string typepool[7];
Zombie *zombies;
public:
ZombieHorde(int N);
~ZombieHorde(void);
void announce(void) const;
};
The constructor of this class takes a number N and initializes the array of N zombies. Like this.
ZombieHorde::ZombieHorde(int N)
{
int i;
i = 0;
this->zombies = new Zombie[N];
while (i < N)
{
this->zombies[i].set_name(this->namepool[rand() % 7]);
this->zombies[i].set_type(this->typepool[rand() % 7]);
i++;
}
}
Now I want to iterate over zombies and call a function on each of them ... like this...
void ZombieHorde::announce() const
{
int i;
i = 0;
while (&this->zombies[i])
{
this->zombies[i].announce();
i++;
}
}
And the announce function gives segmentation fault cuz i
goes beyond the range of the array with this main:
#include "ZombieHorde.hpp"
int main()
{
ZombieHorde horde(4);
horde.announce();
}
Now the main question is how to iterate over the zombies array in order to not get a segmentation fault.
ATTENTION: Note that this is a 42 school exercise and I am not allowed to use STL of C++. I should allocate zombies at once in the constructor.
Solution 1:
As i read the given headline to your question , I thought you really have an "pointer array" and iterate over it. But you coded an array of objects, which is a different thing. OK, so lets start creating a real pointer array...
Your problem is while (&this->zombies[i])
. This will test if the result is true or false, if you have pointers, they will be implicit converted to bool, as this we expect a nullptr
at the end of the array.
Maybe you change the allocation and initializing of your array to:
Zombie **zombies = new Zombie*[N+1];
for ( unsigned int idx=0; idx<N; idx++)
{
zombies[idx] = new Zombie;
}
zombies[N] = nullptr; // important to have the "end" mark if we later test for nullptr!
// use it later maybe per index
for ( unsigned int idx=0; idx<N; idx++)
{
zombies[idx]->announce();
}
// or as you tried with pointer to nullptr compare
// you can also use your While instead if you initialize
// your running variable before outside the loop
for ( Zombie** ptr= zombies; *ptr; ptr++)
{
std::cout << ptr << std::endl;
(*ptr)->announce();
}
BTW: No need to write this
in this context!
But you should start to write C++ instead of "C with classes"!
class Zombie
{
private:
std::string name;
std::string type;
public:
// you should always use constructors to set content
// of the class at the beginning instead later overwrite
// values. Making things private and write accessor's to
// all and everything is not the use case of encapsulation
Zombie( const std::string& name_, const std::string& type_): name{name_},type{type_}{}
void announce() const { std::cout << "Zombie " << name << ":" << type << std::endl; }
};
class ZombieHorde {
private:
static std::string namepool[7];
static std::string typepool[7];
std::vector<Zombie> zombies;
public:
ZombieHorde(const unsigned int N);
~ZombieHorde(){}
void announce() const;
};
std::string ZombieHorde::namepool[7] = { "One","two","three","four","five","six","seven"};
std::string ZombieHorde::typepool[7] = { "red","blue","green","yellow","pink","mouve","black"};
ZombieHorde::ZombieHorde(const unsigned int N)
{
for ( unsigned int idx=0; idx < N; idx++ )
{
zombies.emplace_back( this->namepool[rand() % 7], this->typepool[rand() % 7]);
}
}
void ZombieHorde::announce() const
{
// iterate over containers is now simplified to:
for ( const auto& zombie: zombies ) { zombie.announce(); }
}
int main()
{
ZombieHorde horde(4);
horde.announce();
}
Solution 2:
question is how to iterate over the zombies array in order to not get a segmentation fault.
One way to resolve this would be to have a data member called zombieSize
that stores the value of N
as shown below in the modified snippets:
class ZombieHorde {
private:
static std::string namepool[7];
static std::string typepool[7];
Zombie *zombies;
std::size_t zombieSize; //data member that is used to store the value of N
public:
ZombieHorde(int N);
~ZombieHorde(void);
void announce(void) const;
};
//use member initializer list to initialize zombieSize
ZombieHorde::ZombieHorde(int N): zombieSize(N)
{
int i;
i = 0;
this->zombies = new Zombie[zombieSize];//use data member zombieSize instead of N
while (i < zombieSize)//use zombieSize instead of N
{
this->zombies[i].set_name(this->namepool[rand() % 7]);
this->zombies[i].set_type(this->typepool[rand() % 7]);
i++;
}
}
void ZombieHorde::announce() const
{
int i;
i = 0;
while (i < zombieSize)//use zombieSize instead of N
{
this->zombies[i].announce();
i++;
}
}