Array Wrapper Corrupts Heap - c++

Sequel to: array wrapper corrupts stack
The project:
I am working on a std::vector replacement.
The error:
I get a heap corruption error whenever I attempt to delete a temporary array I am creating in order to store the copied elements of another array that I delete in order to reallocate it when my array gets resized. (It seems that if I try to assign one array to another, I actually end up assigning the pointer to the array to the other array instead of copying the elements. Truly crazy stuff).
I read online that this error may actually come from the part where I actually interact with the array, but the error only pops out when I attempt to delete it.
Where I interact with the array is the function _tempcpy. I pass a pointer to a source and destination array and copy each element from the source to the destination. I struggled a bit with making sure that the array would start from 0 and not 1 and in the process I messed a bit too much with the element_count member, so it may be that i am somehow writing outside of bounds and I have stared so much at the code I can't see the issue.
The code:
template<class T> class dyn_arr
{
public:
dyn_arr(void)
{
this->array = {};
this->element_count = {};
}
~dyn_arr(void)
{
this->dealloc();
}
bool alloc(unsigned int element_count)
{
if (0 == element_count)
{
element_count = 1;
}
if (this->array != nullptr)
{
T* temp = new T[this->element_count];
if (false == this->_tempcpy(&this->array, &temp, this->element_count))
{
return false;
}
delete[] this->array;
this->array = new T[this->element_count];
if (false == this->_tempcpy(&temp, &this->array, this->element_count))
{
return false;
}
delete[] temp;
if (nullptr != this->array)
{
return true;
}
}
else
{
this->array = new T[this->element_count];
if (nullptr != this->array)
{
return true;
}
}
return false;
}
bool dealloc(void)
{
if (nullptr == this->array)
{
return false;
}
delete[] this->array;
return true;
}
bool add(T Object)
{
if (0 == Object)
{
return false;
}
if (true == this->alloc(this->element_count))
{
this->array[this->element_count] = Object;
++this->element_count;
return true;
}
return false;
}
T get(unsigned int index)
{
if (index > this->element_count)
{
return T{};
}
return this->array[index];
}
unsigned int get_count(void)
{
return this->element_count;
}
private:
bool _tempcpy(T** src, T** dest, unsigned int count)
{
if ((nullptr == src) || (nullptr == dest) || (0 == count))
{
return false;
}
for (unsigned int i = 0; i < count; ++i)
{
*dest[i] = *src[i];
}
return true;
}
T* array;
unsigned int element_count;
};
int main()
{
dyn_arr<int> pNr = {};
pNr.add(1);
pNr.add(2);
pNr.add(3);
for (int i = 0; i < pNr.get_count(); ++i)
{
printf("%d\n", pNr.get(i));
}
getchar();
return 0;
}

In your alloc function there lie a few problems, such as:
if (0 == element_count)
{
element_count = 1;
}
is unnecessary. Instead, you can just do a +1 where necessary which is almost everywhere except the temp dynamic array.
bool alloc(...)
{
this->array = new T[this->element_count];
//...
else
{
this->array = new T[this->element_count];
}
}
should be
this->array = new T[this->element_count + 1];
//...
else
{
this->array = new T[this->element_count + 1];
}
this will fix the problems with allocation. That leaves us with _tempcpy() which fails because instead of trying to get the next element of the underlying array, it tries to do that with the double ptr itself. Read about operator precedence rules. Fixed version:
bool _tempcpy(T** src, T** dest, unsigned int count)
{
//....
for (unsigned int i = 0; i < count; ++i)
{
(*dest)[i] = (*src)[i];
}
//....
}
However, I am unsure as to why double ptr is needed in this function in the first place. Just use single pointers. Also dest should be const as it is not changing in this function. It gives the reader of the function a clear idea of which parameters will change inside the function and which will not:
bool _tempcpy(T* src, const T* dest, unsigned int count) {...}
same could be applied to other parts of the class.
Additionally, in C++
dyn_arr(void)
We don't do this. There's no need to explicitly write void. According to the C++ standard:
8.3.5 Functions [dcl.fct]
...
A parameter list consisting of a single unnamed parameter of non-dependent type void is equivalent to an empty parameter list.

Related

Memory Issue in C++ - UNINITIALIZED READ: reading register eax

