dynamic memory allocation with arrays in c++ - c++

I am trying to insert an int into an array that is in a class object, and I cannot figure out what I am doing wrong. The current state of my code never inserts the int into the array.
Basically what I am trying to do is when i call insert(int) it will check to to see if there is any room left in the array, and if there is it will add it, otherwise it would reallocate with 8 more spaces in the array.
here is some relevant class info
private:
unsigned Cap; // Current capacity of the set
unsigned Num; // Current count of items in the set
int * Pool; // Pointer to array holding the items
public:
// Return information about the set
//
bool is_empty() const { return Num == 0; }
unsigned size() const { return Num; }
unsigned capacity() const { return Cap; }
// Initialize the set to empty
//
Set()
{
Cap = Num = 0;
Pool = NULL;
}
here is the code i am working on
bool Set::insert(int X)
{
bool Flag = false;
if (Num == Cap)
{
//reallocate
const unsigned Inc = 8;
int * Temp = new int[Cap+Inc];
for (unsigned J=0;J<Num;J++)
{
Temp[J] = Pool[J];
}
delete [] Pool;
Pool = Temp;
Cap = Cap+Inc;
}
if(Num < Cap)
{
Pool[Num+1] = X;
Flag = true;
}
return Flag;
}

Your insert function never updates Num. Try Pool[Num++] = X; or something like that.

You probably want to increment the number of element but only after copying the new element in: the first element should have index 0. Basically, your insert() function should look something like this:
bool Set::insert(int X)
{
if (Num == Cap)
{
const unsigned Inc(std::max(8, 2 * Cap));
std::unique_ptr<int[]> Temp(new int[Cap+Inc]);
std::copy(Pool.get(), Pool.get() + Num, Temp.get());
Pool.swap(Temp);
Cap += Inc;
}
Pool[Num] = X;
++Num;
return true;
}
Of course, this assumes that Pool is reasonably declared as std::unique_ptr<int[]> (or something with similar functionality which is easy to write if necessary). The reason to use std::unique_ptr<int[]> rather than raw pointers is that they automatically clean up resources when they are destroyed. Copying a sequence of ints won't throw an exception but if int get's replaced by a std::string or a template parameters there is potential to throw exceptions.

Related

Arrays with unknown size on Arduino

