Best practices for creating a two dimensional array of std::strings - c++

I am new to c++ and learning how to declare, use and delete a two dimensional array of std::string.
Because this is a learning exercise I am ignoring the idea of using vectors (for now).
I wrote a program that creates a small two dimensional array, adds data and then deletes the 2d array trying to use best practices along the way.
Can someone suggest improvements? I am most concerned about cleaning up the 2d array after I'm done using it, so I can avoid the possibility of a memory leak.
Thanks in advance.
#include <iostream>
#include <string>
using namespace std;
void DIM(std::string **marray,unsigned int row,unsigned long cols)
{
if (marray[row] != nullptr) {
delete [] marray[row];
marray[row] = nullptr;
}
marray[row] = new std::string[cols];
}
void DIM_DELETE (std::string **marray,unsigned int row)
{
if (*&marray[row] != nullptr) {
delete[] marray[row];
marray[row] = nullptr;
}
}
void DIM_DELETE_ALL (std::string **marray,unsigned int rows)
{
for (int i=(rows-1); i>-1; i--) {
if (marray[i] != nullptr) {
delete[] marray[i];
marray[i] = nullptr;
}
}//next i
//now take care of marray
if (marray != nullptr) {
delete [] marray;
marray = nullptr;
}
}
std::string **create2darray(unsigned int rows,unsigned int cols)
{
//first create the pointer
std::string **my = nullptr; //create pointer , note: no data portion assigned yet
//now assign a data portion to the pointer (could do above in one step)
my = new std::string*[rows];// elements 0 through rows-1 //assigns data section (an array of std::strings)
//now set newly created rows to nullptr
for (unsigned int i = 0; i<rows; i++) {
my[i] = nullptr;
}
//dim each row for cols columns
for (unsigned int i = 0; i<rows; i++) {
DIM(my,i,cols);//dims the strings (creates data portion) my = new std::string*[x];//
}
return my;//returning a std::string **
}
int main()
{
unsigned int rows = 3;//3 rows (0 through 2)
unsigned int cols = 4;//4 columns (0 through 3)
std::string **myarray = create2darray(rows,cols);//2d array (3 rows, 5 cols)
cout << "2d array created" << endl << endl;
myarray[0][0] = "a0"; //row 0, col 0
myarray[1][0] = "b0"; //row 1, col 0
myarray[2][0] = "c0";
myarray[0][1] = "a1";
myarray[0][2] = "a2";
myarray[0][3] = "a3";
myarray[1][1] = "b1";
myarray[1][2] = "b2";
myarray[1][3] = "b3";
myarray[2][1] = "c1";
myarray[2][2] = "c2";
myarray[2][3] = "c3";
cout << "assigned data to rows 0 to 2 and cols 0 to 3" << endl << endl;
for (unsigned int i=0; i<rows; i++) {
cout << i << ",0: " << myarray[i][0] << " " << i << ",1: " << myarray[i][1] << " " << i << ",2: " << myarray[i][2] << " " << i << ",3: " << myarray[i][3] << endl;
}
cout << endl;
cout << "we are done with 2d array, let's delete it" << endl;
//tested dim_delete (seems to work)
/*
DIM_DELETE(myarray,0);//delete [] myarray[0]; myarray[0] = nullptr;
DIM_DELETE(myarray,1);
DIM_DELETE(myarray,2);
//still need to delete myarray
delete [] myarray;
myarray = nullptr;
*/
//delete all rows and delete the std::string that holds the rows
DIM_DELETE_ALL(myarray,rows);
cout << "array deleted, all done" << endl;
//hold cursor so user can see console messages
do {} while(cin.get()!='\n');
return 0;
}

If the second dimension of your array is constant, I think you can be fine using a single new and delete operators. Something like this:
#include <stdio.h>
#include <string>
int ROWS = 3;
const int COLS = 4;
typedef std::string arr4[COLS];
int main()
{
arr4 *a;
a = new arr4[ROWS];
for (int i = 0; i < ROWS; i++)
for (int j = 0; j < COLS; j++)
a[i][j] = std::to_string(j*ROWS + i);
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLS; j++)
printf("%s ", a[i][j].c_str());
printf("\n");
}
printf("\n");
delete [] a;
}

