C++ Dynamic Array Template issue - c++

I am a beginner programmer in school still, and I was assigned this problem:
"Make your own dynamic array template. It should allow creating contiguous arrays (filled with things of the same type) which you can extend without worrying about running out of space.
Do one version using malloc and free.
Do one version using new and delete."
So far this is what I have:
#include <iostream>
#include <sstream>
#include "Array.h"
using namespace std;
int main(){
Array<int> *testArray = new Array<int>(5);
testArray->initArray();
testArray->printArray();
testArray->addData(7);
testArray->printArray();
return 0;
}
And here is the "Array.h" file:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
template<typename T>
class Array{
public:
Array(int size){
size = size;
data = new T[size];
};
Array<T> *addData(T dataToAdd){
Array <T> *tmp = new Array <T> (this->size);
tmp->data = this->data;
Array <T> *newData = new Array<T> (this->size + 1);
for (int i = 0; i < this->size + 1; ++i){
if (i < this->size){
//newData->data[i] = tmp->data[i];
newData->setData(tmp->getData()[i], i);
}
else{
//newData->data[i] = dataToAdd;
newData->setData(dataToAdd, i);
}
}
return newData;
};
void initArray(){
for (int i = 0; i < this->size; ++i){
//this->data[i] = i;
this->setData(i, i);
}
};
void printArray(){
ostringstream oss;
string answer = "";
for (int i = 0; i < this->size; ++i){
oss << this->data[i] + " ";
//cout << this->data[i] << " ";
}
answer = oss.str();
cout << answer << "asdf" << endl;
};
T* getData(){
return this->data;
}
int getSize(){
return this->size;
}
void setData(T data, int index){
this->getData()[index] = data;
}
private:
int size;
T* data;
};
So far what SHOULD happen in my main file is there should be an array of 5 ints, that are initialized to 0,1,2,3,4 from the initArray function.
Then it should print out the array, showing "0 1 2 3 4," add another "7" to it, then print the new array out showing "0 1 2 3 4 7."
For some reason, and I think it has something to do with losing data somehow when going between the two files, the field "data" of my Array class is not being properly changed.
I even hardcoded a test for this in main where I wrote a for loop using the setData function that initializes the Array to "0 1 2 3 4," and then manually printed out these values with another for loop, but the output was only "0 0 0 0 0."
Right now, as the code is, the output is:
asdf
asdf
As it was outputting whitespace before so I added the "asdf"'s to see if my printArray worked at all.
To sum up, why is the data in my private field "data" not being properly stored? I am very new to programming in c++ and any advice would be greatly appreciated. Thank you for your time, and if there is anything you do not understand please ask for clarification and I will do my best.
EDIT: problem solved! Thank you everyone who helped, the issue was with my constructor and how I was calling my functions in main.

One issue is your constructor:
Array(int size){
size = size;
data = new T[size];
};
The way you have it, you're just assigning your size argument to itself, which has no effect. One way to fix it would be to use a different name for the argument:
Array(int size_arg){
size = size_arg;
data = new T[size_arg];
};
However, the preferred way is to use the constructor initializer syntax:
Array(int size) : size(size), data(new T[size]) {};
With the constructor initializer syntax, the compiler knows that you are trying to initialize specific members and doesn't get confused between the argument name and the member name.

Related