I'm doing an Arduino project and I need to pass arrays with different sizes as parameter to my function.
The problem is that std::vector is not an option.
How can I do that?
The fallback is to pass a pointer to the first element in the array and the size:
void foo(int* arr, size_t size);
The reason for std::vector not being available on some platforms is that on some platforms dynamic allocations is a bad idea. However, once you are dynamically allocating arrays:
int* x = new int[42];
foo(arr,42); // array decays to pointer
delete[] x;
then you could as well use std::vector.
If std::vector is not available to you, then either search for an alternative (maybe this?) or write your own. The pointer + size approach is fragile and not recommended unless absolutely necessary. The power of std::vector is from the abstract concept to encapsulate the array, its size and capacity. Nobody can prevent you to apply that concept even if you cannot use std::vector.
In case you are talking about statically sized arrays, then thats not quite the use case for std::vector. You do not need dynamic allocation, and you can pass arrays by reference. I won't repeat here what you can find in this answer (std::array) or here (c-arrays).
Something like this should work
template<size_t N>
void DaFunction(std::array<int, N>& daArray)
you can do it without having to deal with memory allocation or pointers just by creating a string variable and a limited size array and then you start shifting
#include <Arduino.h>
class ArrayShifter
{
private:
// String Reservoire Tank
String _text;
// a fixed size array of 5 in my case (depending on the amount of data you expect)
String _viewPortArray[5];
int _size = 0;
// Methode to fill the array
bool shiftArray(int position);
public:
ArrayShifter(/* args */);
// Method that gets the text from Serial
String getSerialText();
// get data from the array
String getArrayData(int index);
// array size getter
int getSize();
//clear the array
void clearArray();
//remove item
void removeArrayItem(int index);
};
ArrayShifter::ArrayShifter(/* args */)
{
}
String ArrayShifter::getSerialText()
{
// lesteing to the serial and returning the value
_text = Serial.readString();
return _text;
}
bool ArrayShifter::shiftArray(int position)
{
/*Assuming that the data is comming separated with ";" for each row and ":" for each value
to optimize the size of array in this way :
name:value;age:value;gender:value;
*/
String text = getSerialText();
int index = 0;
_size = 0;
if (text.length() > 0) // text isn't empty
{
if (position <= 5) // if the data belongs to the first 5 range
{
for (int i = 0; i < 5; i++)
{
// get the index of our separator that we've chosed to be ";"
index = text.indexOf(";");
if (index > 0)
{
// index found
_size++;
// putting the value before ";" in the array
_viewPortArray[i] = text.substring(0, index);
// deleting the value from the tank
text = text.substring(index + 1);
}
}
}
else
{
_size = 0;
// to wich range the desired index belongs
unsigned int dataRange = ((position - position % 5));
int ghostIndex = 0;
// looping throught all ";" to get indexes
for (int i = 0; i < dataRange; i++)
{
ghostIndex = text.indexOf(";");
if (ghostIndex > 0)
{
_size++;
text = text.substring(ghostIndex + 1);
}
}
// grabing just 5 of the data
for (int i = 0; i < 5; i++)
{
if (ghostIndex > 0)
{
_size++;
_viewPortArray[i] = text.substring(0, ghostIndex);
text = text.substring(ghostIndex + 1);
}
// updating ghost index
ghostIndex = text.indexOf(';');
}
}
return true;
}
return false;
}
String ArrayShifter::getArrayData(int index)
{
// turn the roulette
if (shiftArray(index))
{
if (index <= 5)
{
// yes we have this
return _viewPortArray[index];
}
else
{
// but we have to put it in the range of 5
index = index - 5;
return _viewPortArray[index];
}
}
}
int ArrayShifter::getSize()
{
return _size;
}
void ArrayShifter::clearArray()
{
for(int i = 0 ; i <5 ; i ++)
{
_viewPortArray->remove(i);
_size = 0;
}
}
void ArrayShifter::removeArrayItem(int index)
{
_viewPortArray->remove(index);
_size--;
}
main class :
#include <Arduino.h>
#include <ArrayShifter.h>
ArrayShifter array;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
while (!Serial){}
}
void loop() {
if(Serial.available()>0)
{
Serial.println(array.getArrayData(7));
int sizeOption2 = array.getSize();
Serial.println(sizeOption2);
array.removeArrayItem(7);
Serial.println(array.getArrayData(7));
}
}
please check my github repository
https://github.com/Riadam/ViewPort-Array-Shifter-for-Arduino-Uno.git

C++ circular array queue setCapacity

I am working on an assignment that involves me writing a template class for a queue. It uses a dynamically allocated array. I am having trouble with the copying of the array. This is the prompt.
aQueue.setCapacity(newCapacity), that changes the capacity of aQueue to newCapacity. (This is much trickier than Stack::setCapacity(): if newCapacity is zero or < getSize(), setCapacity() should throw an exception; otherwise, it should allocate a new array with the new capacity, copy the values from the old array into the new array, and deallocate the old array.) To help you see all the things that can go wrong, you should make certain your method passes all the tests in this test method before working on the rest of the project.
Instance variables are:
unsigned mySize; // number of items I contain
unsigned myCapacity; // how many items I can store
unsigned myFirst; // index of oldest item (if any)
unsigned myLast; // index of next available spot for append (if any)
Item* myArray; // dynamic array of items
This is what I have so far:
template <class Item>
void ArrayQueue<Item>::setCapacity(unsigned newCapacity) {
if (newCapacity == 0 || newCapacity < mySize) {
throw QueueException("setCapacity()","newCapacity is too small");
} else {
Item * newArray = new Item[newCapacity];
unsigned y = myFirst;
for (unsigned x = 0; x < mySize; x++) {
newArray[y] = myArray[x];
y++;
}
delete [] myArray;
myArray = newArray;
myCapacity = newCapacity;
myLast = y;
}
}
These are the methods for getFirst() and getLast():
// Method returns first Item in ArrayQueue
template <class Item>
unsigned ArrayQueue<Item>::getFirst() const {
if (this->isEmpty()) {
throw EmptyQueueException("getFirst()");
} else {
return myArray[myFirst];
}
}
// Method returns last Item in ArrayQueue
template <class Item>
unsigned ArrayQueue<Item>::getLast() const {
if (this->isEmpty()) {
throw EmptyQueueException("getLast()");
} else {
return myArray[(myLast - 1 + myCapacity) % myCapacity];
}
}
I have been working on this for hours so any help would be greatly appreciated.
Credit goes to: Aconcagua
for (unsigned x = 0; x < mySize; x++) {
newArray[x] = myArray[(y % myCapacity)];
y++;
}
delete [] myArray;
myArray = newArray;
myCapacity = newCapacity;
myFirst = 0;
myLast = mySize;
By setting myFirst to 0 and myLast to mySize this properly allocates the indexes correctly. In addition to this when copying the array you most set newArray[x] to myArray[(y % myCapacity)].

