I had this task in C++ where I had to implement a Stack only using arrays (and not using things like Vectors). The teacher gave us an interface to follow and some code to test our ArrayStack on. My problem is that when I create a stack, fill it with 100 elements then empty it the size is 4 (i set 4 for a minimum) and when the teacher code do the same (in the testStack function) the same check fails.
Heres my code:
#include <iostream>
#include <string>
#include <assert.h>
using namespace std;
template<typename T>
class Stack {
public:
// Adds new element to the top of the stack
virtual void push(T x) = 0;
// Returns the top element AND removes it from the stack
// If the stack is empty use 'throw std::out_of_range("<human_friendly_message>");'
virtual T pop() = 0;
// Returns the top element but does NOT remove it from the stack
// If the stack is empty use 'throw std::out_of_range("<human_friendly_message>");'
virtual T top() = 0;
// Returns the current number of elements in the stack
virtual int getSize() = 0;
// Returns the current capacity of the underlying data storage (array)
virtual int getCapacity() = 0;
// Returns true if the stack has no elements and false otherwise
virtual bool isEmpty() = 0;
};
template<typename T>
class ArrayStack : public Stack<T>{
private:
T* data;
int arraysize;
int N;
void resize(int capacity)
{
T* copy = new T[capacity];
for (int i = 0; i < N; i++)
copy[i] = data[i];
T* p = data;
data = copy;
delete [] p;
}
public:
ArrayStack(){
N = 0;
data = new T[4];
arraysize = 4;
}
ArrayStack(int n){
if (n < 1) n = 1;
N = 0;
data = new T[n];
arraysize = n;
}
bool isEmpty(){ return N == 0; }
void push(T x)
{
if (N == arraysize)
{
resize(2 * arraysize);
arraysize *= 2;
}
data[N] = x;
N++;
}
T pop()
{
if (isEmpty()){
throw out_of_range("Can't pop on empty stack");
}
else{
N--;
T k;
k = data[N];
if (N > 0 && N == arraysize / 4 && arraysize/2>=4)
{
resize(arraysize / 2);
arraysize /= 2;
}
return k;
}
}
T top()
{
if (isEmpty()) throw out_of_range("Can't top on empty stack");
return data[N - 1];
}
int getCapacity()
{
return arraysize;
}
int getSize()
{
return N;
}
~ArrayStack()
{
delete [] data;
}
};
template<class T>
void testStack(Stack<T> *& stack, int cap = 128) {
for (int i = 0; i < 100; i++) {
stack->push(i);
assert(stack->top() == i);
}
assert(stack->getCapacity() == cap);
assert(stack->getSize() == 100);
for (int i = 99; i >= 0; i--) {
assert(stack->top() == i);
stack->pop();
}
assert(stack->getCapacity() == 4);
assert(stack->isEmpty());
}
int main() {
try {
Stack<int> * stackI = new ArrayStack<int>();
testStack(stackI);
delete stackI;
Stack<float> * stackF = new ArrayStack<float>(1);
testStack(stackF);
delete stackF;
Stack<double> * stackD = new ArrayStack<double>(65536);
testStack(stackD, 65536);
delete stackD;
Stack<string> * stackS = new ArrayStack<string>();
stackS->push("string1");
stackS->push("string2");
stackS->push("string3");
stackS->push("string4");
for (int i = 0; i < 4; i++) {
stackS->pop();
}
assert(stackS->isEmpty());
cout << "All tests passed!" << endl;
}
catch (std::exception & ex) {
cout << ex.what() << endl;
}
return 0;
}
As you may have noticed, the problem occurs with the last stack, the one with an initial capacity of 65536.
If you print the capacity just before the failed assertion, you will notice that it's 65536.
It looks like the stack hasn't been resized at all.
Looking at your conditions for when to shrink the storage, there is a required condition that N == arraysize / 4.
Since N doesn't become greater than 100, and 65536 / 4 is 16384, this condition will never be true.
Replacing == with <= takes care of it:
N <= arraysize / 4
Related
So, here is the header file where I implemented my own vector class in a simple way.
The problem is that even though the code compiles, the member functions pushBack and insert both do not work properly.
I'd be really glad if anyone can figure out the problem in my code or find some ways how I can get this problem resolved.
#include <iostream>
#include <new>
using namespace std;
template <typename T>
class DiyVector
{
public:
DiyVector()
{
arr = new T[1];
arrSize = 0;
index = 0;
capacity = 1;
}
~DiyVector()
{
delete[] arr;
}
T& at(unsigned int index) const
{
if (index >= arrSize || index < 0)
{
throw OutOfRange{};
}
else
{
return arr[index];
}
}
unsigned int size() const
{
return arrSize;
}
void pushBack(const T& item)
{
if (arrSize == capacity)
{
arrTemp = new T[capacity += 1];
for (unsigned int i = 0; i < capacity; ++i)
{
arrTemp[i] = arr[i];
}
delete[] arr;
capacity++;
arr = arrTemp;
}
arr[arrSize] = item;
arrSize++;
}
void popBack()
{
if (arrSize == 0)
{
throw OutOfRange{};
}
else
{
arrSize--;
}
}
void erase(unsigned int index)
{
if (index >= arrSize || index < 0)
{
throw OutOfRange{};
}
else
{
arrTemp = new T[capacity -= 1];
for (unsigned int i = 0; i < capacity; ++i)
{
arrTemp[i] = arr[i];
}
delete[] arr;
capacity--;
arr = arrTemp;
}
}
void insert(unsigned int index, const T& item)
{
if (index >= arrSize || index < 0)
{
throw OutOfRange{};
}
else if (index == capacity)
{
pushBack(item);
}
else if (0 <= index && index <= size())
{
arr[index] = item;
}
}
class OutOfRange{};
private:
unsigned int arrSize;
unsigned int capacity;
unsigned int index;
T* arr;
T* arrTemp;
};
For starters this check in some member functions (for example including insert)
if (index >= arrSize || index < 0)
^^^^^^^^^^
does not make sense because the variable index declared as having the type unsigned int never can be negative. So you may exclude the second sub-condition of the if statement.
In the function pushBack in this loop
for (unsigned int i = 0; i < capacity; ++i)
{
arrTemp[i] = arr[i];
}
subsritute capacity for arrSize.
Also remove the statement
capacity++;
because capacity was already incremented in this statement
arrTemp = new T[capacity += 1];
Within the function insert change this code snippet
else if (index == capacity)
{
pushBack(item);
}
else if (0 <= index && index <= size())
{
arr[index] = item;
}
to
if ( arrSize <= index )
{
pushBack(item);
}
else
{
arr[index] = item;
}
And you may remove the data member
unsigned int index;
because it is not used.
Pay attention to that the member function erase is also incorrect. At least there is no need to reallocate the array and change its capacity. And again there are twice capacity is decremented.
arrTemp = new T[capacity -= 1];
//...
capacity--;
that is the function has the same defects as the function pushBack. And in the loop you are coping the erased element.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I am writing a dynamic matrix class that stores each non-zero value as a List of 3 elements [row,column,value]
I made a dynamic array class called "List", and class"Matrix" a List of list pointers.
My code to transpose the Matrix works:
void transpose(Matrix tripleList)
{
for (int i = 0; i < tripleList.getNumOfElem(); i++)
{
List* list = new List;
(*list).copy(*(tripleListMatrix.getAt(i)));
int temp = (*list).getAt(0);
(*list).set(0, (*list).getAt(1));
(*list).set(1, temp);
(*list).displayList();
cout << "\n";
}
}
it works when written directly in main() but gives error when in stand alone function. can anyone explains why and how to fix it?
Full code:
#include <iostream>
using namespace std;
class List //a dynamic int pointer array
{
private:
int capacity;
int numOfElem;
int *arr;
//initialize all values in capacity to 0
void initialize(int from)
{
for (int i = from; i < capacity; i++)
{
arr[i] = 0;
}
}
//double the capaicty, then initialize
void expand()
{
capacity *= 2;
int *tempArr = new int[capacity];
for (int i = 0; i < numOfElem; i++)
tempArr[i] = arr[i];
delete[] arr;
arr = tempArr;
initialize(numOfElem);
}
public:
List()//constructor
{
capacity = 10;
numOfElem = 0;
arr = new int[capacity];
}
~List()//destrcutor
{
delete[] arr;
}
//add int to the end of List
void append(int newElement)
{
if (numOfElem >= capacity)
expand();
arr[numOfElem++] = newElement;
}
//Copy all element of an input list to the end of List
void copy(List list)
{
for (int i = 0; i < list.getNumOfElem(); i++)
{
if (numOfElem >= capacity)
expand();
arr[numOfElem++] = list.getAt(i);
}
}
//get reference of the int at an index in te list
int* getAddress(int index)
{
if (index < 0 || index >= numOfElem)
throw ("Out of bounds exception!!!");
return &arr[index];
}
//change the value of at specific index
void set(int index, int value)
{
arr[index] = value;
}
//get int at an index in te list
int getAt(int index)
{
if (index < 0 || index >= numOfElem)
throw ("Out of bounds exception!!!");
return arr[index];
}
int getNumOfElem()
{
return numOfElem;
}
void displayList()
{
for (int i = 0; i < numOfElem; i++)
{
cout << arr[i] << " ";
}
}
};
class Matrix //a List of list pointers
{
private:
int capacity;
int numOfElem;
List* *arr;
void initialize(int from)
{
for (int i = from; i < capacity; i++)
{
arr[i] = new List;
}
}
void expand()
{
capacity *= 2;
List* *tempArr = new List*[capacity];
for (int i = 0; i < numOfElem; i++)
tempArr[i] = arr[i];
delete[] arr;
arr = tempArr;
initialize(numOfElem);
}
public:
Matrix()
{
capacity = 10;
numOfElem = 0;
arr = new List*[capacity];
}
~Matrix()
{
delete[] arr;
}
void append(List* newElement)
{
if (numOfElem >= capacity)
expand();
arr[numOfElem++] = newElement;
}
void set(int index, List* value)
{
arr[index] = value;
}
List* getAt(int index)
{
if (index < 0 || index >= numOfElem)
throw ("Out of bounds exception!!!");
return arr[index];
}
int getNumOfElem()
{
return numOfElem;
}
};
void transpose(Matrix tripleList)
{
for (int i = 0; i < tripleList.getNumOfElem(); i++)
{
{
List* list = new List;
(*list).copy(*(tripleListMatrix.getAt(i)));
int temp = (*list).getAt(0);
(*list).set(0, (*list).getAt(1));
(*list).set(1, temp);
(*list).displayList();
cout << "\n";
}
}
int main()
{
int m, n, input;
cout << "Please enter the number of rows and columns of the matrix :\n";
cin >> m >> n;
Matrix tripleListMatrix;
int k = 0;
cout << "Please enter the matrix : \n";
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
cin >> input;
if (input != 0)
{
tripleListMatrix.append(new List);
(*(tripleListMatrix.getAt(k))).append(i + 1);
(*(tripleListMatrix.getAt(k))).append(j + 1);
(*(tripleListMatrix.getAt(k))).append(input);
k++;
}
}
}
cout << "The triple list of matrix is:\n";
for (int i = 0; i < tripleListMatrix.getNumOfElem(); i++)
{
(*(tripleListMatrix.getAt(i))).displayList();
cout << "\n";
}
cout << "\n\n";
//transpose(tripleListMatrix);
//the code below is the same as in the function transpose but transpose gives error
for (int i = 0; i < tripleListMatrix.getNumOfElem(); i++)
{
List* list = new List;
(*list).copy(*(tripleListMatrix.getAt(i)));
int temp = (*list).getAt(0);
(*list).set(0, (*list).getAt(1));
(*list).set(1, temp);
(*list).displayList();
//cout << "\t" << list;
cout << "\n";
}
cout << "\n\n";
//checking that tripleListMatrix is unchanged
for (int i = 0; i < tripleListMatrix.getNumOfElem(); i++)
{
(*(tripleListMatrix.getAt(i))).displayList();
cout << "\n";
}
return 0;
}
List* *arr;
When you call transpose(), it makes a copy Matrix because you're not passing by reference. That copy just has a copy of the address for your List, not it's own List object. When the destructor runs on the copy, it clears up the allocated memory, but the original Matrix object in main still points to that same memory. When that object goes away, its destructor tries to free the same memory again and that's bad.
You probably meant:
void transpose(Matrix const & tripleList)
So that no copy is made when calling transpose(), but you should also explicitly delete the copy construtor of Matrix so it cannot be called
Matrix(Matrix const &) = delete;
or make an explicit Matrix copy constructor that makes a deep copy of the memory.
I've been trying to make a dynamic array. My main method calls push_back() to add ints to an array 50 times. The push_back() method calls the grow_if_needed() method if the size of the array needs to be doubled. The size() method returns the current capacity of the array. And the toString method is for printing the array as a string. I keep getting this error at the end of the grow_if_needed() method.
#include <string>
class ArrayList
{
private:
static int capacity;
static int count;
public:
int& operator [](int i);
int *arrayPtr = new int[1];
ArrayList();
int * push_back(int m);
int * grow_if_needed();
int * erase(int m);
int size();
std::string toString();
};
#include "ArrayList.h"
using namespace std;
int ArrayList::capacity = 1;
int ArrayList::count = 0;
int & ArrayList::operator[](int i)
{
return arrayPtr[i];
}
ArrayList::ArrayList()
{
arrayPtr[0] = 0;
}
int * ArrayList::push_back(int m)
{
if (count == size()) {
grow_if_needed();
}
for (int i = size() - 1; i >= 0; i--) {
arrayPtr[i + 1] = arrayPtr[i];
}
arrayPtr[0] = m;
count++;
return arrayPtr;
}
int * ArrayList::grow_if_needed() {
int k;
capacity = size() * 2;
int * tempArray = new int[capacity];
for (k = 0; k < count; k++) {
tempArray[k] = arrayPtr[k];
}
while (k != capacity) {
tempArray[k] = 0;
k++;
}
delete [] arrayPtr;
arrayPtr = tempArray;
return arrayPtr;
}
int ArrayList::size()
{
return capacity;
}
string ArrayList::toString()
{
string num = "";
for (int i = 0; i <= size() - 1; i++) {
num += std::to_string(arrayPtr[i]) + " ";
}
return num;
}
In your push_back function you have this loop:
for (int i = size() - 1; i >= 0; i--) {
arrayPtr[i + 1] = arrayPtr[i];
}
Here size() - 1 is the top index, so in the first iteration when you do i + 1 you are out of bounds.
Also, this function is called push_back, but it attempts to add to the front? If it added to the end (the "back") you would not need the loop, and your problem would "magically" disappear.
Im trying to implement one of the Vector's Functions which is Resize
As much as I know all the other functions that I implemented are alright
In the test code I tried to print out every possible situation that might happen but when I came to print the size of the new Vector (poitner to integer called _elements)
I get an error "#.exr Triggered a breakpoint
for some odd reason in the tester (main) when i set at the loop "i <8" it works fine but if I do <= it triggers it
I believe the is caused by the resize function but Even after following the debugger I cant seem to find the problem
(explenation of the funtion is in the code)
the vector that I created was successfuly intelized for those who might wonder
Why is this happening?
the function with the following inputs / outputs are:
Vector::Vector(const Vector& other)
{
_elements = new int;
_size = other._size;
_capacity = other._capacity;
_resizeFactor = other._resizeFactor;
for (int i = 0; i < _size; ++i)
{
_elements[i] = other._elements[i];
}
}
//change _size to n, unless n is greater than the vector's capacity
//same as above, if new elements added their value is val
void Vector::resize(int n, const int& val)
{
if (n <= _capacity)
{
while (n < _size)
{
pop_back();
}
while (n > _size)
{
push_back(val);
}
_capacity = n;
}
else if (n > _capacity)
{
reserve(n);
while (n > _size)
{
push_back(val);
}
}
}
//change the capacity
void Vector::reserve(int n)
{
if (n > _capacity)
{
int size = _resizeFactor;
while (n - _capacity > size)
{
size = size + _resizeFactor;
}
_capacity += size;
}
}
//adds element at the end of the vector
void Vector::push_back(const int& val)
{
if (_size < _capacity)
{
_elements[_size] = val;
_size++;
}
else if (_size == _capacity)
{
int* a = new int[_capacity + _resizeFactor];
for (int i = 0; i < _size; i++)
{
a[i] = _elements[i];
}
_capacity += _resizeFactor;
_elements = new int[_capacity];
for (int i = 0; i < _size; i++)
{
_elements[i] = a[i];
}
delete a;
_elements[_size] = val;
_size++;
}
}
void Vector::pop_back()
{
if (_size > 0)
{
_elements[_size] = NULL;
_size--;
}
}
and I check it with
void print(const Vector& p)
{
cout << "Size = " << p.size() << ", Capacity = " << p.capacity() << ", isEmpty = " << (p.empty() ? "True" : "False") << endl;
}
and in main:
Vector a(10);
for (int i = 0; i <= 8; i++)
a.push_back(i+1);
print(a);
a.push_back(10);
print(a);
a.push_back(11);
print(a);
int x = 99;
a.resize(a.capacity() + 11, x);
print(a);
For a C++ class I am taking, I am creating a Vector Library. We are not allowed to use the built in vector library, of course, and I have decided to use arrays in my 'myvector' class.
I am currently trying to test my code and I am not sure how to create an object of class myvector.
The error I get is Incomplete type is not allowed.
main.cpp:
#include "my_vectorHeader.h"
using namespace std;
int main(){
myvector<int> vector = new myvector<int>(3);
}
my_vectorLib.cpp:
#include "my_vectorHeader.h"
#include iostream
#include exception
using namespace std;
template<typename T> class myvector {
private:
int vector_size, //holds current size
vector_capacity; //holds current capacity
public:
//constructors
myvector<T>(int length){
T vector[length];
vector_size = length;
vector_capacity = length;
}
myvector<T>(const T& doppelganger){
T vector = doppelganger;
while(vector[vector_size] != NULL)
vector_size++;
}
myvector<T>(const T& dat_arr, int arr_size){
vector_size = arr_size;
vector_capacity = arr_size;
for(int i = 0; i < arr_size; i++)
vector[i] = dat_arr[i];
}
~myvector(){ //destructor
delete [] vector;
delete myvector;
}
myvector& myvector::operator[](int index){ //override []
try{
throw vector[index];
} catch(exception e){
cout << e.what() << endl;
}
return vector[index];
}
T at(int index){
return vector[index];
}
int size(){
return vector_size;
}
int capacity(){
return vector_capacity;
}
bool empty(){
if(size() > 0)
return false;
else
return true;
}
void resize(int new_size){
T vector_copy[new_size];
for(int i = 0; i < new_size; i++){
if(i >= vector_size)
vector_copy[i] = NULL;
else
vector_copy[i] = vector[i];
if(new_size > capacity)
capacity = new_size;
}
vector_size = new_size;
delete [] vector;
T *vector;
vector = vector_copy;
for(int i = 0; i < vector_size; i++)
vector[i] = vector_copy[i];
delete [] vector_copy;
}
void reserve(int new_capacity){
if(new_capacity < vector_size){
cout << "Error. Newly provided vector capacity is smaller than the current vector size. The capacity is " << vector_capacity << " and has not been changed.";
} else {
vector_capacity = new_capacity;
}
}
T pop_back(){
T return_val = vector[size() - 1];
resize(size() - 1);
return return_val;
}
void push_back(T new_val){
resize(size() + 1);
vector[size() - 1] = new_val;
}
void assign(int position, T new_val){
vector[position] = new_val;
}
void clear(){
for(int i = 0; i < size(); i++)
vector[i] = NULL;
}
void erase(int position){
vector[position] = NULL;
do{
vector[position] = vector[position + 1];
}while(position != NULL);
resize(size() - 1);
}
void erase(int in, int between){
int i = in + 1, j = between;
while(i < between){
vector[i] = vector[j];
vector[j] = NULL;
i++, j++;
}
resize(between);
}
void insert(int index, T new_val){
for(int i = size + 1; i > index; i--)
vector[i] = vector[i - 1];
vector[index] = new_val;
}
};
Declaration and implementation of templates should be in the same file(or implementation should be included too). Also this
myvector<int> vector = new myvector<int>(3);
is incorrect(new returns pointer) and unnecessary. Just use
myvector<int> vector(3);
Put the class (all the code) found at my_vectorLib.cpp in your my_vectorLib.h As #soon pointed you, templates classes (unless specialized) need to be at the header file (the one you include at main.cpp which where the class is instantiated, which means the compiler generates the actual code when you use the template).