Related

Can't manage to display the last array

I have these code:
#include<iostream>
#include<iomanip>
using namespace std;
class Array {
private:
static const int size = 100;
int arr[size];
public:
Array();
void display();
Array& operator+(const Array& arr);
};
Array::Array()
{
for (int i = 0; i < size; i++)
{
arr[i] = rand() % 99 + 1;
}
}
void Array::display()
{
for (int i = 0; i < size; i++)
{
cout << setw(5) << arr[i];
if ((i + 1) % 10 == 0)
cout << endl;
}
}
Array & Array::operator+(const Array & arr)
{
Array temp;
for (int i = 0; i < size; i++)
{
temp.arr[i] = this->arr[i] + arr.arr[i];
}
return temp;
}
int main()
{
srand(time(NULL));
Array arr1, arr2;
cout << "arreglo 1:\n";
arr1.display();
cout << endl;
cout << "arreglo 2:\n";
arr2.display();
cout << endl;
//adding both arr HERE IS MY PROBLEM
Array arr3 = arr1 + arr2;
cout << "Suma de arreglo 1 y arreglo 2: " << endl;
arr3.display();
cout << endl;
return 0;
}
Somehow it can't manage to display Array arr3 = arr1 + arr2.
Array & Array::operator+(const Array & arr)
{
Array temp;
...
return temp;
}
This returns a reference to an object that goes out of scope and is destroyed after the function returns. As a general rule you should not return addresses of or references to local variables.
Remove the & so it returns a new Array instead:
Array Array::operator+(const Array & arr)

dynamic memory allocation using vectors and bubble sort

