Why this c++ program giving seg fault - c++

Why this program giving segmentation fault. I am allocating the memory for 20 strings. (by default is also 20). and setting and trying to access 20th element.
#include <iostream>
using namespace std;
class myarray
{
private:
string *items;
public:
myarray (int size=20)
{
items = new string[size];
}
~myarray()
{
delete items;
}
string& operator[] (const int index)
{
return items[index];
}
/*
void setvalue (int index, string value)
{
items[index] = value;
}
string getvalue (int index)
{
return items[index];
}
*/
};
int main()
{
myarray m1(20);
myarray m2;
m1[19] = "test ion";
cout << m1[19];
//m1.setvalue (2, "Devesh ");
//m1.setvalue (8, "Vivek ");
//cout << m1.getvalue(19);
return 0;
}

If you allocate an array like you are doing with new string[size] you need to use delete[] items;

Use delete[] instead of delete.
Rule of thumb is:
If you have allocated memory with new, free it with delete.
If you have allocated memory with new[], free it with delete[].

Change constructor to:
items = new string[size]();
And destructor to:
delete[] items;

Related

How to correctly delete an allocated array (queue data structure)

I created a queue data structure using a struct and a dynamically allocated array, I don't understand what is the right way to free or delete it without any memory leaks.
I have tried using the following:
delete[] q->data;
delete[] &(q->data);
delete &(q->data);
#include "queue.h"
void initQueue(queue* q, unsigned int size)
{
q->maxSize = size;
q->size = 0;
q->data = new unsigned int[size];
q->front = 0;
q->rear = 0;
}
void enqueue(queue* q, unsigned int newValue)
{
if (q->size != q->maxSize)
{
q->data[q->rear] = newValue;
q->size++;
q->rear++;
}
else
{
std::cout << "Queue is full! you can clean it and initialize a new one" << std::endl;
}
}
int dequeue(queue* q)
{
int i = 0;
if (q->size == 0)
{
std::cout << "Queue is empty!" << std::endl;
return EMPTY;
}
else
{
q->front++;
q->size--;
return q->data[q->front];
}
}
void cleanQueue(queue* q)
{
//the delete function
}
The technical right answer here is to delete q->data, as others have suggested. But...
right way to free or delete it without any memory leaks
The right way in C++, unless you're doing some exotic with allocation, is not to do your own memory management. Write a class that allocates in the constructor, and deletes in the destructor, as Chris suggested, is a great way to learn about RAII and how it saves you from the mental burden of manually writing "delete" everywhere.
But the right right way, if someone was paying me? I'd skip all that and use a vector.
#include <vector>
class MyQueue {
public:
MyQueue(unsigned int size) : data(size) { }
void enqueue(unsigned int value) { /* whatever... */ }
int dequeue() { /* whatever... */ }
private:
std::vector<unsigned int> data;
};
When this class goes out of scope or gets deleted, the vector will automatically be cleaned up. You don't even need to free or delete anything.

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 :)

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.

Adding something to a dynamic array

I want to add X to the end of my Array if the array is full I double the size but i'm having trouble inserting it into newArray after I get it into newArray I use pointers to switch dynamicArray to newArray.
#include <iostream>
using namespace std;
class IntegerDynamicArray {
public:
IntegerDynamicArray();
~IntegerDynamicArray();
int add(int x);
private:
int * dynamicArray;
int currentSize=maxSize;
int maxSize=4;
};``
IntegerDynamicArray::IntegerDynamicArray()
{
dynamicArray = new int [maxSize];
}
IntegerDynamicArray::~IntegerDynamicArray()
{
delete [] dynamicArray;
}
int IntegerDynamicArray::add(int x)
{
cout<<x<<endl;
if(dynamicArray[currentSize-1]!=0)
{
int * newArray;
newArray= new int[currentSize*2];
for(int i =0;i<currentSize;i++)
{
newArray[i]=dynamicArray[i];
newArray[currentSize]=x;
}
currentSize=currentSize*2;
dynamicArray = newArray;
}
else
{
int * newArray;
newArray= new int[currentSize];
for(int i =0;i<currentSize;i++)
{
newArray[i]=dynamicArray[i];
newArray[currentSize-1]=x;
}
dynamicArray = newArray;
}
return *dynamicArray;
}
int main() {
IntegerDynamicArray intDynArray;
while (1) {
char input;
cout << "Enter A for add or anything else to quit: ";
cin >> input;
if (input == 'A') {
cout << "Enter number to add: ";
int x;
cin >> x;
cout << intDynArray.add(x) << endl;
} else {
break;
}
}
}
There are several problems with your code. Because you didn't asked a dedicated question these are the main ones:
Your class lacks a variable containing the index of the last written (or next free) index of the array. Instead you (mis)use currentSize as such index variable.
On each call of add() you allocate a new array although it might not be full already.
As already mentioned in the comments you do not delete [] your old arrays after copying into the new one.
You use 0 as indicator that a slot in your array is empty, but you do not prevent adding 0 as regular element and you do not initialize your array to zero.
As Thomas Matthews pointed out:
You are leaking memory while calling add(int x). For each use of new, there should be a call for delete
Consider the following:
int n=10;
int* x= new int[n];
//assign some values
int* temp=new int[n*2]; //create new array
for(int i=0;i<n;i++)
temp[i]=x[i]; //assign values from x
delete[] x; //free memory
x=temp; //assign to x address of new array
Manual memory managment can be risky, so consider using std::vector in future

Memory leaks passing dynamic variables recursively

I have a recursive function that requires me to create a new array every time the function is called. The function also requires the array that was previously created:
void myFunc(int* prevArray)
{
int newSize;
//do some calculations to find newSize
int* newArray;
newArray = new int[newSize];
//do some calculations to fill newArray
//check some stopping condition
myFunc(newArray);
}
This function leaks memory, but I can't avoid that by adding
delete[] newArray;
since I can only add that after calling the function again. How can I solve this?
You can solve this by making use of dynamic memory allocation.
// allocate initial size
const int INITIAL_SIZE = 5;
int *myArray = malloc(sizeof(int) * INITIAL_SIZE));
int myFunc(int *aArray, int numAllocated) {
int numElements = calculateNewSize();
if (numElements != numAllocated) {
// allocate new size
realloc(aArray, (numElements * sizeof(int));
}
return numElements;
}
Now you can call myFunc like this:
int numElements;
numElements = myFunc(myArray, numElements);
When your done using myFunc don't forget to free the memory
free(myArray);
Try something like
void myFunc(int* prevArray)
{
int newSize;
...newArray = new int[newSize];
myFunc(newArray);
delete[] newArray;
}
or better yet use std::unique_ptr to control the newArray memory. In this way you will follow the rule of thumb regarding dynamic memory - that it should have one owner, responsible for both allocating and freeing it.
You might just use a vector and swap the new result into the final result.
#include <iostream>
#include <vector>
struct X { ~X() { std::cout << "Destruction\n"; } };
void recursive(unsigned n, std::vector<X>& result) {
// Put new_result in a scope for destruction
{
std::vector<X> new_result(1);
// Do something
// The previous result is no longer needed
std::swap(result, new_result);
}
// Next recursion
if(n) {
std::cout << "Call\n";
recursive(--n, result);
}
}
int main() {
std::vector<X> result(1);
std::cout << "Call\n";
recursive(3, result);
return 0;
}