Array is not resizing with operator new [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 12 months ago.
Improve this question
I want to implement a dynamic array as a class.
I haven written a method which adds an element at the end of the array:
void DynamicArray::addElementAtEnd() {
cout << "\nPodaj liczbe calkowita: ";
int* number = new int;
cin >> *number;
if (DynamicArray::array == NULL) {
DynamicArray::array = new int[1];
DynamicArray::array[0] = *number;
delete number;
(*DynamicArray::size)++;
return;
}
int* buff = new int[*DynamicArray::size + 1];
memcpy(buff, DynamicArray::array, (*DynamicArray::size) * sizeof(int));
delete[] DynamicArray::array;
buff[(*DynamicArray::size)] = *number;
DynamicArray::array = buff;
(*DynamicArray::size)++;
delete number;
return;
};
Here's the .h file of the DynamicArray class:
#include <iostream>
using namespace std;
class DynamicArray {
public:
int* array;
int* size;
public:
DynamicArray() {
DynamicArray::size = new int;
*DynamicArray::size = 0;
};
void handleMenu();
void readFromFile();
void addElementAtEnd();
void addElementAtBeginning();
void addAtIndex(int index);
void deleteElementAtEnd();
void deleteElementAtBeginning();
void deleteElementByIndex(int index);
void showAllElements();
void showElementAtIndex(int index);
void findElementByValue(int value);
};
The problem is that this method adds only the first element, but if I try to add more then nothing happens. I debugged it, and the problem starts on this line:
int* buff = new int[*DynamicArray::size + 1];
I don't know why, but it seems like this line is not creating a bigger array.
I searched for some solutions, and it seems that the problem is connected with using *DynamicArray::size + 1 instead of eg a variable, or I don't do something right with it.
The actual problem is that you are not initializing array to NULL.
So when you check if array is NULL on the first iteration, it is often not.
The minimal solution:
DynamicArray::DynamicArray() {
this->size = 0; // You should use 'size' like an int, not a pointer
this->array = NULL;
}
// Or using the Member Initializer List (by #user4581301)
DynamicArray::DynamicArray(): size(0), array(nullptr) {}
Note: Differences between NULL and nullptr
Other simple solution could be to check if size is equal to 0 instead of checking if array is NULL.
The above change will solve your problem but your code can still be improved.
Take into account the comments of other users.
And make sure to free each dynamically allocated memory.
Let's address a variety of things.
class DynamicArray {
public:
int* array;
int* size;
public:
DynamicArray() {
DynamicArray::size = new int;
*DynamicArray::size = 0;
}
};
A few things here. First, as others have suggested, there's zero reason to make size a pointer.
Next, it's a strong guideline / good idea to always initialize your fields when declared.
So this section of code can look like this:
class DynamicArray {
public:
int* array = nullptr;
int size = 0;
public:
DynamicArray() {
}
};
After that, please use nullptr instead of NULL. NULL is from C, but the correct value in C++ is nullptr.
Now, let's look at this bit of code.
void DynamicArray::addElementAtEnd() {
cout << "\nPodaj liczbe calkowita: ";
int* number = new int;
cin >> *number;
if (DynamicArray::array == NULL) {
DynamicArray::array = new int[1];
DynamicArray::array[0] = *number;
delete number;
(*DynamicArray::size)++;
return;
}
int* buff = new int[*DynamicArray::size + 1];
memcpy(buff, DynamicArray::array, (*DynamicArray::size) * sizeof(int));
delete[] DynamicArray::array;
buff[(*DynamicArray::size)] = *number;
DynamicArray::array = buff;
(*DynamicArray::size)++;
delete number;
return;
};
Aside from the extra colon on the end of the function (entirely not necessary), this is far more complicated than it needs to be. First, get rid of the int pointer. That's just ridiculous.
void DynamicArray::addElementAtEnd() {
cout << "\nPodaj liczbe calkowita: ";
int number = 0;
cin >> number;
int * newArray = new int[size + 1];
newArray[size] = number;
if (array != nullptr) {
for (int index = 0; index < size; ++index) {
newArray[index] = array[index];
}
delete [] array;
}
array = newArray;
++size;
}
A last comment -- it would make far more sense to pass in the new value as an argument to the method, and the calling test code should get the value you're adding. But you're just learning, so this works.
Note also that you shouldn't specify the class the way you have: DynamicArray::array. No one does that. Do it the way I did above.

Array and pointers to structures

So I have this structure
struct Data {
int id;
string message;
};
I am trying to create an array of struct pointers and fill it with values using this
Data *stack[10];
for(int i=0; i<10; i++){
stack[i] = (struct Data*) malloc(sizeof(struct Data));
stack[i]->id = i;
stack[i]->message = "message" + i;
}
however, I keep getting an error (segmentation fault when debugging) from stack[i]->message = "message" + i;
Can anyone please help understand what's causing the error and how to solve it?
Below is the working example. You can use smart pointers for automatic memory management, that is the destructor will be called automatically when reference count goes to zero.
#include <iostream>
#include <memory>
using namespace std;
struct Data {
int id;
string message;
Data()
{
std::cout<<"default consructor"<<std::endl;
}
~Data()
{
std::cout<<"destructor "<<std::endl;
}
};
int main()
{
std::cout << "Hello World" << std::endl;
std::shared_ptr<Data> stack[10];
for(int i=0; i<10; i++){
stack[i] = std::make_shared<Data>();
stack[i]->id = i;
stack[i]->message = "message" + std::to_string(i);//make sure to convert the integer to std::string
}
//check the value of id for first element in stack
std::cout<<stack[1]->id<<std::endl;
return 0;
}
You can also use new instead of malloc but then you will have to call delete explicitly. Note the use of std::to_string() to convert the integer i to string.

Segfault with std::vector =-operation to uninitialized space

I get segmentation faults when I use the =-operator to copy a struct that contains a std::vector to uninitialized memory.
The critical code looks like that:
template<typename T>
ComponentContainer
{
T* buffer;
size_t capacity;
size_t m_size;
public:
ComponentContainer();
~ComponentContainer();
size_t size();
void resize(size_t size);
T & operator[](size_t index);
};
template<typename T>
void ComponentContainer<T>::resize(size_t newSize)
{
if(this->m_size >= newSize)
{
this->m_size = newSize;
}
else
{
if(this->capacity < newSize)
{
const size_t newCapacity = capacity*2;
T* newBuffer = (T*)malloc(newCapacity*sizeof(T));
for(size_t i = 0; i<m_size; i++)
{
// checks if this->buffer[i] is valid intialized memory
if(pseudo_checkIfElementIsInitialized(i))
{
// when this is uncommented no segfault happens
//new (&newBuffer[i]) T();
newBuffer[i] = this->buffer[i]; // <- segfault happens here
}
}
this->capacity = newCapacity;
free(this->buffer);
this->buffer = newBuffer;
}
this->m_size = newSize;
}
}
The T-type is a struct with a std::vector of structs when I get the segfault.
I suspect that the std::vector =-operator uses somehow the left side variable newBuffer[i] and the segmentation fault happens since newBuffer[i] is not initialized.
Objects will be created only with in-placement new with the function T & operator[](size_t index). The malloc should only allocate the memory without initializing anything.
I tried to write a simple example but that hasn't worked out so well:
#include <iostream>
#include <vector>
struct Hello
{
Hello()
{
std::cout << "constructor" << std::endl;
}
~Hello()
{
std::cout << "destructor" << std::endl;
}
std::vector<double> v = std::vector<double>(1);
};
int main()
{
Hello* buffer = (Hello*)malloc(1*sizeof(Hello));
char* noise = (char*)buffer;
for(size_t i = 0; i<sizeof(Hello); i++)
{
noise[i] = 100;
}
auto tmp = Hello();
tmp.v[0] = 6.6;
//new (&buffer[0]) Hello();
buffer[0] = tmp;
std::cout << buffer[0].v[0] << std::endl;
return 0;
}
It works fine without segfault. I assume that is because the uninitialized memory was just by chance ok for the std::vector =-operation.
So
a) is that theory correct
and if yes
b) how to solve this problem without using a default constructor (T()) for every class that i use as T for my ComponentContainer
Well, yeah. You can't assign to an object that doesn't exist.
Uncomment the line that fixes it!
If you can't default construct, then copy construct:
new (&newBuffer[i]) T(this->buffer[i]);
And if you can't do that, then, well, you know the rest.
The malloc should only allocate the memory without initializing anything.
Is it possible that you've underestimated the weight of this statement? You don't just get memory then decide whether or not to initialise it with some values. You have to actually create objects before using them; this is not optional. You're programming C++, not manipulating bits and bytes on a tape :)