Need to reference and update value from nested class C++

Bear with me, I'm new to C++. I'm trying to update a value which is stored in a vector, but I'm getting this error:
non-const lvalue reference to type 'Node'
I'm using a simple wrapper around std::vector so I can share methods like contains and others (similar to how the ArrayList is in Java).
#include <vector>
using namespace std;
template <class T> class NewFrames {
public:
// truncated ...
bool contains(T data) {
for(int i = 0; i < this->vec->size(); i++) {
if(this->vec->at(i) == data) {
return true;
}
}
return false;
}
int indexOf(T data) {
for(int i = 0; i < this->vec->size(); i++) {
if(this->vec->at(i) == data) {
return i;
}
}
return -1;
}
T get(int index) {
if(index > this->vec->size()) {
throw std::out_of_range("Cannot get index that exceeds the capacity");
}
return this->vec->at(index);
}
private:
vector<T> *vec;
};
#endif // A2_NEWFRAMES_H
The class which utilizes this wrapper is defined as follows:
#include "Page.h"
#include "NewFrames.h"
class Algo {
private:
typedef struct Node {
unsigned reference:1;
int data;
unsigned long _time;
Node() { }
Node(int data) {
this->data = data;
this->reference = 0;
this->_time = (unsigned long) time(NULL);
}
} Node;
unsigned _faults;
Page page;
NewFrames<Node> *frames;
};
I'm at a point where I need to reference one of the Node objects inside of the vector, but I need to be able to change reference to a different value. From what I've found on SO, I need to do this:
const Node &n = this->frames->get(this->frames->indexOf(data));
I've tried just using:
Node n = this->frames->get(this->frames->indexOf(data));
n.reference = 1;
and then viewing the data in the debugger, but the value is not updated when I check later on. Consider this:
const int data = this->page.pages[i];
const bool contains = this->frames->contains(Node(data));
Node node = this->frames->get(index);
for(unsigned i = 0; i < this->page.pages.size(); i++) {
if(node == NULL && !contains) {
// add node
} else if(contains) {
Node n = this->frames->get(this->frames->indexOf(data));
if(n.reference == 0) {
n.reference = 1;
} else {
n.reference = 0;
}
} else {
// do other stuff
}
}
With subsequent passes of the loop, the node with that particular data value is somehow different.
But if I attempt to change n.reference, I'll get an error because const is preventing the object from changing. Is there a way I can get this node so I can change it? I'm coming from the friendly Java world where something like this would work, but I want to know/understand why this doesn't work in C++.
Node n = this->frames->get(this->frames->indexOf(data));
n.reference = 1;
This copies the Node from frames and stores the copy as the object n. Modifying the copy does not change the original node.
The simplest "fix" is to use a reference. That means changing the return type of get from T to T&, and changing the previous two lines to
Node& n = this->frames->get(this->frames->indexOf(data));
n.reference = 1;
That should get the code to work. But there is so much indirection in the code that there are likely to be other problems that haven't shown up yet. As #nwp said in a comment, using vector<T> instead of vector<T>* will save you many headaches.
And while I'm giving style advice, get rid of those this->s; they're just noise. And simplify the belt-and-suspenders validity checks: when you loop from 0 to vec.size() you don't need to check that the index is okay when you access the element; change vec.at(i) to vec[i]. And in get, note that vec.at(index) will throw an exception if index is out of bounds, so you can either skip the initial range check or keep the check (after fixing it so that it checks the actual range) and, again, use vec[index] instead of vec.at(index).

