I'm working on an assignment which involves updating the size of a dynamic array to store repeated inputs, with a value of -1 signifying the end of input. When I use this code:
bool end = false;
int curr;
int n = 0;
int* currArr = new int[n];
int* temp = NULL;
while (end == false) {
cin >> curr;
if (curr == -1) {
end = true;
}
else {
n++;
int* temp = new int[n];
temp = currArr;
temp[n - 1] = curr;
currArr = temp;
}
}
delete[] currArr;
delete[] temp;
am I defining a memory address for temp, changing what is stored at that address during each iteration, then cleanly deleting the contents of that address at the end?
Or am I allocating a new dynamic array during each iteration, only deleting the array defined in the final iteration, and leaking the rest? If so, how would I avoid that?
Similarly, if I define a dynamic array within a function like so:
int* fxn(int size) {
int* x = new int[size];
return &x[0];
}
int main() {
int* y = fxn(size);
delete[] y;
return 0;
}
My understanding is that deleting y will delete the array because y is pointing to the same address that x pointed to within the function. If fxn were a void function, x would need to be deleted within fxn, because fxn would not output any information to the main with which to locate x.
Am I understanding it correctly?
Thanks!
Each time you allocate memory and assign your previous allocated pointer to the newly allocated memory, you should delete the previous one. Otherwise it results in a memory leak. In your case curArr keeps pointing to the new address in the loop but previous is never deleted. Then your delete of both curArr and temp will crash because they are pointing to the same location, so you're deleting the same pointer twice. And assinging temp to curArray after allocating it, you just lost the newly allocated pointer again. So the code is a giant mess that's full of leaks and crashes. You're also initially allocating a memory of size 0 which is undefined behavior.
#include <iostream>
#include <memory>
using namespace std;
int main(){
bool end = false;
int curr;
int n = 1;
int* currArr = new int[n];
while (end == false) {
cin >> curr;
if (curr == -1) {
end = true;
}
else {
currArr[n - 1] = curr;
int* temp = new int[n+1];
memcpy(temp, currArr, n*sizeof(int));
delete[] currArr;
currArr = temp;
++n;
}
}
for(int index = 0; index < n-1; ++index){
std::cout << currArr[index]<< std::endl;
}
delete[] currArr;
}
I got rid of redundancies in your code and fixed up the leaks.
The code will initially allocate memory with a size of n=1. Then whatever the user enters into curr will be placed at index n-1. Then new memory will be allocated using temp to size of n+1. The previous memory from curArr will be copied into the newly allocated region. The previous region of curArr will be deleted and the pointer will be assigned to the new region.
And yes. Your understanding of your second question is correct.
int* temp = new int[n];
This allocates a new int array, in dynamic scope, assigning the allocated array to temp. Immediately afterwards:
temp = currArr;
This takes the newly-allocated array, temp, and immediately overwrites this pointer with an existing pointer currArr. The newly-allocated memory is leaked, and when is all and said and done, both temp and currArr are now the same pointer value (the second assignment, two lines later, does not change this, it's already too late).
delete[] currArr;
delete[] temp;
Therefore, this ends up delete[] ing the same pointer value twice, resulting in undefined behavior, memory corruption, and a likely crash.
Additionally, even if the allocation in the loop is fixed so it doesn't get clobbered, since the loop can execute more than once, and this deletes anything only at the conclusion of the loop, there's no way to avoid leaking memory, in any case.
am I defining a memory address for temp, changing what is stored at
that address during each iteration, then cleanly deleting the contents
of that address at the end?
No, you're leaking memory, corrupting memory, and causing undefined behavior, and a likely crash.
You need to fix the initial allocation, so it doesn't get clobbered, and delete the previous buffer (currArray) immediately after allocating the new one (temp), and then, finally, assign temp to currArray (after copying its contents).
Related
bool StudentList::remove(const char * studentName)
{
for (int i = 0; i < MAX_SIZE; i++)
{
if (this->students[i]->isEqualTo(studentName)) // Finds a name to remove
{
cout << "Remove: "; // Displays name wished to be removed
students[i]->print();
// delete[] students[i]; - Crashes
// students[i] = NULL; - Replaces removed name with null, stops working.
// students[i]->~Student(); - Call deconstructor, Crashes.
return true;
}
}
return false;
}
I just want to remove a single element out of the array, but keeps crashing when i delete that element.
students[i] is a pointer array, and i need to remove selected elements
First quetion, if you really need to delete "Student" object. If yes, you can add some bad code like:
students[i] = nullptr;
If your students are stored not only in this array, you can make that storage responsible for their deleting. But both ways aren't very good because of using null pointers later. Learn how to use collections, for example vector. You will be able just remove the pointer from an array.
It seems that you want to delete each instance of students, if you could find the studentname.
students seems a two dimensional structure pointer to a pointer. ie; **students. But, you are deleting it in wrong way.As you first need to delete the instance of students[i], then delete the instance of students.
Also, since you are calling the destructor students[i]->~Student(); after deleting instance, it may crash again, as you have assigned student[i] = NULL. then it will be, NULL->~Student() -it will also lead crash.
You need to delete it in following way :
for (int i = 0; i < MAX_SIZE; i++)
{
if (this->students[i]->isEqualTo(studentName)) // Finds a name to remove
{
students[i]->~Student();
delete students[i];
students[i] = NULL;
}
}
delete[] students;
students = NULL;
I want to resize the array when the rehash function is called, by copying the values of initial dictionary into it and then at last redifining the newdictionary as dictionary
void rehash ()
{
int newsize=2*Size;
node **newdictionary;
newdictionary= new node*[newsize];
//Initialising the dictionary
for (int i = 0;i < newsize;i++)
{
newdictionary[i]->name = "";
newdictionary[i]->value = -1;
}
node **temp=dictionary;
delete [] dictionary;
dictionary=newdictionary;
SIZE=newsize;
for(int i=0;i<SIZE;i++)
{
if(temp[i]->value!= -1)
insertvalue(temp[i]->name,temp[i]->value);
}
delete [] temp;
};
Earlier I have defined insertvalue as:
void insertvalue (string filedata, int code)
{
// tableindex is the position where I want to insert the value
dictionary[tableindex]->name= filedata;
dictionary[tableindex]->value=code;
};
You didn't actually explain what problem(s) you're having, but your code has several issues:
void rehash ()
{
int newsize=2*Size;
node **newdictionary;
newdictionary= new node*[newsize];
At this point, newdictionary is simply an array of uninitialized pointers.
//Initialising the dictionary
for (int i = 0;i < newsize;i++)
{
newdictionary[i]->name = "";
newdictionary[i]->value = -1;
}
So the loop above is trying to access the members of node objects that don't yet exist.
node **temp=dictionary;
delete [] dictionary;
These two lines don't make sense. dictionary and temp point to the same memory. So when you delete dictinoary you've deleted the memory that temp is pointing to.
dictionary=newdictionary;
SIZE=newsize;
for(int i=0;i<SIZE;i++)
{
if(temp[i]->value!= -1)
insertvalue(temp[i]->name,temp[i]->value);
}
Even if you hadn't just deleted the memory out from under temp, you're now trying to access temp from 0 to the new size, not the old size. In other words, this would access temp beyond its bounds.
Those are the major problems that I've noticed in the code so far. You at least need to correct all of them before there's any hope of this working. You probably need to spend some time really stepping through your logic to ensure it makes sense in the end.
I'm trying to implement an unbounded array: What is an unbounded array?
More details on this page:
http://www.cs.cmu.edu/~fp/courses/15122-s11/lectures/12-ubarrays.pdf
This is the code:
#include <iostream>
#include <cstdlib>
using namespace std;
class UBArray
{
public:
int *arr, *arrN, j, *pos; //Initial array is arr. The position of arr is stored in pos. arrN is the new array created when size = limit.
int size, limit; //size is the current size of the array and limit is the total size available untill a new array is created.
UBArray()
{
size = 0;
limit = 10;
arr = new int[10];
pos = arr;
}
private:
void increment()
{
// New array arrN is created and then the values in the old arrays is put into the new array.
// Limit is increased by 10 - this is the extra space the new array contributres.
// pos which carries the address of the current array now carries the address of the new array.
// Later when a new array is created its address will be on the heap which is empty. This address is replace the address stored
// in the arrN. The older array can still be accessed for the array updation process by using the variable pos.
// IMPORTANT: I had initially tried to delete the older array to space space but while trying to debug the segmentation fault, I have
// removed it. I will be adding it again once the error has been fixed.
arrN = new int[size + 10];
for (j = 0; j < size; j++)
{
arrN[j] = pos[j];
}
limit = limit + 10;
pos = arrN;
}
public:
void push(int n)
{
if (size<limit)
{
size++;
pos[size-1]=n;
}
else
{
increment();
push(n);
}
}
int pop()
{
int p = pos[size-1];
size--;
return p;
}
};
int main()
{
UBArray array;
int num;
cout << "Enter 36 elements: ";
for (int k = 0; k<36; k++)
{
cin >> num;
array.push(num);
}
cout << endl << "The last element is : " << array.pop();
}
I have tried to give comments in the code to make it understandable to the reader. I'm copying some of it here:
Initial array is arr. The position of arr is stored in pos. arrN is the new array created when size = limit.
size is the current size of the array and limit is the total size available until a new array is created.
New array arrN is created and then the values in the old array are put into the new array.
Limit is increased by 10 - this is the extra space the new array contributres.
pos which carries the address of the current array now carries the address of the new array.
Later when a new array is created its address will be on the heap which is empty. This address is replaced the address of arrN. The older array can still be accessed for the array updation process by using the variable pos which will be updated by the old values have been copied to the new one.
I get segmentation fault during execution. I have tried to use cout statements to debug the code but it seems really confusing. I could see loops both inside and outside the for loop inside the increment method. I'm unable to figure out much. Any help is appreciated.
UPDATE: As pointed out by jrok, I changed the code and the seg fault is gone. But I'm getting seg fault again at the creation of the 3rd array.
UPDATE 2 Everything fixed now. Thank you.
arr = new int(10*sizeof(int));
That creates a single int, initialized to the value of 10*sizeof(int). The loop you wrote right after this statement runs out of bounds and it's cause of segmentation fault.
What you want is the array form of new:
arr = new int[10]; // note 10 only, new expression knows the size
// of the type it allocates
Note that when you assign the pointer to the new array to the pointer to the old array you lose the handle to it and create a memory leak:
int* arr = new int[10];
int* new_arr = new int[20];
arr = new_arr; // original array at arr has leaked
You need to delete[] arr before you reassign it. Also, I see no use for the third (pos) pointer. Not even for arrN, for that matter. One will do. Create a local pointer inside increment and assign it to arr when you're done deallocating the old array.
Finally, what people have been telling you in the comments, unless this is a learning exercise, don't try to reinvent the wheel and use std::vector instead.
An unbounded array only needs 3 data members (rather than 6): the address of the beginning of the data buffer, the capacity of the buffer, and the actual size (of the part of the buffer used so far). When expanding, you will temporarily need to hold the address of the new buffer in an automatic variable. Also, you should avoid leaking the memory of previous buffers. A simple layout is like this:
struct ua
{
int size,capacity,*buff; // 3 data members only
ua(int n) // constructor: n = initial capacity
: size(0) // initially empty
, capacity(n<0?0:n) // guard against n<0
, buff(capacity?new int[capacity]:0) {} // only allocate if n>0
~ua() { delete[] buff; } // destructor: note: delete[] 0 is ok
void empty() const { return size==0; } // is array empty?
void push(int x) // add another datum at back
{
if(size==capacity) { // buffer is full: we must expand
if(capacity) capacity+=capacity; // double capacity
else capacity=1; // but ensure capacity>0
int*nbuff=new int[capacity]; // obtain new buffer
if(size)
memcpy(nbuff,buff,size*sizeof(int)); // copy data from old to new buffer
delete[] buff; // free memory form old buffer
buff=nbuff; // set member buff to new buffer
}
buff[size++]=x; // write; increment size (post-fix)
}
int pop() // ill-defined if empty()
{ return buff[--size]; } // read; decrement size (pre-fix)
int operator[](int i) const // ill-defined if i<0 or i>=size
{ return buff[i]; }
int&operator[](int i) // ill-defined if i<0 or i>=size
{ return buff[i]; }
// you may add more functionality, for example:
void shrink(); // reduces capacity to size
void reserve(int n); // extends capacity to n, keeping data
ua(ua const&other); // copy buffered data of other
void swap(ua&other); // swap contents with other (no copying!)
};
Ok, first of all I've written the method, searched stackoverflow beforehand, and noticed my
idea matched the way most people did it, but, the stack doesn't actually get reversed, but instead weird values are put in it:
I'm doing it like this: I make an auxiliary stack and a while loop with the condition size != 0, and then I call aux.push(pop()) since the pop method also returns the deleted element, so the stack should be reversed, and in O(n) time complexity. But, this happens:
STACK TO BE REVERSED: A C D F -> RESULT: Đ Đ `
I ran a memory leak tester, it told me I had 4 times tried to free up already freed space, so I'm thinking that might be the cause.
More details:
Stack implemented as dynamic array
Here is the code with the relevant functions:
template<typename T>
bool NizStek<T>::push(const T& element){
if(_size == _capacity) increaseCapacity();
if(_size == 0){
_brojE++;
_top++;
_array[_top] = new T(element);
}
else{
_size++;
++_top;
_array[_top] = new T(element);
}
}
POP FUNCTION:
template<typename T>
T NizStek<T>::pop(){
if(_size == 0) throw "Stack is empty";
T oldTop = *_array[_top];
delete _array[_top];
_top--;
_size--;
return oldTop;
}
Reverse function:
template<typename T>
void NizStek<T>::reverse() {
NizStek<T> aux;
while(size() != 0){
aux.push(pop());
}
*this = aux;
}
COPY CONSTRUCTOR(OPERATOR = is the same with the first line being delete[] _array;)
template<typename T>
NizStek<T>::NizStek(const NizStek& rhs){
_size = rhs._size;
_capacity = rhs._capacity;
_niz = new T*[_capacity];
for(int i=0; i<_size ;i++) _array[i] = rhs._array[i];
_top = rhs._top;
}
Thanks in advance!
Since you haven't shown it, I'm guessing you are letting the compiler create your copy constructor, which will do a shallow copy. So this:
template<typename T>
void NizStek<T>::reverse()
{
NizStek<T> aux;
while(size() != 0)
{
aux.push(pop());
}
*this = aux; // Potential problem here!
}
Will set this equal to aux's pointer values. Presumably, your destructor frees up the memory, so when aux goes out of scope, the items pointed to in this (this->_array) are no longer allocated ... so you get junk when you attempt to dereference them.
You can fix that by writing your own copy-constructor and actually doing a deep copy of the data (or use move semantics).
EDIT
With your updated copy constructor, you appear to have another issue:
_niz = new T*[_capacity];
for(int i=0; i<_size ;i++)
_array[i] = rhs._array[i]; // this is still a shallow copy!
_top = rhs._top;
The allocation will create an array of pointers, not an array of objects. So you'll have an array of unassigned pointers (this and aux will be pointing to the same items, so when aux clears them out in its destructor, you are still pointing to junk). I think what you wanted was
_niz = new T[_capacity]; // note the lack of *
for(int i=0; i<_size ;i++)
_array[i] = rhs._array[i];
_top = rhs._top;
Or
_niz = new T*[_capacity];
for(int i=0; i<_size ;i++)
{
_array[i] = new T(*rhs._array[i]); // actually do a deep copy
}
_top = rhs._top;
As a side note, if you are concerned about efficiency, you'll probably want to either use a fixed size array, or use a linked-list. Reallocating and copying the memory buffer every time you push an item that requires a new capacity will be very inefficient for a stack structure.
i am starting homework about dynamic array, first, I have a 2 dimensional array :
int initializeInfo[3][4] ={{77,68,0,0},{96,87,89,78},{70,90,86,0}};
and use pointer to store it:
int **ptr = (int**)malloc(3*sizeof(int));
int size = 0;
for(int i =0;i<3;i++){
addInitiazeInfo(ptr,initializeInfo[i],size);
}
here is function addInitiazeInfo:
void addInitiazeInfo(int**& ptr, int arr[],int& size){
ptr[size] = (int*)malloc(4*sizeof(int));
if(ptr[size] == NULL){
return;
}
ptr[size] = arr;
size++;
}
It's run OK! The 2 dimensional array is store by ptr pointer.
And I want to add new row, I think realloc is needed, then I try:
int arr[] = {3,4,5,6};
size++;
ptr = (int**)realloc(ptr,size * sizeof( int ) );
ptr[size-1] = (int*)malloc(4*sizeof(int));
ptr[size-1] = arr;
But I think this is my trouble, the output make me hard to know how it happend:
please help me, thanks everyone
When you do
ptr[size] = arr;
You are essentially assigning the address of arr, to ptr[size]. This means that the memory you just allocated is lost and successfully leaked.
You want to manually copy element by element or use something like memcpy. It is likely this might fix your issue, depending on the rest of your code.