C++, Weird behavior of cout when trying to print integers

Im trying to write a class that stores an id and a value in an container class.
Im using an nested class as my data structure.
When im compiling the code sometimes it prints perfectly, sometimes it prints nothing and sometimes it prints half of the data then stops.
When i debug the code the same weird behavior occours, when it fails during debug it throws an error "Map.exe has triggered a breakpoint.", the Error occours in the print method when im using cout.
cmap.h
#pragma once
class CMap
{
public:
CMap();
~CMap();
CMap& Add(int id, int value);
void print() const;
private:
class container
{
public:
~container();
int container_id = 0;
int container_value = 0;
};
container* p_komp_;
int dim_ = -1;
void resize();
};
cmap.cpp
#include "cmap.h"
#include <iostream>
using namespace std;
CMap::CMap()
{
p_komp_ = new container[0];
}
CMap::~CMap()
{
p_komp_ = nullptr;
cout << "destroy cmap";
}
CMap& CMap::Add(int id, int value)
{
resize();
p_komp_[dim_].container_id = id;
p_komp_[dim_].container_value = value;
return *this;
}
void CMap::resize()
{
container* temp_array = new container[++dim_];
if (dim_ == 0)
{
temp_array[0].container_id = p_komp_[0].container_id;
temp_array[0].container_value = p_komp_[0].container_value;
}
for (unsigned i = 0; i < dim_; i++)
{
temp_array[i].container_id = p_komp_[i].container_id;
temp_array[i].container_value = p_komp_[i].container_value;
}
p_komp_ = temp_array;
}
void CMap::print() const
{
for (unsigned i = 0; i <= dim_; i++)
{
cout << p_komp_[i].container_id;
cout << p_komp_[i].container_value;
}
}
CMap::container::~container()
{
cout << "destruct container";
}
Map.cpp
#include "cmap.h"
#include <iostream>
using namespace std;
void main(void)
{
CMap m2;
m2.Add(1, 7);
m2.Add(3, 5);
m2.print();
}
These two things are a possible reason for your problem:
int dim_ = -1;
and
container* temp_array = new container[++dim_];
When you allocate, you increase dim_ from -1 to 0. That is you create a zero-sized "array", where every indexing into it will be out of bounds and lead to undefined behavior.
You also have memory leaks since you never delete[] what you new[]. I didn't look for more problems, but there probably a more.
And an "array" (created at compile-time or through new[]) will have indexes from 0 to size - 1 (inclusive). You seem to think that the "size" you provide is the top index. It's not, it's the number of elements.
It seems to me that you might need to take a few steps back, get a couple of good books to read, and almost start over.