After declaring a default constructor for this templated program I am working on:
template<typename T>
Set<T>::Set()
: size(0), capacity(8) {
//allocate new array
items = new T[capacity];
}
I have a relatively inconspicuous function contains that tests for whether or not items contains a specific item in it.
template<typename T>
bool Set<T>::contains(const T& item) const {
for (int i = 0; i < size; i++) {
if (this->items[i] == item)
return true;
}
return false;
}
It works fine when I call it in certain locations such as this function that reads through items and only adds an item if there is no other copy (part of our assignment specifications):
template<typename T>
void Set<T>::add(const T& item) {
if (this->contains(item) == 0) {
grow();
items[size++] = item;
}
}
But when I call it when attempting to overload the operator ==, I get the error in the title when I run it through DRMemory
template<typename T>
bool Set<T>::operator==(const Set<T>& other) const {
int count = 0;
for (int i = 0; i < size; i++) {
if (this->contains(other.items[i])) {
count++;
}
}
if (count == size)
return true;
return false;
}
for (int i = 0; i < size; i++) {
if (this->contains(other.items[i])) {
count++;
}
}
size should be other.size. Otherwise other.items[i] in the loop may be out-of-bounds if size > other.size.
Similarly size in the later check needs to be other.size as well.
On the other hand, you need to add a test for size == other.size anyway to make sure that the sets are really equal. If you put that at the beginning, it won't matter whether you use size or other.size later.
Btw. instead of using count to count the identical elements, you can just return false as soon as one .contains fails.

With C++ how do I Pass a value from a void function?

I have two C++ functions in a class:
void Attribute::setIndex(int inIndex) {
if (inIndex < 0) {
index = 0;
}
else if (inIndex >= MAX_NUM_ATTRIBUTES) {
index = MAX_NUM_ATTRIBUTES - 1;
}
else {
index = inIndex;
}
}
and
int Attribute::getValueWithinRange(int value) {
value = setIndex(value);
return value;
}
The second function is supposed to use setIndex to set 'value' to the correct number and return it. However, since the first function is a void function, i cannot simply pas the value in the way i did above. Should i do pass by reference or are there any suggestions? Thank you very much.
I would like just to note, that if you are learning C++, you should try to learn model cases first, sometimes rushing examples is not the best way, but there we go:
Change the setIndex to return int, my favorite;
int Attribute::setIndex(int inIndex)
{
if (inIndex < 0)
{
index = 0;
}
else if (inIndex >= MAX_NUM_ATTRIBUTES)
{
index = MAX_NUM_ATTRIBUTES - 1;
}
else
{
index = inIndex;
}
return index;
}
int Attribute::getValueWithinRange(int value)
{
value = setIndex(value);
return value;
}
Change the getValueWithinRange to return index, both methods are in one class, they share the access to index;
int Attribute::getValueWithinRange(int value)
{
setIndex(value);
return index;
}
Giving it reference would work, but you can not set reference to null unless using a trick and it would require unnecessarily another method, so pointer makes it less messy:
int Attribute::setIndex(int inIndex, int* ret_index = nullptr)
{
if (inIndex < 0)
{
index = 0;
}
else if (inIndex >= MAX_NUM_ATTRIBUTES)
{
index = MAX_NUM_ATTRIBUTES - 1;
}
else
{
index = inIndex;
}
if (ret_index != nullptr) *ret_index = index;
return index;
}
int Attribute::getValueWithinRange(int value)
{
int retvalue;
setIndex(value); // use it like this when returning value is not needed
setIndex(value, &retvalue);
return retvalue;
}

Minimal C++ STL Vector Implementation Problems