I need help in adding the user to enter value that becomes array size and will sort array by bubble sort its sorting however I need user to enter the value and it becomes value of an array ie. allocation memory dynamically
#include <iostream>
#include <vector>
//function to swap values
//need to pass by reference to sort the original values and not just these copies
void Swap (int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void BubbleSort (std::vector<int> &array)
{
std::cout<<"Elements in the array: "<<array.size()<<std::endl;
//comparisons will be done n times
for (int i = 0; i < array.size(); i++)
{
//compare elemet to the next element, and swap if condition is true
for(int j = 0; j < array.size() - 1; j++)
{
if (array[j] > array[j+1])
Swap(&array[j], &array[j+1]);
}
}
}
//function to print the array
void PrintArray (std::vector<int> array)
{
for (int i = 0; i < array.size(); i++)
std::cout<<array[i]<<" ";
std::cout<<std::endl;
}
int main()
{
std::cout<<"Enter array to be sorted (-1 to end)\n";
std::vector<int> array;
int num = 0;
while (num != -1)
{
std::cin>>num;
if (num != -1)
//add elements to the vector container
array.push_back(num);
}
//sort the array
BubbleSort(array);
std::cout<<"Sorted array is as\n";
PrintArray(array);
return 0;
}
I tried cin using while however array doesn't print
I modified your version and show you, how you can get the number of elements to sort from the user and hot to dynamically allocate memory in your array.
You will simply use the std::vectors constructor to define a size. Looks then like: std::vector<int> array(numberOfElements);.
The whole adapted code:
#include <iostream>
#include <vector>
//function to swap values
//need to pass by reference to sort the original values and not just these copies
void Swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void BubbleSort(std::vector<int>& array)
{
std::cout << "Elements in the array: " << array.size() << std::endl;
//comparisons will be done n times
for (size_t i = 0; i < array.size(); i++)
{
//compare elemet to the next element, and swap if condition is true
for (size_t j = 0; j < array.size() - 1; j++)
{
if (array[j] > array[j + 1])
Swap(&array[j], &array[j + 1]);
}
}
}
//function to print the array
void PrintArray(std::vector<int> array)
{
for (size_t i = 0; i < array.size(); i++)
std::cout << array[i] << " ";
std::cout << std::endl;
}
int main()
{
std::cout << "Enter the number of data to sort: ";
size_t numberOfElements{ 0 };
std::cin >> numberOfElements;
std::vector<int> array(numberOfElements);
size_t counter{ 0 };
std::cout << "\nEnter "<< numberOfElements << " data\n";
int num = 0;
while ((counter < numberOfElements) &&(std::cin >> num) )
{
array[counter] = num;
++counter;
}
//sort the array
BubbleSort(array);
std::cout << "Sorted array is as\n";
PrintArray(array);
return 0;
}
But, I would recomend to use modenr C++ elements, like algorithms to solve the problem.
See:
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
int main()
{
size_t numberOfElements{ 0 };
std::vector<int> array{};
std::cout << "Enter the number of data to sort: ";
std::cin >> numberOfElements;
std::cout << "\nEnter " << numberOfElements << " data values:\n";
std::copy_n(std::istream_iterator<int>(std::cin), numberOfElements, std::back_inserter(array));
std::sort(array.begin(), array.end());
std::cout << "\n\nSorted data:\n\n";
std::copy(array.begin(), array.end(), std::ostream_iterator<int>(std::cout, "\n"));
return 0;
}

How to point one array to another array

I have two arrays in a class, both with different sizes. My goal is to copy the second array (nArray) to the the first array (_theArray) using pointers. Below I have included the code of the function in the class, as well as the function in main to test the swap.
I have written the code below, where I try to point the first array to the second array using pointer p (int * p).
void easyArray::resize(unsigned int newSize)
{
// created new dynamic array
int * nArray = new int[newSize];
// init the new array
for (int i = 0; i < newSize; i++) {
nArray[i] = 0;
cout << nArray[i] << " ";
}
if (newSize >= _size) {
for (int i = 0; i < _size; i++) {
nArray[i] = _theArray[i];
}
} else {
cout << "not enough room" << endl;
}
destroy(); //deletes old array
int *p = _theArray; //points old to new array (?)
p = nArray; //sets old array = to new array (?)
}
in main:
void testResize()
{
easyArray a(5);
for(int i = 0; i < a.size(); i++) {
a[i] = i + 100;
}
a.resize(10);
a[9] = 99;
cout << "TEST RESIZE: " << a << endl << endl;
}
Any help is appreciated
Currently when I run this I get the error:
Debug Assertion Failed!
Expression:_CrtIsValiedHeadPointer(block)
Assuming _theArray is a class member variable, you can do _theArray = nArray after the call to destroy() and delete the last 2 lines involving p.

C++ allocating memory

Can someone explain me why when i back form function i lost my data from tabOfOffsets. I did the same thing twice and program crash only with the second array.
I printed values of this array on the end of function and everything is clear and correct. Maybe i make mistake somewhere with delete?
Below it is the code.
#include<iostream>
#include <algorithm>
using std::cout;
using std::endl;
void changeSizeOfVector(int *tabValue, int *tabOffsets, int &oldSize, int
newSize) {
int temp = std::min(oldSize, newSize);
int *newTabOfValues = new int [newSize] {0};
int *newTabOfOffsets = new int [newSize] {0};
for (int i = 0; i < temp; i++) {
newTabOfValues[i] = tabValue[i];
newTabOfOffsets[i] = tabOffsets[i];
}
delete[] tabValue;
delete[] tabOffsets;
tabValue = new int [newSize] {0};
tabOffsets = new int [newSize] {0};
for (int i = 0; i < newSize; i++) {
tabValue[i] = newTabOfValues[i];
tabOffsets[i] = newTabOfOffsets[i];
std::cout << tabOffsets[i] << tabValue[i] << endl;
}
oldSize = newSize;
delete[] newTabOfValues;
delete[] newTabOfOffsets;
for (int i = 0; i < newSize; i++) {
std::cout << tabOffsets[i] << tabValue[i] << endl;
}
}
int main() {
int SIZE = 10;
int * tabOfOffsets = new int[SIZE];
int * tabOfValues = new int[SIZE];
for (int i = 0; i < SIZE; i++)
{
tabOfValues[i] = i;
tabOfOffsets[i] = i;
cout << tabOfValues[i] << " : " << tabOfOffsets[i] << endl;
}
changeSizeOfVector(tabOfValues, tabOfOffsets, SIZE, 12);
for (int i = 0; i < SIZE; i++) {
cout << tabOfOffsets[i] << " : " << tabOfValues[i] << endl;
}
delete[] tabOfOffsets;
delete[] tabOfValues;
}
This function declaration is wrong:
void changeSizeOfVector(int *tabValue, int *tabOffsets, int &oldSize, int
newSize);
it means you can change the values of tabOffsets but not the pointer itself in order to make it behave correctly you should declare it as follows:
void changeSizeOfVector(int *tabValue, int **tabOffsets, int &oldSize, int
newSize);
This way you can change the pointer itself and assign a newly allocated array to it.

C++ HEAP error when delete [] is called

I keep getting the error in VS 2100 "CRT detected that the application wrote to memory before start of heap buffer"
Can anyone help? My int Main is all the way on the bottom. The error occur when the delete [] command is run on the operator= function
#include "intset.h"
const int MAXINITIALSIZE = 5;
int IntSet::numOfArray = 0;
IntSet::IntSet(int a, int b, int c, int d, int e)
{
numOfArray++;
int tempArray[] = {a, b, c, d, e};
size = determineHighest(tempArray) + 1; //determines largest int
cout << "size is " << size << endl;
arrayPtr = new bool[size]; //creates array of bool
for (int i = 0; i < size; i++) //fill bool array
{
arrayPtr[i]= false; //arrayptr is a bool pointer created in the header
}
for (int i = 0; i < MAXINITIALSIZE; i++)
{
arrayPtr[tempArray[i]]= true;
}
for (int i = 0; i < size; i++)
{
cout << &arrayPtr[i] << endl;
}
}
IntSet::IntSet(const IntSet &intsetObject)
{
numOfArray++;
size = intsetObject.size;
arrayPtr = new bool[size];
for (int i = 0; i < size; i++)
{
if (intsetObject.arrayPtr[i])
arrayPtr[i] = intsetObject.arrayPtr[i];
}
}
IntSet::~IntSet()
{
--numOfArray;
delete [] arrayPtr;
arrayPtr = NULL;
}
int IntSet::determineHighest(int tempArray[])
{
int temp = tempArray[0];
for (int i = 1; i < MAXINITIALSIZE; i++)
{
if (tempArray[i] > temp)
temp = tempArray[i];
else
continue;
}
return temp;
}
IntSet& IntSet::operator=(const IntSet &intsetObject) //ask about IntSet&
{
cout << "inside operator=" << endl;
if (&intsetObject != this)
{
for (int i = 0; i < size; i++)
{
cout << &arrayPtr[i] << endl;
}
delete [] arrayPtr; //HEAP ERROR HERE!
for (int i = 0; i < size; i++)
{
cout << &arrayPtr[i] << endl;
}
size = intsetObject.size
arrayPtr = new bool[size]();
for (int i = 0; i < size; i++)
{
if (intsetObject.arrayPtr[i])
arrayPtr[i] = intsetObject.arrayPtr[i];
}
}
return *this;
}
ostream& operator<<(ostream &output, const IntSet &intsetObject)
{
output << "{ ";
for (int i = 0; i < intsetObject.size; i++)
{
if (intsetObject.arrayPtr[i] == true)
{
output << i << " ";
}
else
continue;
}
output << "}";
return output;
}
//main
#include "intset.h"
int main() {
IntSet object2(9);
IntSet object4(3,6);
object4 = object2;
return 0;
}
This can only happen if arrayPtr is accessed with a negative index. I suspect your defaults for a,b,c,d,e are -1 in the declaration for IntSet::IntSet, so it is writing to arrayPtr[-1] in the set-true loop. Check for tempArray[i] >= 0 there.
Also, you can't print the array after you have deleted it, so you should remove those lines after the delete, although they should be "harmless" in that only garbage will be printed, but who knows - the OS could release the page containing the array and it could segfault your program.
Finally, you should not test if (intsetObject.arrayPtr[i]) in the copy & = operators. Otherwise all "false" elements in the source array become uninitialized in the destination array (new bool[size] does not initialize the array to all false).