I am implementing an ADT Stack using an array. I want to doubling the size of the array when the stack is full.
const int MAX_SIZE = 6 // max size of array stack
template<class ItemType>
class ArrayStack: public StackInterface<ItemType>{
private:
ItemType items[MAX_SIZE]; // Array of stack items
int top; // index of top
int itemCount; // Amount of items in stack
int maxsize;
This is my push method:
template<class ItemType>
bool ArrayStack<ItemType>::push(const ItemType& newEntry){
if(itemCount == maxsize){ // resize array
cout << "resizing an array..." << endl; // just for testing
ItemType* oldArray = items; // old array to be deleted
ItemType* newItems = new ItemType[2*maxsize];
for(int i=0; i<maxsize; i++){
newItems[i] = oldArray[i]; // copying all array items
}
delete[] oldArray; // deallocate
maxsize = maxsize * 2; // doubling max size
items = newItems; <- I'm getting error from this code
} // end if
// Stack is not full
top++;
items[top] = newEntry;
itemCount++;
return true;
}
I'm getting this error while I'm trying to double the size of the array:
error: array type 'int [6]' is not assignable
items = newItems;
How can I solve this?
ItemType items[MAX_SIZE]; is a fixed array. You can't resize it, you can't reallocate it, and you certainly can't assign an ItemType* pointer to it.
For what you are attempting to do, items needs to be an ItemType* pointer instead of an ItemType[] array:
template<class ItemType>
class ArrayStack: public StackInterface<ItemType>{
private:
ItemType *items; // Array of stack items
...
};
Don't forget to initialize items in your constructor(s), and call delete[] items; in the destructor, and also implement proper copy/move constructors and copy/move assignment operators, per the Rule of 3/5/0.
Related
I am trying to make a network application. Its class blueprint is roughly like this-
class Node
{
public:
// member functions
private:
int nodeID;
// other members
};
class NodeNetwork
{
public:
// member functions
private:
Node nodeArray[MAX_NODES];
// other members
};
Here, the Node class will deal with each node and the NodeNetwork is used to deal with the complete network.
The actual number of nodes in nodeArray can vary from 0 to MAX_NODES during runtime, i.e., it may not always be MAX_NODES, the number of nodes can be increased or decreased during runtime. Moreover, when the program starts the number will always be 0, after that it will start increasing.
I am using Node nodeArray[MAX_NODES];, but I think it's a serious wastage of space as not always I will have MAX_NODES nodes at runtime. So I am looking for ways to optimize it. I want it so that it starts with a zero-length array, but the size can be increased or decreased subjected to the above constraints based on the nodes added or removed at runtime. I researched on the internet but did not find any concrete answer.
I hope someone can help me solve this problem, thanks in advance.
You can use dynamically array allocation for this purpose:
int* arr = new int[5];
..and anytime you wish to change the number of elements:
int size = 5;
int* arr = new int[size] {};
int* new_arr = new int[size + 1];
for (int i = 0; i < size; i++)
{
new_arr[i] = arr[i];
}
delete[] arr;
arr = new_arr;
// Now arr has a storage capacity of 6 elements
..so for your case you can write:
Node* nodeArray = nullptr; // nullptr == null pointer
But this can take a lot of time for huge arrays.
So preferably, you can use std::vector:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vec{ 1, 2, 3, 4, 5 };
vec.push_back(6); //Insert a new element
std::cout << vec[0]; // Accessing an element is the same as an array
}
..so for your case:
// {} is just for initialization, not exactly mandatory
std::vector<Node> nodeArray{};
You can use std::vector instead of array. That is, you can make the data member nodeArray to be a std::vector<Node> as shown below.
#include <iostream>
#include<vector>
class Node
{
public:
//constructor for initializing nodeID data member
Node(int pnodeID): nodeID(pnodeID)
{
}
//getter for nodeId
int getId() const
{
return nodeID;
}
private:
//always initialize built in type in local/block scope so that they don't have indeterminate value
int nodeID = 0;
// other members
};
class NodeNetwork
{
public:
// member function to add Node
void addNode(const Node& n)
{
nodeArray.push_back(n);
}
//member function to print out the current nodes
void display() const
{
std::cout<<"Network has the following nodes: "<<std::endl;
for(const Node& elem: nodeArray)
{
std::cout<<elem.getId()<<std::endl;
}
}
private:
std::vector<Node> nodeArray; //used std::vector instead of array
// other members
};
int main()
{
//create Node objects
Node node1{1};
Node node2{2};
Node node3{3};
NodeNetwork network1;
//add node1 into the network1's nodeArray data member
network1.addNode(node1);
//add node2 into the network1's nodeArray data member
network1.addNode(node2);
//display all nodes into network1
network1.display();
return 0;
}
In the above demo we have added elements into the nodeArray data member by using std::vector::push_back member function.
The output of the above program can be seen here:
Network has the following nodes:
1
2
So this is the original code:
class IntegerArray {
public:
int *data;
int size;
};
int main() {
IntegerArray arr;
arr.size = 2;
arr.data = new int[arr.size];
arr.data[0] = 4; arr.data[1] = 5;
delete[] a.data;
}
After moving arr.data = new int[arr.size] to a constructor, it becomes
class IntegerArray {
public:
int *data;
int size;
IntegerArray(int size) {
data = new int[size];
this->size = size;
}
};
int main() {
IntegerArray arr(2);
arr.data[0] = 4; arr.data[1] = 5;
delete[] arr.data;
}
I'm fairly lost on what the code is trying to do. For
IntegerArray(int size) {
data = new int[size];
this->size = size;
}
Is int size just the same as the int size that was declared in the class IntegerArray?
Does data = new int[size] just tell us that data is pointing to the output of the array at int size, with new saying that the size of the array is variable?
Is this-> size = size just a pointer that tells us that the size value of the constructor is just equal to the size parameter of the class?
Why are arr.data[0] and arr.data[1] even mentioned after IntegerArray arr(2)? They don't seem to follow the constructor, but I'm probably just too tired to comprehend that part.
IntegerArray(int size) {
data = new int[size];
this->size = size;
}
Is int size just the same as ...
This int size:
IntegerArray(int size) {
^^^^^^^^
is an argument to the constructor
Does data = new int[size] just tell us ...
new int[size] dynamically allocates an array that contains size number of int objects. data pointer is then assigned to point to that newly created array.
Is this-> size = size just a pointer ...
No. this is a special pointer, that within the constructor points to the object that is being constructed. this->size is the member variable that was declared here:
class IntegerArray {
public:
int *data;
int size;
^^^^^^^^
The complete expression this->size = size assigns the value size that is the constructor argument, to the member variable size.
Why are arr.data[0] and arr.data[1] even mentioned after IntegerArray arr(2)?
The constructor does not initialize the contents of the array (the integer objects within the array). The mentioned code does assigns a values to them.
this->size = size //the fist size is your member variable which is inside IntegerArray. the 2nd size is the size you give over to the Method
data = new int[size]; // here you are creating a new array with the size of "size"
the method IntegerArray(int size) is a constructor method, you only can call it once per object (even at the time when you create the object)
int main() //the startpoint of your program
{
IntegerArray arr(2); //you are creating a new object with a size of 2
arr.data[0] = 4; arr.data[1] = 5; //because of your array is public, you can call it direct from outside (you sould define it as private ore protected). arr.data[0] is the first item of the array, arr.data[1] is the 2nd item
delete[] arr.data;
}
delete[] arr.data; should be inside the destructor of your class...
I am trying create my own vector, I am at the beginning, and when compile e execute the code, i get "Program not responding". This is the code:
struct X
{
X(){};
~X(){};
int v1, v2, v3;
};
template<typename T>
class Vector
{
public:
// constructors
Vector();
Vector(unsigned s);
virtual ~Vector();
// overloaded operators
T operator[](unsigned index);
// others
void clear();
void add(T value);
unsigned getSize();
bool isEmpty();
private:
// pointer to first item of memory block
T* first;
unsigned size;
};
template<typename T>
Vector<T>::Vector()
{
first = NULL;
size = 0;
}
template<typename T>
Vector<T>::Vector(unsigned s)
{
size = s;
first = new T[s];
};
template<typename T>
Vector<T>::~Vector()
{
clear();
}
template<typename T>
void Vector<T>::clear()
{
for(unsigned i = size ; i > 0 ; i--)
delete &first[i];
first = NULL;
}
template<typename T>
void Vector<T>::add(T value)
{
T* temp = new T[size + 1]; // error happens here
// copy data to new location
for(unsigned i = 0 ; i < size ; i++)
temp[i] = first[i];
// delete older data
clear();
// add the new value in last index
temp[size + 1] = value;
// update the pointer
first = temp;
size++;
}
template<typename T>
T Vector<T>::operator[](unsigned index)
{
return first[index];
}
template<typename T>
unsigned Vector<T>::getSize()
{
return size;
}
template<typename T>
bool Vector<T>::isEmpty()
{
return first == NULL;
}
int main(int argc, char* args[])
{
Vector<X> anything;
X thing;
anything.add(thing);
anything.add(thing);
anything.add(thing); // if remove this line, program work fine.
}
As I commented, error happens in T* temp = new T[size + 1];.
If i define the value of v1, v2, v3 of X class, e.g. X() : v1(0), v2(0), v3(0) { }, the program works correctly.
If i change the type, e.g., Vector of int, he works perfectly.
If put X class in std::vector, work fine too.
Other comments are also accepted.
Can someone helpme?
Your description of the problem is incredibly vague, but I can point out problems with your code:
No vector copy constructor (causes double-deletes and crashes)
No vector copy assignment (causes double-deletes and crashes)
clear is incorrectly calling delete (causes crashes and corruption) (you should match your single new of an array with a single delete of the array. Don't loop over elements.
add is writing past the end of the array (causes crashes and corruption)
add is not exception safe
You have to fix at least the first four. The third and fourth are probably the causes of your hang.
You have a buffer overflow occurring.
T* temp = new T[size + 1]; // When size is 0, you allocate 1 space.
You then assign to the temp array, but in location temp[1], which isn't a valid location because your array has only 1 element. This is undefined behavior, and that this point, your program is free to continue however it chooses. In this case, it seems to loop indefinitely.
// add the new value in last index
temp[size + 1] = value; // When size is zero, your array is length '1', but
// you are accessing temp[1] which is outside the
// bounds of your allocated memory.
I have the following class and code:
template <class T>
class HashTable {
struct Pair{
T element;
int key;
Pair(T element, int Key) : element(element), key(key) {};
};
int table_size;
int counter;
List<Pair> (*elements);
void changeTableSize(int newSize){
List<Pair> *temp = new List<Pair>[newSize];
for (int i = 0; i < table_size; i++){
for (typename List<Pair>::Iterator j = elements[i].begin(); j != elements[i].end(); j++){
Pair p = *j;
temp[p.key % newSize].insert(Pair(p.element, p.key));
}
}
delete[] elements;
elements = temp;
table_size = newSize;
}
public:
HashTable() : table_size(100), counter(0){
elements = new List<Pair>[table_size];
};
void insert(T data, int key){
if (member(key)){
throw ElementAlreadyExists();
}
elements[key % table_size].insert(Pair (data, key));
counter++;
if (counter == table_size){
changeTableSize(table_size*2);
}
};
When I call changeTableSize() the first time, everything is fine. When I call it the second time my program crashes saying "warning: HEAP: Free Heap block 006618C0 modified at 006618D4 after it was freed" right after the allocation for temp. What can cause this?
If originalSize > table_size then you are performing an illegal memory access in the inner 'for' loop.
Remove the 'originalSize' argument that you are passing to the function.
Use the class variable 'table_size' instead, and update it to the new size before you return.
Also, make sure that class Pair has a copy-constructor properly defined and implemented:
Pair(const Pair& pair)
{
// For each variable x of pair, that points to dynamically-allocated memory:
// this->x = new ...
// memcpy(this->x,pair.x,...)
// For each variable y of pair, that doesn't point to dynamically-allocated memory:
// this->y = pair.y
}
Otherwise, you might have two different instances of class Pair with internal variables pointing to the same dynamically-allocated memory. And when one instance is destroyed, the internal variables of the other instance will point to an already-freed memory.
I have a class, whereby one of its elements is of another class, but is an array
class B
{
public:
B() //default
{
element = new A [1]; count = 0;
}
A add(A place)
{
A* newArr;
newArr = new A [count+1];
newArr = element;
newArr[count+1] = place;
delete element;
return newArr[count+1];
}
protected:
int count;
A* element;
};
I am trying to use dynamic arrays, where I when adding the element, I make a new array dynamically, initilzed to the size of the old array plus 1, then copy the elements of the old array to the new array, and then delete the old array. But I am unsure of how to modify the array that's already within the class, if that makes sense (Basically what to return in my add method).
In C++ there's no notion of resizing arrays once declared. Same goes for dynamic arrays, which can't be resized once allocated. You can, however, create a bigger sized array, copy all elements from the older array to the newer one and delete the old one. This is discouraged and would not be performant.
Using std::vector would allow you to add at will and will also keep track of its size, so you don't need count as part of the class.
class B
{
// no need to allocate, do add when required i.e. in B::add
B() : count(), elements() { }
A add(A place)
{
// unnecessarily allocate space again
A *new_elements = new A[count + 1];
// do the expensive copy of all the elements
std::copy(elements + 0, elements + count, new_elements);
// put the new, last element in
new_elements[count + 1] = place;
// delete the old array and put the new one in the member pointer
delete [] elements;
elements = new_elements;
// bunp the counter
++count;
return place; //redundant; since it was already passed in by the caller, there's no use in return the same back
}
protected:
size_t count;
A *elements;
};
The above code perhaps does what you want but is highly discouraged. Use a vector; you code will simply become
class B
{
// no need of a constructor since the default one given by the compiler will do, as vectors will get initialized properly by default
void Add(A place)
{
elements.push_back(place);
// if you need the count
const size_t count = elements.size();
// do stuff with count here
}
protected:
std::vector<A> elements;
};
A more thorough example would be to more closely mimic std::vector:
template<typename T>
class B
{
private: // don't put data under a protected access!
std::size_t _capacity;
std::size_t _size;
T* _elements;
public:
B() : _capacity(0), _size(0), _elements(nullptr) {}
// other methods
void add(const T& t)
{
if (_size >= _capacity) // need to resize the array
{
_capacity++; // you can make this better by increasing by several at a time
T* temp = new T[_capacity];
std::copy(_elements, _elements + _size, temp);
delete [] _elements;
_elements = temp;
}
_elements[_size++] = t;
}
};