How to Copy Data from One Array to Another Without Names? (C++)

I'm working on an assignment right now and have run into a roadblock. The assignment is an array list in C++ that dynamically expands by a factor of 2 every time it runs out of room to store new elements (initially starts with room for 2 elements). Here is the code I'm working on (some of it is included in a separate .h file provided by the professor, I won't post everything in order to keep this compact).
#include "array_list.h"
//initial size to create storage array
static const unsigned int INIT_SIZE = 2;
//factor to increase storage by when it gets too small
static const unsigned int GROW_FACTOR = 2;
unsigned int growthTracker = 1;
array_list::array_list()
{
m_storage = new unsigned int[INIT_SIZE];
m_capacity = INIT_SIZE;
m_current = -1;
m_size = 0;
}
array_list::~array_list()
{
delete m_storage;
}
void array_list::clear()
{
delete m_storage;
m_storage = new unsigned int[INIT_SIZE];
m_capacity = INIT_SIZE;
m_current = -1;
m_size = 0;
}
unsigned int array_list::size() const
{
return m_size;
}
bool array_list::empty() const
{
bool A = 0;
if(m_size == 0)
{
A = 1;
}
return A;
}
void array_list::insert(const unsigned int val)
{
m_storage[m_size++] = val;
m_current = m_size;
}
void array_list::grow_and_copy()
{
if(m_size == m_capacity)
{
new unsigned int[INIT_SIZE * (GROW_FACTOR ^ growthTracker)];
growthTracker++;
m_capacity = m_capacity * 2;
}
m_storage[m_size++] = val;
}
Now, my problem is trying to figure out how to copy the values of the old, smaller array into the new, larger one. If I wasn't using dynamic unnamed arrays, this would be very easy to do with a loop, a simple case of "for a certain range, arrayA[i] = arrayB[i]." However, because the arrays are just defined as new unsigned int[], I'm not sure how to go about this. There are no names, so I can't figure out how to tell C++ which array to copy into which. And since the grow_and_copy could be called multiple times, I'm fairly sure I can't give them names, right? Because then I would end up with multiple arrays with the same name. Can anyone point me in the right direction here? Thanks so much.
array_list::growList(int increase = GROW_FACTOR)
{
unsigned int* temp = m_storage;
m_storage = new unsigned int[m_capacity * increase];
for (int i = 0; i < m_capacity; i++)
m_storage[i] = temp[i];
m_capacity *= increase;
delete temp;
}
I don't know if there are other variables you want to change, but this should basically do what you are asking.

No Appropriate Default Constructor Available despite default constructor made?

Trying to make my own Map struct to store my own-created 'Strings,' and after 8 hours or so finally got it down to only a few compiler errors (six of them). I've spent the last hour and forty minutes searching the web for answers, only to find people forgot default constructors, and tried mixing things up in my own program. Since I'm not really sure where the problem is in advance, I apologize for posting all this code...I put what I thought were the most relevant files first; I think only the first 3 are necessary. The error is
"SubdomainPart' : No appropriate default constructor available" for lines 12 and 20 of the Map.h file.
Map.h
// Map.h - Map template class declaration
// Written by -----
#pragma once
template<typename KEY_TYPE, typename VALUE_TYPE>
struct Map
{
public:
// Default / initial constructor hybrid
Map(int initialCapacity = 10)
{
Size = 0;
Capacity = initialCapacity;
Key;
MappedValue;
//Allocate the C-Array elements using HEAP
Data = new VALUE_TYPE[Capacity];
}
struct iterator
{
KEY_TYPE * current;
KEY_TYPE * prev;
KEY_TYPE * next;
iterator operator ++ ()
{
iterator it = this;
iterator itNext = it.next;
it.next = itNext.next; // pushes iterator forward.
it.prev = it.current;
it.current = it.next;
}
iterator operator -- ()
{
iterator it = this;
iterator itPrev = it.prev;
it.prev = itPrev.prev; // pushes iterator backward.
it.next = it.current;
it.current = it.prev;
}
};
Map(const Map& copyFrom)
{
// Necessary to prevent the delete[] Data; statement in the assignment operator from
// freezing because Data has some garbage address in it.
Data = NULL;
*this = copyFrom; //'this' points to the current instance of the object. (in this case, 'Map')
}
// Destructor: MUST HAVE because we allocate memory
~Map()
{
delete[] Data;
}
Map& operator = (const Map& copyFrom)
{
// 0) delete the old one!
delete[] Data;
// 1) copy Size and Capacity
Size = copyFrom.Size;
Capacity = copyFrom.Capacity;
// 2) Allocate Memory
Map* Data = new Map[Capacity];
// 3) Copy the Map Elements
for(int i = 0; i<Size; i++)
Data[i] = copyFrom.Data[i];
return *this;
}
// Index Operator
VALUE_TYPE& operator[] (KEY_TYPE key) const
{
return Data[key];
}
// Accessor functions: read-only access to Size and Capacity
int GetSize() const //const does not modify ANY data members of the class (size, capacity, or data)
{
return Size;
}
int GetCapacity() const
{
return Capacity;
}
void PushBack(const VALUE_TYPE& newElement) //adds value to end of Map as default
{
if(Size >= Capacity)
increaseCapacity(2 * Capacity);
Data[Size] = newElement;
Size++; // increases size of the array so it can be used later.
}
// Overloaded Add function, inserts a value at specified index, calls in "Insert" to do so.
void Add(const VALUE_TYPE& newElement, int index)
{
if( (index<0) || (index > Size))
{
throw ("Index to insert is out of range");
}
//Make sure there's space!
if (Size >= Capacity)
increaseCapacity(2*Capacity); //increase size of array if too small!
Insert(index, newElement);
}
void Remove(int index) // index = index to be removed.
{
// Make sure it's inside the bounds
if( (index<0) || (index > Size))
{
throw ("Index to Remove is out of range.");
}
// it's going to remove the unneeded space by having its capacity one above the Size.
Map* new_Data = new Map[Size];
//Copy data onto new pointer section.
for(int x = 0; x<Size; x++)
new_Data[x] = Data[x];
delete[] Data; //deallocates old memory and uneeded capacity slots.
for(int x = index; x < (Size - 1); x++) //removes the value at index 'index.' Now Data has a capacity of the amount of slots used and one more for a NULL value.
new_Data[x] = new_Data[x+1];
Data = new_Data;
Data[Size-1] = NULL;
Size--;
}
void increaseCapacity(int new_capacity)
{
if(new_capacity>Capacity)
{
if(new_capacity> 2* Capacity)
Capacity = new_capacity;
else
Capacity *= 2;
//create Map with a new capacity!
Map* new_Map = new Map[Capacity];
for(int x = 0; x<Size; x++)
{
new_Map[x] = Data[x];
}
//clear out old memory
delete[] Data;
//set data pointer to the new Map
Data = new_Map;
}
}
KEY_TYPE * Key; // Used to identify mapped values.
VALUE_TYPE MappedValue; // The value actually contained.
private:
int Size; // The count of actual C-Array elements used
int Capacity; // The count of C-array elements allocated
// The encapsulated C-array
VALUE_TYPE * Data; // pointer of type 'DATA_TYPE' called data (will be name of our array).
void Insert(const int index, const VALUE_TYPE& insertValue)
{
if( (index<0) || (index > Size))
{
throw out_of_range ("Index to insert is out of range");
}
//Time to shuffle the array down!
for(int x = Size; x>index; x--)
{
Data[x] = Data[x-1];
}
//Insert the new item at index 'Index!'
Data[index] = insertValue;
Size++;
}
};
SubdomainPart.h
// SubdomainPart.h - SubdomainPart validation class declaration
// Written by -------
#pragma once
#include "String.h"
using namespace std;
class SubdomainPart
{
public:
// Takes the address and stores into the Address data member
SubdomainPart(const String& address);
// Returns true when the Address is valid or false otherwise
virtual bool IsValid();
private:
String Address;
};
SubdomainPart.cpp
// SubdomainPart.cpp - Subdomain validation class implementation
// Written by ---------
#pragma once
#include "SubdomainPart.h"
// Takes the address and stores into the Address data member
SubdomainPart::SubdomainPart(const String& address)
{
Address = address;
}
// Returns true when the Address is valid or false otherwise
bool SubdomainPart::IsValid()
{
int currentDotIndex = 0;
int nextDotIndex = 0;
int found = 0; // first index of a found invalid character
int hyphenIndex = 0; // used to check hyphen rule
// 1. Check the size, 255 total characters
if(Address.GetLength() < 1 || Address.GetLength() > 255)
return false;
// Checks for valid amount of 1-63 characters between dots
currentDotIndex = Address.FindFirstOf('.');
if(currentDotIndex == 0 || currentDotIndex == Address.GetLength()-1)
return false;
else if(currentDotIndex!=(-1))
nextDotIndex = Address.Find('.', currentDotIndex+1);
else
nextDotIndex = (-1); // if no '.' is found, ensures the following loop doesn't run.
while(nextDotIndex!=(-1))
{
if((nextDotIndex-currentDotIndex) == 1 || (nextDotIndex-currentDotIndex) > 63)
return false;
currentDotIndex = nextDotIndex;
nextDotIndex = Address.Find('.', currentDotIndex+1);
}
// 2. Check for valid characters
found = Address.FindFirstNotOf("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890-.");
if(found!=(-1)) // if a character not listed above is found.
return false;
// 3. Check for dash rule
// Making sure hyphens aren't located at the first or last index of a subdomain.
hyphenIndex = Address.FindFirstOf('-');
if(hyphenIndex == 0)
return false;
hyphenIndex = Address.FindLastOf('-');
if(hyphenIndex == Address.GetLength()-1)
return false;
// Makes sure two hyphens aren't in a row.
for(int x = 1; x<Address.GetLength(); x++)
if(Address[x] == '-' && Address[x] == Address[x-1])
return false;
return true;
}
I don't see a default constructor in this class:
class SubdomainPart
{
public:
// Takes the address and stores into the Address data member
SubdomainPart(const String& address);
// Returns true when the Address is valid or false otherwise
virtual bool IsValid();
private:
String Address;
};
Keep in mind that this map constructor is default-constructing every member rather than initializing them:
Map(int initialCapacity = 10)
{
Size = 0;
Capacity = initialCapacity;
Key;
MappedValue;
//Allocate the C-Array elements using HEAP
Data = new VALUE_TYPE[Capacity];
}
You don't have a default constructor for SubdomainPart you have only provided a copy constructor. A default constructor takes no argument.
The compiler is complaining that SubdomainPart doesn't have a default constructor, and indeed it doesn't. It's required because your Map contains an object of type VALUE_TYPE:
VALUE_TYPE MappedValue;
Also, your Map constructor contains very weird code. I assume you actually wanted to use an initialiser list:
Map(int initialCapacity = 10)
: Key()
, MappedValue()
, Size(0)
, Capacity(initialCapacity)
, Data(new VALUE_TYPE[Capacity])
{}
The problem is with Data = new VALUE_TYPE[Capacity]; part.
The compiler generates code to allocate the array and instantiate each element by calling the parameterless constructor for VALUE_TYPE. As SubdomainPart doesn't have one (since you have defined a custom one), the compiler throws an error.
The reason that compiler reports error in map.h is that it is exactly the place where the constructor is called from. It is not used in SubdomainPart code, it is just defined there.