I have my own classes which implements queue and stack using LL, the source code compiles fine on my machine but after throwing it in valgrind it shows me some memory leaks
class S{
private:
struct Node{
int value;
Node* next;
Node(int v, Node* n):value(v), next(n){}
};
Node* head;
S(const S& other) {}
S& operator=(const S& other) {}
public:
S():head(NULL){}
void push(unsigned int data){
head = new Node(data, head);
}
class Q{
private:
struct Node{
int value;
Node* next;
Node(int v, Node* n):value(v), next(n){}
};
Node* head;
Node* tail;
int size;
Q(const Q& other) {}
Q& operator=(const Q& other) {}
public:
Q():head(NULL), tail(NULL), size(0){}
void push(int data){
if (head == NULL) head = tail = new Node(data, tail);
else{
tail -> next = new Node(data, tail);
tail = new Node(data, tail);
}
size++;
}
What am i doing wrong? Much help would be appreciated :) cheers
In your class constructor:
PQ(int cap){
capacity = cap;
arr = new int [capacity++];
for (int i= 0; i < capacity; i++) arr[i] = {0};}
this:
capacity++
will first return the capacity and then increase its value by one.
Because of this, when you are filling your array in a for loop, you are going out of array range, because your array size is 1 less than the capacity value.
This is not a "memory leak".
This is memory corruption. You can start fixing it by making a mental effort to understand that arrays in C++ are 0-based, not 1-based. The first element of an array is array[0] and not array[1], and everything else is based on that. The following is based on the notion that array elements start with array element #1:
int top(){
return arr[1];
}
void pop(){
arr[1] = arr[size];
The first element of an array is element #0, not element #1, but this is structured based on the concept that the first element in the array is element #1.
It might seem like adding 1 to the array size before allocating it is an easy way to avoid having to make this adjustment, but it only leads to more grief, confusion, and bugs, later down the line. This is why, apparently, the constructor attempts to increment the size of the array before allocating it:
PQ(int cap){
capacity = cap;
arr = new int [capacity++];
for (int i= 0; i < capacity; i++) arr[i] = {0};
}
Except that it increments it incorrectly. It's a post-increment, so if, for example, cap was 4, new int[4] gets allocated, before capacity gets incremented. The next line attempts to clear array elements #0 through #4, except that array element #4 doesn't exist, the code tries to initialize it, runs off the end of the array, and valgrind throws a red flag.
Although this is fixable simply by using pre-increment instead of post-increment, the correct solution is not to increment at all, but restructure the code so that it follows the natural properties of C++ arrays being 0-based, instead of 1-based.
Related
I am trying to make a network application. Its class blueprint is roughly like this-
class Node
{
public:
// member functions
private:
int nodeID;
// other members
};
class NodeNetwork
{
public:
// member functions
private:
Node nodeArray[MAX_NODES];
// other members
};
Here, the Node class will deal with each node and the NodeNetwork is used to deal with the complete network.
The actual number of nodes in nodeArray can vary from 0 to MAX_NODES during runtime, i.e., it may not always be MAX_NODES, the number of nodes can be increased or decreased during runtime. Moreover, when the program starts the number will always be 0, after that it will start increasing.
I am using Node nodeArray[MAX_NODES];, but I think it's a serious wastage of space as not always I will have MAX_NODES nodes at runtime. So I am looking for ways to optimize it. I want it so that it starts with a zero-length array, but the size can be increased or decreased subjected to the above constraints based on the nodes added or removed at runtime. I researched on the internet but did not find any concrete answer.
I hope someone can help me solve this problem, thanks in advance.
You can use dynamically array allocation for this purpose:
int* arr = new int[5];
..and anytime you wish to change the number of elements:
int size = 5;
int* arr = new int[size] {};
int* new_arr = new int[size + 1];
for (int i = 0; i < size; i++)
{
new_arr[i] = arr[i];
}
delete[] arr;
arr = new_arr;
// Now arr has a storage capacity of 6 elements
..so for your case you can write:
Node* nodeArray = nullptr; // nullptr == null pointer
But this can take a lot of time for huge arrays.
So preferably, you can use std::vector:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vec{ 1, 2, 3, 4, 5 };
vec.push_back(6); //Insert a new element
std::cout << vec[0]; // Accessing an element is the same as an array
}
..so for your case:
// {} is just for initialization, not exactly mandatory
std::vector<Node> nodeArray{};
You can use std::vector instead of array. That is, you can make the data member nodeArray to be a std::vector<Node> as shown below.
#include <iostream>
#include<vector>
class Node
{
public:
//constructor for initializing nodeID data member
Node(int pnodeID): nodeID(pnodeID)
{
}
//getter for nodeId
int getId() const
{
return nodeID;
}
private:
//always initialize built in type in local/block scope so that they don't have indeterminate value
int nodeID = 0;
// other members
};
class NodeNetwork
{
public:
// member function to add Node
void addNode(const Node& n)
{
nodeArray.push_back(n);
}
//member function to print out the current nodes
void display() const
{
std::cout<<"Network has the following nodes: "<<std::endl;
for(const Node& elem: nodeArray)
{
std::cout<<elem.getId()<<std::endl;
}
}
private:
std::vector<Node> nodeArray; //used std::vector instead of array
// other members
};
int main()
{
//create Node objects
Node node1{1};
Node node2{2};
Node node3{3};
NodeNetwork network1;
//add node1 into the network1's nodeArray data member
network1.addNode(node1);
//add node2 into the network1's nodeArray data member
network1.addNode(node2);
//display all nodes into network1
network1.display();
return 0;
}
In the above demo we have added elements into the nodeArray data member by using std::vector::push_back member function.
The output of the above program can be seen here:
Network has the following nodes:
1
2
I am implementing an ADT Stack using an array. I want to doubling the size of the array when the stack is full.
const int MAX_SIZE = 6 // max size of array stack
template<class ItemType>
class ArrayStack: public StackInterface<ItemType>{
private:
ItemType items[MAX_SIZE]; // Array of stack items
int top; // index of top
int itemCount; // Amount of items in stack
int maxsize;
This is my push method:
template<class ItemType>
bool ArrayStack<ItemType>::push(const ItemType& newEntry){
if(itemCount == maxsize){ // resize array
cout << "resizing an array..." << endl; // just for testing
ItemType* oldArray = items; // old array to be deleted
ItemType* newItems = new ItemType[2*maxsize];
for(int i=0; i<maxsize; i++){
newItems[i] = oldArray[i]; // copying all array items
}
delete[] oldArray; // deallocate
maxsize = maxsize * 2; // doubling max size
items = newItems; <- I'm getting error from this code
} // end if
// Stack is not full
top++;
items[top] = newEntry;
itemCount++;
return true;
}
I'm getting this error while I'm trying to double the size of the array:
error: array type 'int [6]' is not assignable
items = newItems;
How can I solve this?
ItemType items[MAX_SIZE]; is a fixed array. You can't resize it, you can't reallocate it, and you certainly can't assign an ItemType* pointer to it.
For what you are attempting to do, items needs to be an ItemType* pointer instead of an ItemType[] array:
template<class ItemType>
class ArrayStack: public StackInterface<ItemType>{
private:
ItemType *items; // Array of stack items
...
};
Don't forget to initialize items in your constructor(s), and call delete[] items; in the destructor, and also implement proper copy/move constructors and copy/move assignment operators, per the Rule of 3/5/0.
I'm creating a stack class as an exercise trying to learn some c++ concepts (initializer lists, memory management and templates here). I've run into something that I can't get my head around.
In function void Stack::push(const T& item), if I uncomment the delete [] data; line, my code runs well when the template argument is for example int or char. But with std::string, I get weird memory errors.
My thinking here is that I need a bigger array -> arrays can't be resized -> I create a new one -> I deallocate the memory I needed for the one that's soon to be not needed -> I make the existing pointer point to a new memory address where I create the bigger array.
Now, when I comment the delete line, the code runs well even with std::string, but I can't see why I can't do the delete operation safely with all types.
Any insights will be appreciated.
#include <iostream>
#include <stdio.h>
#include <memory.h>
template<class T>
class Stack
{
T* data;
int sz;
public:
//Stack(){sz=0;}
Stack(const std::initializer_list<T>&);
~Stack();
void push(const T&);
T& pop();
void show() const;
};
template<class T>
Stack<T>::Stack(const std::initializer_list<T> &list)
{
sz=0;
data = new T[list.size()];
for (auto i : list) {
data[sz] = i;
++sz;
}
std::cout<< "Created with sz: "<< sz<<std::endl;
}
template<class T>
Stack<T>::~Stack()
{
delete [] data;
}
template<class T>
void Stack<T>::push(const T& item) {
std::cout<<"push "<<item<<std::endl;
T* arr = new T[sz];
memcpy(arr, data, sz*sizeof(T));
//delete [] data;
data = new T[sz + 1];
memcpy(data, arr, sz*sizeof(T));
++sz;
data[sz - 1] = item;
std::cout<<"new size: "<<sz<<", bytes: "<<sz*sizeof(T)<<std::endl;
}
template<class T>
T& Stack<T>::pop()
{
if(sz > 0) {
std::cout<<"pop "<<data[sz-1]<<std::endl;
std::cout<<"new size: "<<sz-1<<std::endl;
return data[--sz];
}
else
return data[0];
}
template<class T>
void Stack<T>::show() const
{
for (int i=0; i<sz; i++) {
std::cout<<data[i]<<" ";
}
std::cout<<std::endl;
}
int main(){
Stack<int> s = {1,2,3,4,5,6,7,8,9,10,11};
s.show();
s.push(12);
s.push(13);
s.push(14);
s.pop();
s.pop();
s.push(15);
s.push(16);
s.show();
Stack<std::string> d = {"one","two","three"};
d.show();
d.pop();
d.push("four");
d.show();
return 0;
}
Don't use memcpy to copy objects, that will copy the bits alright, but for some object a bit-wise copy is not correct as the copy constructor (or copy assignment operator) Will not be used.
A good and simple example is if you have a stack of std::string objects. When you do a bit-wise copy (with memcpy) the contents of the std::string objects are copied, but that basically is just a pointer and a size. When you do a bit-wise copy then you will have two std::string objects referencing the same memory. Destroying one of those object will lead to the other having a stray pointer to some memory (that used to contain the string) that no longer is owned by your program.
To solve this use std::copy instead to copy the objects, it will do the right thing.
Unrelated to your problem, but your push function does a copy that it doesn't need:
T* arr = new T[sz];
memcpy(arr, data, sz*sizeof(T));
This is simply not needed, instead do something like
T* oldData = data;
data = new T[sz + 1];
// Copy from old array to new
std::copy(oldData, oldData + sz, data);
delete[] oldData;
I am trying create my own vector, I am at the beginning, and when compile e execute the code, i get "Program not responding". This is the code:
struct X
{
X(){};
~X(){};
int v1, v2, v3;
};
template<typename T>
class Vector
{
public:
// constructors
Vector();
Vector(unsigned s);
virtual ~Vector();
// overloaded operators
T operator[](unsigned index);
// others
void clear();
void add(T value);
unsigned getSize();
bool isEmpty();
private:
// pointer to first item of memory block
T* first;
unsigned size;
};
template<typename T>
Vector<T>::Vector()
{
first = NULL;
size = 0;
}
template<typename T>
Vector<T>::Vector(unsigned s)
{
size = s;
first = new T[s];
};
template<typename T>
Vector<T>::~Vector()
{
clear();
}
template<typename T>
void Vector<T>::clear()
{
for(unsigned i = size ; i > 0 ; i--)
delete &first[i];
first = NULL;
}
template<typename T>
void Vector<T>::add(T value)
{
T* temp = new T[size + 1]; // error happens here
// copy data to new location
for(unsigned i = 0 ; i < size ; i++)
temp[i] = first[i];
// delete older data
clear();
// add the new value in last index
temp[size + 1] = value;
// update the pointer
first = temp;
size++;
}
template<typename T>
T Vector<T>::operator[](unsigned index)
{
return first[index];
}
template<typename T>
unsigned Vector<T>::getSize()
{
return size;
}
template<typename T>
bool Vector<T>::isEmpty()
{
return first == NULL;
}
int main(int argc, char* args[])
{
Vector<X> anything;
X thing;
anything.add(thing);
anything.add(thing);
anything.add(thing); // if remove this line, program work fine.
}
As I commented, error happens in T* temp = new T[size + 1];.
If i define the value of v1, v2, v3 of X class, e.g. X() : v1(0), v2(0), v3(0) { }, the program works correctly.
If i change the type, e.g., Vector of int, he works perfectly.
If put X class in std::vector, work fine too.
Other comments are also accepted.
Can someone helpme?
Your description of the problem is incredibly vague, but I can point out problems with your code:
No vector copy constructor (causes double-deletes and crashes)
No vector copy assignment (causes double-deletes and crashes)
clear is incorrectly calling delete (causes crashes and corruption) (you should match your single new of an array with a single delete of the array. Don't loop over elements.
add is writing past the end of the array (causes crashes and corruption)
add is not exception safe
You have to fix at least the first four. The third and fourth are probably the causes of your hang.
You have a buffer overflow occurring.
T* temp = new T[size + 1]; // When size is 0, you allocate 1 space.
You then assign to the temp array, but in location temp[1], which isn't a valid location because your array has only 1 element. This is undefined behavior, and that this point, your program is free to continue however it chooses. In this case, it seems to loop indefinitely.
// add the new value in last index
temp[size + 1] = value; // When size is zero, your array is length '1', but
// you are accessing temp[1] which is outside the
// bounds of your allocated memory.
I have this class for double linked lists:
template <typename T>
class Akeraios
{
struct node
{
T data;
node* prev;
node* next;
node(T t, node* p, node* n) : data(t), prev(p), next(n) {}
};
node* head;
node* tail;
public:
Akeraios() : head( NULL ), tail ( NULL ) {}
template<int N>
Akeraios( T (&arr) [N]) : head( NULL ), tail ( NULL ) //meta apo : simainei einai initializer list--arxikopoiisi listas
{
for( int i(0); i != N; ++i)
push_back(arr[i]);
}
bool empty() const { return ( !head || !tail ); }
operator bool() const { return !empty(); }
void push_back(T);
void push_front(T);
T pop_back();
T pop_front();
~Akeraios()
{
while(head)
{
node* temp(head);
head=head->next;
delete temp;
}
}
};
and somewhere in main
int arr[num1len];
int i=1;
Akeraios <int> dlist ( arr );//error line!!
for(i=1;i<=num1len;i++){
double digit;
int div=10;
int j;
for(j=1;j<=i;j++)div=div*div;
digit=number1/div;
int dig=(int) digit;
the error in error line is:
no matching function for call to `Akeraios::Akeraios(int[((unsigned int)((int)num1len))])'
candidates are: Akeraios::Akeraios(const Akeraios&)
note Akeraios::Akeraios() [with T = int]
try this:
Akeraios <int>* dlist = new Akeraios( arr );
your compiler thinks you're calling a function doing it the way you do it.
you could also use the implicit constructor
Akeraios<int> dlist = arr;
(not very nice this is)
This code is perfectly valid and compliant as-is. The only way I can see it messing up is if you had a compiler extension for VLAs and attempted to call the constructor with a variable-length array, which would almost certainly fail. Otherwise, it is perfectly legitimate. Visual Studio accepts without quarrel.
Since you're saying that num1len is a variable:
Templates are evaluated at compile-time. When you say arr[num1len], you're specifying an array with a variable length (is this C99 or something?). The template expects an array with a size that can be evaluated at compile time (you're saying template<int N>Akeraios( T (&arr) [N]), so there's no way the compiler can match that up.
Just imagine you had a specialization for N=5 or N=10. How would the compiler be able to find the right specialization when compiling the code if the size of the array is not known at that point?