Class of dynamically resizable C++ string array - c++

I need to create a class called DynamicArray based on the given main.cpp file. However I cannot make it work. The program crashes. I believe it should be the constructor problem. Please see the following codes with comments:
main.ccp
#include <iostream>
#include <dynamicarray.h>
using namespace std;
int main()
{
DynamicArray* arr=new DynamicArray(ARRAY_SIZE);
for (int i=0; i<25; i++) {
arr->add("test");
}
for (int j=0; j<10; j++){
arr->remove();
}
delete [] arr;
arr=NULL;
return 0;
}
dynamicarray.h
#ifndef DYNAMICARRAY_H
#define DYNAMICARRAY_H
#define ARRAY_SIZE 5
#include <iostream>
using namespace std;
class DynamicArray
{
DynamicArray* darr;
int del;
int occSize;
int totSize;
public:
DynamicArray();
~DynamicArray();
DynamicArray(int);
void add(string);
void remove();
int totalSize();
int occupiedSize();
DynamicArray operator= (string);
DynamicArray operator= (int);
};
#endif // DYNAMICARRAY_H
dynamicarray.cpp
#include "dynamicarray.h"
DynamicArray::DynamicArray()
{
darr=new DynamicArray[ARRAY_SIZE];
del=0;
occSize=0;
totSize=ARRAY_SIZE;
}
DynamicArray::DynamicArray(int n){
darr=new DynamicArray[n];
del=0;
occSize=0;
totSize=ARRAY_SIZE;
}
DynamicArray::~DynamicArray()
{
delete [] darr;
darr=NULL;
}
//adding s to the next available slot in the array. When the array is full,
//add() will grow the array by another ARRAY_SIZE
void DynamicArray::add(string s){
if (occSize<totSize){
darr[occSize]=s;
occSize++;
}else{
totSize=totSize+ARRAY_SIZE;
DynamicArray* temp=new DynamicArray[totSize];
for (int i=0; i<occSize; i++){
temp[i]=darr[i];
}
darr=temp;
delete [] temp;
temp=NULL;
darr[occSize]=s;
occSize++;
}
}
//remove the element where the index is poining to in the array.
//when there are more than ARRAY_SIZE empty slots left, the delete()
//will shrink the array by another ARRAY_SIZE
void DynamicArray::remove(){
darr[del]=NULL;
del++;
occSize--;
if (del>5){
DynamicArray* temp=new DynamicArray[totSize-ARRAY_SIZE];
int j=del;
for (int i=0; i<occSize; i++){
temp[i]=darr[del];
j++;
}
darr=temp;
del=0;
delete [] temp;
temp=NULL;
}
}
//returning the current max capacity size of the array
int DynamicArray::totalSize(){
return totSize;
}
//returning the number of occupied slots in the array
int DynamicArray::occupiedSize(){
return occSize;
}
DynamicArray DynamicArray::operator= (string s){
*this=s;
return *this;
}
DynamicArray DynamicArray::operator= (int n){
*this=n;
return *this;
}

Of course it crashes, as in the constructor of DynamicArray you create new instances of DynamicArray which calls the constructor which in turn creates new instances of DynamicArray... This infinite recursion will lead to a stack overflow which crashes the program.
If the DynamicArray should by a dynamic array (or vector) of strings, then it should contain an "array" of strings, either std::string objects or of pointers. Like
class DynamicArray
{
private:
char** darr; // The actual array of data
...
};
DynamicArray::DynamicArray(int n)
{
darr = new char*[n];
...
}

Related

How in C++ would you create a method that shuffles the the elements in a Generic Array