Creating a personal string vector class

I am not allowed to make use of the vector class so I need to make my own. I made a int vector class and it works fine, but when trying to make it for strings it compiles but gives me an error because of the pointers. Any hint where I am making the mistake? All I did was change every int element for string, but aparently that does not work. Please help I am very confused.
public:
StringRow(){
elements = new string;
size = 0;
}
~StringRow(){...}
void push_back(string value){...}
};
You defined pointer to variable, not array of variables.
elements = new string;
Replace it with
elements = new string[size];
You can optimize algorithm with defining initial size. Create bigger array only if it's necessary.
There are several problems:
in the constructor you don't need to allocate anything. You don't even need a constructor here, you can initialize the members directly as you declare them.
if you allocate with string* tmpElementsArray = new string[size + 1]; you need to deallocate with delete [] tmpElementsArray;
Corrected working version:
#include <string>
#include <iostream>
using namespace std;
class StringRow {
private:
string* elements = nullptr;
int size = 0;
public:
// constructor not needed
// StringRow() {
// elements = nullptr;
// size = 0;
// }
~StringRow() {
delete []elements;
}
void push_back(string value) {
string* tmpElementsArray = new string[size + 1];
for (int i = 0; i<size; i++) {
tmpElementsArray[i] = elements[i];
}
delete [] elements;
elements = tmpElementsArray;
elements[size] = value;
size++;
}
int length() {
return size;
}
string at(int index) {
if (index<size) {
return elements[index];
}
}
};
int main()
{
StringRow s;
string str1 = "hello";
string str2 = "hello2";
s.push_back(str1);
s.push_back(str2);
cout << s.at(0) << endl ;
cout << s.at(1) << endl;
}
Doing a delete []elements if elements is nullptr is OK.
NB: This is not the most efficient way.