I have a technical problem and it's really confusing me. I apologise in advance because I may not be giving the relevant details; I don't yet why it's going wrong and it would be excessive to include all the code I'm working with.
I'm working with a large program that uses the C++ STL. I'm moving this code to a very sensitive environment without a standard clib nor STL implementaton; it will redefine malloc/free/new/delete etc... For that, I need to replace the std:: parts with my own simplified implementations. I've started with std::vector. Right now it's running in the standard ecosystem so it's the GNU libc and STL. The only thing that's changed is this vector class.
When I execute the program with the replaced class, it segfaults. I've put this through GDB and found that the program will request an object from the vector using the subscript operator. When the object reference is returned, a method is invoked and the program segfaults. It seems it can't find this method and ends up in main_arena() in GDB. The type of the object is an inherited class.
I'm really not sure at all what the problem is here. I would love to provide additional details, but I'm not sure what more I can give. I can only assume something is wrong with my vector implementation because nothing else in the program has been changed. Maybe there's something obvious that I'm doing wrong here that I'm not seeing at all.
I'm using: g++ (GCC) 4.4.5 20110214 (Red Hat 4.4.5-6)
I'd really appreciate any feedback/advice!
#ifndef _MYSTL_VECTOR_H_
#define _MYSTL_VECTOR_H_
#include <stdlib.h>
#include <assert.h>
typedef unsigned int uint;
namespace mystl
{
/******************
VECTOR
********************/
template <typename T>
class vector
{
private:
uint _size;
uint _reserved;
T *storage;
void init_vector(uint reserve)
{
if (reserve == 0)
{
_reserved = 0;
return;
}
storage = (T*)malloc(sizeof(T)*reserve);
assert(storage);
_reserved = reserve;
}
public:
vector()
{
// std::cerr << "default constructor " << this << std::endl;
storage = NULL;
_size = 0;
_reserved = 0;
}
vector(const vector<T> &other)
{
// std::cerr << "copy constructor " << this << std::endl;
storage = NULL;
_size = 0;
_reserved = 0;
init_vector(other.size());
_size = other.size();
for (uint i=0; i<other.size(); i++)
{
storage[i] = T(other[i]);
}
}
vector(uint init_num, const T& init_value)
{
// std::cerr << "special constructor1 " << this << std::endl;
storage = NULL;
_size = 0;
_reserved = 0;
init_vector(init_num);
for (size_t i=0; i<init_num; i++)
{
push_back(init_value);
}
}
vector(uint init_num)
{
// std::cerr << "special constructor2 " << this << std::endl;
storage = NULL;
_size = 0;
_reserved = 0;
init_vector(init_num);
}
void reserve(uint new_size)
{
if (new_size > _reserved)
{
storage = (T*)realloc(storage, sizeof(T)*new_size);
assert(storage);
_reserved = new_size;
}
}
void push_back(const T &item)
{
if (_size >= _reserved)
{
if (_reserved == 0) _reserved=1;
reserve(_reserved*2);
}
storage[_size] = T(item);
_size++;
}
uint size() const
{
return _size;
}
~vector()
{
if (_reserved)
{
free(storage);
storage = NULL;
_reserved = 0;
_size = 0;
}
}
// this is for read only
const T& operator[] (unsigned i) const
{
// do bounds check...
if (i >= _size || i < 0)
{
assert(false);
}
return storage[i];
}
T& operator[] (unsigned i)
{
// do bounds check...
if (i >= _size || i < 0)
{
assert(false);
}
return storage[i];
}
// overload = operator
const vector<T>& operator= (const vector<T>& x)
{
// check for self
if (this != &x)
{
_reserved = 0;
_size = 0;
storage = NULL;
init_vector( x.size() );
for(uint i=0; i<x.size(); i++)
{
storage[i] = T(x[i]);
}
_size = x.size();
}
return *this;
}
uint begin() const
{
return 0;
}
void insert(uint pos, const T& value)
{
push_back(value);
if (size() == 1)
{
return;
}
for (size_t i=size()-2; i>=pos&& i>=0 ; i--)
{
storage[i+1] = storage[i];
}
storage[pos] = value;
}
void erase(uint erase_index)
{
if (erase_index >= _size)
{
return;
}
//scoot everyone down by one
for (uint i=erase_index; i<_size; i++)
{
storage[i] = storage[i+1];
}
_size--;
}
void erase(uint start, uint end)
{
if (start > end)
{
assert(false);
}
if (end > _size)
end = _size;
for (uint i=start; i<end; i++)
{
erase(start);
}
assert(false);
}
void clear()
{
erase(0,_size);
}
bool empty() const
{
return _size == 0;
}
}; //class vector
}
#endif // _MYSTL_VECTOR_H_
Wow!
Your assignment operator also leaks memory.
Becuause you are using malloc/release the constructor to your type T will will not be called and thus you can not use your vector for anything except the most trivial of objects.
Edit:
I am bit bored this morning: Try this
#include <stdlib.h> // For NULL
#include <new> // Because you need placement new
// Because you are avoiding std::
// An implementation of swap
template<typename T>
void swap(T& lhs,T& rhs)
{
T tmp = lhs;
lhs = rhs;
rhs = tmp;
}
template <typename T>
class vector
{
private:
unsigned int dataSize;
unsigned int reserved;
T* data;
public:
~vector()
{
for(unsigned int loop = 0; loop < dataSize; ++loop)
{
// Because we use placement new we must explicitly destroy all members.
data[loop].~T();
}
free(data);
}
vector()
: dataSize(0)
, reserved(10)
, data(NULL)
{
reserve(reserved);
}
vector(const vector<T> &other)
: dataSize(0)
, reserved(other.dataSize)
, data(NULL)
{
reserve(reserved);
dataSize = reserved;
for(unsigned int loop;loop < dataSize;++loop)
{
// Because we are using malloc/free
// We need to use placement new to add items to the data
// This way they are constructed in place
new (&data[loop]) T(other.data[loop]);
}
}
vector(unsigned int init_num)
: dataSize(0)
, reserved(init_num)
, data(NULL)
{
reserve(reserved);
dataSize = reserved;
for(unsigned int loop;loop < dataSize;++loop)
{
// See above
new (&data[loop]) T();
}
}
const vector<T>& operator= (vector<T> x)
{
// use copy and swap idiom.
// Note the pass by value to initiate the copy
swap(dataSize, x.dataSize);
swap(reserved, x.rserved);
swap(data, x.data);
return *this;
}
void reserve(unsigned int new_size)
{
if (new_size < reserved)
{ return;
}
T* newData = (T*)malloc(sizeof(T) * new_size);
if (!newData)
{ throw int(2);
}
for(unsigned int loop = 0; loop < dataSize; ++loop)
{
// Use placement new to copy the data
new (&newData[loop]) T(data[loop]);
}
swap(data, newData);
reserved = new_size;
for(unsigned int loop = 0; loop < dataSize; ++loop)
{
// Call the destructor on old data before freeing the container.
// Remember we just did a swap.
newData[loop].~T();
}
free(newData);
}
void push_back(const T &item)
{
if (dataSize == reserved)
{
reserve(reserved * 2);
}
// Place the item in the container
new (&data[dataSize++]) T(item);
}
unsigned int size() const {return dataSize;}
bool empty() const {return dataSize == 0;}
// Operator[] should NOT check the value of i
// Add a method called at() that does check i
const T& operator[] (unsigned i) const {return data[i];}
T& operator[] (unsigned i) {return data[i];}
void insert(unsigned int pos, const T& value)
{
if (pos >= dataSize) { throw int(1);}
if (dataSize == reserved)
{
reserve(reserved * 2);
}
// Move the last item (which needs to be constructed correctly)
if (dataSize != 0)
{
new (&data[dataSize]) T(data[dataSize-1]);
}
for(unsigned int loop = dataSize - 1; loop > pos; --loop)
{
data[loop] = data[loop-1];
}
++dataSize;
// All items have been moved up.
// Put value in its place
data[pos] = value;
}
void clear() { erase(0, dataSize);}
void erase(unsigned int erase_index) { erase(erase_index,erase_index+1);}
void erase(unsigned int start, unsigned int end) /* end NOT inclusive so => [start, end) */
{
if (end > dataSize)
{ end = dataSize;
}
if (start > end)
{ start = end;
}
unsigned int dst = start;
unsigned int src = end;
for(;(src < dataSize) && (dst < end);++dst, ++src)
{
// Move Elements down;
data[dst] = data[src];
}
unsigned int count = start - end;
for(;count != 0; --count)
{
// Remove old Elements
--dataSize;
// Remember we need to manually call the destructor
data[dataSize].~T();
}
}
unsigned int begin() const {return 0;}
}; //class vector
With your current memory handling, this vector would only work with plain old data types.
To handle all types, it must ensure that objects
are actually created (malloc doesn't do that),
destroyed (free doesn't do that),
and you can't reallocate memory with realloc, because complex objects are not guaranteed to remain valid if they are byte-wise copied to another location.
Looks like the answer can be found in your question: "When the object reference is returned, a method is invoked and the program segfaults. It seems it can't find this method and ends up in main_arena() in GDB. The type of the object is an inherited class."
You probably store base class instance T in the vector, but make push_back for the instance of the class inherited from T. In push_back {storage[_size] = T(item);} you cast (actually make copy constructor T:T(const T&)) item to T (this probably named 'type cut'), then get reference to T and invoke a method of the class inherited from T using virtual table of T where the method is not defined yet/abstract. Am I right?
To make it properly work you should put T* in the vector or shared_ptr/unique_ptr depending on the ownership terms you apply to vector elements.
Generally in vector you can store only POD (Plain Old Data) types.

c++ array class problems

Alright, so without going into detail on why I'm writing this class, here it is.
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
aType * Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
aType * Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
aType * Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
It is supposed to be a std::Vector type object, without all the bells and whistles.
Problem is, it doesn't seem to work.
I basically start by going
nArray<string> ca = nArray<string>(5);
ca.Push_Back("asdf");
ca.Push_Back("asdf2");
int intret = 0;
cout << ca.GetAt(1,intret);
I get an Access Violation Reading Location error and it hits on the line
Array[_Count] = Item
in the Push_back function.
The problem seems to be that it's not treating the Array object as an array in memory.
I've spent time going through the code step by step, and I don't know what else to say, it's not operating right. I don't know how to word it right. I'm just hoping someone will read my code and point out a stupid mistake I've made, because I'm sure that's all it amounts to.
Update
So now I changed 3 initializations of Array in nArray(), nArray(int Count), and Resize(int newSize)
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
This is how my code was before. Anyway, the original problem was the fact that when I try to access a specific element in the array, it just accesses the first element, and it doesn't seem to add elements eather. It doesn't seem to be treating Array as an array.
int Resize(int newSize)
{
.
.
aType * Array = new aType[newSize*2];
At this point, instead of updating the member variable as you intended, you've actually created a local variable called Array whose value is discarded when you exit from Resize(). Change the line to
Array = new aType[newSize*2];
The same thing is happening in your constructors, they also need changing accordingly. Moreover, since the default constructor allocates an array, you should set the size members accordingly. You have too many of these: an array needs to keep track of current element count and maximum capacity, however you appear to have three members. What is the purpose of the third? Redundant information is bad, it makes code difficult to read and without a single point of truth it is easier to make mistakes.
With the code in Resize(), you can do better: the second copy is completely redundant.
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
Also, in
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
you need curly braces around body of the if(), just indentation on its own won't do the trick:
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
{
ret = 1;
return aType();
}
ret = 0;
return Array[Index];
}
You have a number of problems. At a guess, the one causing problems so far is that your default ctor (nArray::nArray()) defines a local variable named Array that it initializes, which leaves nArray::Array uninitialized.
Though you probably haven't seen any symptoms from it (yet), you do have at least one more problem. Names starting with an underscore followed by a capital letter (such as your _Size, _MaxSize, and _Count) are reserved for the implementation -- i.e., you're not allowed to use them.
The logic in your Resize also looks needlessly inefficient (if not outright broken), though given the time maybe it's just my brain not working quite right at this hour of the morning.
Your array is not initialized by the constructors and resize function (working on local vars instead).
And is there a reason you want to store instances of string and not pointers to string (string *) ?
I think the answer after the changes is in moonshadow's reply:
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
This code will always return aType(), the last two lines will never be reached.
You might also want to check what happens if you start out with a default-constructed nArray. (Hint: you call Resize(_MaxSize); but what is the value of _MaxSize in this case?
Edit:
This outputs "asdf2" for me as it should be (with the initialization and the braces fixed):
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1) {
ret = 1;
return aType();
}
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
#include <string>
#include <iostream>
using namespace std;
int main()
{
nArray<string> ca = nArray<string>(5);
ca.Push_Back("asdf");
ca.Push_Back("asdf2");
int intret = 0;
cout << ca.GetAt(1,intret);
}

C++ Stack by Array Implementation

What I want to happen is for the pushFront(int) function to do this:
bool stack::pushFront( const int n )
{
items[++top] = n; // where top is the top of the stack
return true; // only return true when the push is successful
}
items is a struct type of the object "item". Have a look:
class stack
{
stack(int capacity);
~stack(void);
...
private:
int maxSize; // is for the item stack
int top; // is the top of the stack
struct item {
int n;
};
item *items;
i've defined the ctor to the stack class object and dtor as follows:
stack::stack(int capacity)
{
items = new item[capacity];
if ( items == NULL ) {
throw "Cannot Allocoate Sufficient Memmory";
exit(1);
}
maxSize = capacity;
top = -1;
}
stack::~stack(void)
{
delete [] items;
items = NULL;
maxSize = 0;
top = -1;
}
Yes the main issue for me is the items[++top] = n; statement. I've been trying to find ways around it like below:
bool stack::pushFront(const int n)
{
int *a = new int[maxSize];
a[++top] = n;
return true;
}
But I cant drag (+) 'a' array out to see those actual array elements... Which is what I was hoping to happen..
What I want is for the statement items[++top] = n; to work..
You can't assign an int value to an item, because you haven't told the compiler how to do that.
You need to either write a constructor or operator= for item that takes an int as a parameter or use
items[++top].n = n;
bool stack::pushFront( const int n )
{
if(top == maxSize-1)
return false;
items[++top].n = n; // where top is the top of the stack
return true; // only return true when the push is successful
}
It appears you have defined a stack of fixed size. You should check that adding to the stack does not exceed the size. To pushFront, you just need to copy the data in the array to make space for the 0th element to be modified:
bool stack::push(const int n)
{
if ( top >= capacity-1 ) return false;
items[++top].n = n
}
bool stack::pushFront(const int n)
{
if ( top >= capacity-1 ) return false;
bcopy( items, items+1, top+1 );
items[0].n = n;
return true;
}