I am to make a Genetic Array class in C++ and in that class I am to give it a method called shuffle that shuffles(mixes up) the elements in that Array
I am using Repl.it to compile my code and this is the link:
https://repl.it/#jamy155/Exam1
In my code, I have 3 files. My main class, My genetic array class, and one other class.
In my array class, I have this method that is supposed to shuffle the array
//Array.h//
#include <bits/stdc++.h>
using namespace std;
template <typename T>
class Array {
Element<T>*data;
int size;
public:
// sets the size of the array
Array(int size){
this->data = new Element<T>[size];
this-> size = size;
}
int length(){
return this->size;
}
// add Element to the Array
void InsertAt(int i,T value){
data[i].set(value);
}
// prints all element in Array
void print(){
for(int i = 0 ; i<this->size; i++){
cout<<*data[i].get()<<" ";
}
void shuffler(Array arr[]){
int n = this->size;
// To obtain a time-based seed
unsigned seed = 50;
// Shuffling our array
shuffle(arr, arr+n,default_random_engine(seed)); // shuffle method
cout<<"\n";
for(int i=0;i<n;++i)
cout<<arr[i].get(i)<<" ";
}
};
This is my main class.
#include <iostream>
#include "Array.h"
using namespace std;
int main() {
cout << "Hello World!\n";
Array<int> *arr = new Array<int>(7);
arr->InsertAt(0,6);
arr->InsertAt(1,1);
arr->InsertAt(2,10);
arr->InsertAt(3,3);
arr->InsertAt(4,3);
arr->InsertAt(5,5);
arr->InsertAt(6,4);
arr->print();
arr->shuffler(arr); //error
It gives me an error "exited, segmentation fault".What am I doing wrong?

Segmentation fault: 11 in C++ IntVector

I'm attempting to implement an intvector in C++ and am getting a "Segmentation fault: 11" error. I understand this has something to do with memory management, and considering how new I am to C++ it could definitely be a pretty minor mistake. I debugged the code with valgrind and was given messages such as the following:
Use of uninitialized value of size 8, Invalid read of size 4,Conditional jump or move depends on uninitialized value(s).
My best guess is it has something to do with how I'm implementing the arrays. I originally had the arrays stored on the heap but changed it to the stack and still got the same error. I've already implemented an intvector in java, so I was attempting to use similar logic here, which perhaps is part of the issue.
#include <iostream>
#include "IntVector.h"
#include <cmath>
using namespace std;
int num_elements = 0;
int array_size = 0;
int expansion_factor;
void IntVector::expandArray(){
int tempArr[array_size*2];
for(int i =0;i<array_size;i++){
tempArr[i] = array[i];
}
array = tempArr;
array_size = array_size * 2;
}
void IntVector::add(int val){
int tempArr[array_size];
if(array_size == num_elements){
expandArray();
array[num_elements] = val;
}
else{
for(int i = 0;i<array_size;i++){
tempArr[i] = array[i];
}
tempArr[num_elements] = val;
array = tempArr;
}
num_elements++;
}
void IntVector::remove(int index){
}
int IntVector::get(int index) const{
return index;
}
void IntVector::removeLast(){
}
void IntVector::set(int index, int val){
}
std::string IntVector::toString()const {
return "";
}
IntVector::IntVector(int initial_size){
int* array = new int[initial_size];
}
IntVector:: ~IntVector(){
delete[] array;
}
int main(){
IntVector v(0);
v.add(5);
}
#ifndef INTVECTOR_H_
#define INTVECTOR_H_
using std::cout;
class IntVector {
private:
int* array;
int num_elements;
int array_size;
int expansion_factor;
void expandArray();
public:
void add(int val);
void remove(int index);
int get(int index) const;
void removeLast();
void set(int index, int val);
std::string toString() const;
IntVector(int initial_size);
~IntVector();
};
#endif
As mention in the comments, there are definitely some holes in your understanding of C++. Really when dealing with header files you should have a main.cpp, someotherfile.h, someotherfile.cpp. That just best practices to avoid redefinition errors.
There was quite a bit wrong with the way you accessed the private variable. If a class has a private( or even public) variable you don't have to redeclare it each time you want to change its value.
There were one or two major flaws with the way you expanded the vector. If the vector size is initialized to 0 then 0*2 is still 0 so you never actually increased the size. Secondly, when you set the original array = to the new array the new array was just a local array. This means that the memory wasn't actually allocated permanently, once the function ended the temparr was destroyed.
I know this was probably a lot but if you have any question feel free to ask.
main.cpp
#include "IntVector.h"
int main()
{
IntVector v;
IntVector x(10);
v.push(5);
v.push(5);
v.push(5);
v.push(5);
v.push(5);
v.print();
cout << endl;
x.push(5);
x.push(5);
x.push(5);
x.push(5);
x.push(5);
x.print();
return 0;
}
IntVector.h
#include <string>
#include <iostream>
using namespace std;
class IntVector {
private:
int *array;
int num_elements;
int array_size;
//int expansion_factor =; you would only need this if you plan on more than double the vector size
void expandArray(); //normally c++ array double in size each time they expand
public:
//Constructors
IntVector(); //this is a contructor for if nothing is called
IntVector(int initial_size);
//setters
void push(int val); //add
void pop(); //removelast
void remove(int index); //remove
void at(int index, int val); //set
//Getters
int at(int index);
//std::string toString(); I'm changing this to print
void print(); //will print the contents to the terminal
//Deconstructor
~IntVector();
};
IntVector.cpp
#include "IntVector.h"
//constructors
IntVector::IntVector() //no arguments given
{
array = new int[0];
num_elements = 0;
array_size = 0;
}
IntVector::IntVector(int initial_size)
{
array = new int[initial_size];
num_elements = 0;
array_size = initial_size;
}
void IntVector::expandArray()
{
int *tempArr;
if(array_size == 0){
array_size = 1;
tempArr = new int[1];
} else {
//make sure to allocate new memory
//you were creating a local array which was destroy after the function was completed
//using new will allow the array to exist outside the function
tempArr = new int[array_size * 2];
}
for (int i = 0; i < array_size; i++)
{
tempArr[i] = array[i];
}
//make sure to delete the old array otherwise there is a memory leak.
//c++ doesn't have a garbage collector
delete[] array;
array = tempArr;
array_size = array_size * 2;
}
void IntVector::push(int val)
{
num_elements++;
//checking if vector needs to increase
if (array_size <= num_elements)
{
expandArray();
array[num_elements-1] = val;
}
else
{
array[num_elements-1] = val;
}
}
void IntVector::remove(int index)
{
//not sure how to implment this becuase each element has to be a number.
}
int IntVector::at(int index)
{
return array[index];
}
void IntVector::pop()
{
num_elements = num_elements-1; //not really removing it from the "vector" but it won't print out again
}
void IntVector::at(int index, int val)
{
array[index] = val;
}
void IntVector::print()
{
for (int i = 0 ; i < num_elements; i++)
{
cout << array[i] << " ";
}
cout << endl;
}
IntVector::~IntVector()
{
delete[] array;
}
output
5 5 5 5 5
5 5 5 5 5
Hopefully, the comments help. I changed the name of the functions to better match the actual vecter class the already exists in C++. I think it's good to pick apart already defined functions like this because you get a better understanding of how they actually work and not just how to use them.
If you got any questions just leave a comment

getting a SIGSEGV (segmentation fault)

I'm creating a generic box with a template. Basically something like a queue or linked list. I keep getting a SIGSEGV for some reason and I can't figure it out. I take in an integer or a string from the user in main and then the constructor makes allocates memory for the generic box to exist, then using function inert_First (there are a lot more functions like insert_Mid, insert_last, delete_Mid etc) and it keeps telling me I'm accessing wrong memory but I don't know where ?
this is the class
template<class T>
class g_Box
{
int first,mid,last;
int no_Of_Ele;
int capacity;
T *ele;
public:
g_Box();
g_Box(int);
void insert_First(T);
};
this is the constructor
template<class T>
g_Box<T>::g_Box(){
first=-1, last=-1, mid=-1;
no_Of_Ele=0;
capacity=10;
T *ele = new T[capacity];
}
template<class T>
g_Box<T>::g_Box(int a){
first=-1, last=-1, mid=-1;
no_Of_Ele=0;
capacity=a;
T *ele = new T[capacity];
}
This is the insert_First
template<class T>
void g_Box<T>::insert_First(T a){
if(isFull()){
cout<<"The box is full";
}
else if(isEmpty()){
first=0; last=0; mid=(first+last)/2;
ele[0]=a;
no_Of_Ele++;
}
else{
T *ele2 = new T[capacity];
//T ele2[capacity];
for(int i=0; i<no_Of_Ele; i++){
ele2[i]=ele[i];
}
for(int i=0; i<no_Of_Ele; i++){
ele[i+1]=ele2[i];
}
ele[first]=a;
last++;
mid=(first+last)/2;
no_Of_Ele++;
delete[] ele2;
}
}
and this is the main
int main()
{
g_Box<int> g;
int data;
cin>>data
g.insert_First(data);
}

Can't copy newly created objects in the Class constructor to its vector member in C++

In the class constructor, I am initializing other objects and pushing these objects to my class vector member. From what I understand, the vector create a copy of the object and stores it so that it doesn't go out of scope. However, when verifying the objects in another class function, they are not initialized anymore. Here's a example code to explain the behaviour:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
class Square {
private:
int size_ = 0;
int colour_ = 0;
public:
Square(){
size_ = 0;
colour_ = 0;
}
void init(int size, int colour) {
size_ = size;
colour_ = colour;
}
int get_size() { return size_; }
};
class SetSquares {
private:
std::vector<Square> squares_;
int number_;
public:
SetSquares(): number_(0) {}
void init(int num) {
number_ = num;
squares_.clear();
squares_.resize(num);
for (int i=0; i < num; i++) {
Square square;
square.init(i, i);
squares_.push_back(square);
}
}
void sample(int i) {
if (i >= number_) { return; }
std::cout << "Square size is: " << squares_[i].get_size() << std::endl;
}
};
int main()
{
SetSquares set_of_squares;
set_of_squares.init(7);
set_of_squares.sample(4);
return 0;
}
resize(n) will create n default constructed elements in a vector and push_back will append new elements after those n elements. Use reserve and push_back or resize and index operator as suggested in comment.

Resize method intArray

I'm writting an IntArray class for college but don't know how to write my resize method efficiently. What I have doesn't support resizing to smaller lists and I don't know how to fix that..
Here is my code:
void IntArray::resize(unsigned int size){
for (int i = size;i<length;i++){
data[i] = 0;
}
length = size;
}
header file
#ifndef INTARRAY_H_
#define INTARRAY_H_
#include <iostream>
using namespace std;
class IntArray{
private:
int length;
int * data;
public:
IntArray(int size = 0);
IntArray(const IntArray& other);
IntArray& operator=(const IntArray& original);
int getSize() const { return length; };
int& operator[](unsigned int i);
void resize(unsigned int size);
void insertBefore(int value, int index);
friend ostream& operator<<(ostream& out, const IntArray& list);
~IntArray(){ delete[] data; };
};
When you need to resize an you are actually going to create a new array, copy the old into the new and then delete the old array.
void IntArray::resize(unsigned int size){
if (size <= length) // if we are making it smaller reset the size and do nothnig
{
my_size = size
return;
}
int * temparr = new int[size];
// copy data
for (unsigned int i = 0; i < length; ++i)
temparr[i] = data[i];
delete [] data; // get rid of the old array
data = temparr; // set data to the new array
length = size; // set the new size
}
You should also have a capacity member that tracks the actual size of the array like a std::vector. That way you can have an array that is bigger than what you need to as it grows there would need to be less re -llocations.