So my program executes as expected and prints out the correct result. The only issue is that after it is done it does not exit. If I wait a few more seconds windows pops up an error message saying "bignumbs.exe has stopped working". Here is the code to the new function which seems to be causing the problem.
void BigInt::u_basic_mult(const BigInt& n, int digs)
{
const base_int* tptr = n.used > used ? n.data : data;
const base_int* bptr = tptr == data ? n.data : data;
const int tlen = tptr == data ? used : n.used;
const int blen = bptr == data ? used : n.used;
if(digs < 1)
digs = tlen + blen + 1;
base_int* new_data = new base_int[digs];
for(int i = 0; i < digs; ++i)
*new_data++ = 0;
for(int i = 0; i < blen; ++i)
{
int stop_pt = MIN(tlen, digs - i);
overflow_int carry = 0;
overflow_int btmp = bptr[i];
for(int j = 0; j < stop_pt; ++j)
{
overflow_int prod = btmp * tptr[j] + carry;
carry = prod >> BASE_BITS;
overflow_int sum = new_data[i + j] + carry + (prod & MAX_DIG);
carry += sum >> BASE_BITS;
new_data[i + j] = sum;
}
}
//delete[] data; these two lines cause the error
//data = new_data;
used = digs;
alloc = digs;
strip_zeros();
}
Notice the two lines I commented out. Without them the program executes and finishes (although now the result is incorrect). What is it about changing the value of a pointer or deleting it which could make my program have this strange error? Also I am pretty sure data is valid since I use it in the code above.
Also I am compiling with G++ through Netbeans.
After inspecting further it seems that the problem may be with my deconstructor. If I comment out the delete[] data in the deconstructor the error seems to go away. I don't know why.
BigInt::~BigInt()
{
if(data) delete[] data;
}
for(int i = 0; i < digs; ++i)
*new_data++ = 0;
This code is modifying where the new_data pointer is pointing at, so that it is no longer pointing at the original array when you enter the subsequent loop, or do anything with it for that matter. The pointer you pass to delete[] must be pointing at the same memory address that new[] returned.
The correct way to zero-initialize the array is to do this instead:
for(int i = 0; i < digs; ++i)
new_data[i] = 0;
Or, get rid of the loop and just use memset() instead:
memset(new_data, 0, digs * sizeof(base_int));
You must be very careful about matching up uses of new and delete. If you allocate something using the array form of new, you must delete it using the array form of delete. If you mix-and-match the array and non-array forms, you'll get crashes like this. You also must never delete something that wasn't allocated with new, and you must never delete the same thing twice.
I can't give you any more specific advice about this particular program, because you do not show us where the pointer named data is allocated.
I got it. I managed to screw up my new_data pointer.
for(int i = 0; i < digs; ++i)
*new_data++ = 0;
I changed it to this.
for(int i = 0; i < digs; ++i)
new_data[i] = 0;
Related
void CMPT135_String::append(const CMPT135_String &s) /*12*/
{
char *temp = new char[this->getLength()+1];
int len = CMPT135_String::cstrlen(buffer);
for (int i =0; i < len; i++)
temp[i] = this->operator[](i);
for (int i = 0; i < s.getLength()+1; i++)
temp[len+i] = s[i];
if(this->getLength() >0)
delete[] this->buffer;
this->buffer = temp;
}
I have been working with this append() member function for a custom string class.
The function works fine, but after it runs I get a popup window showing up:
Windows has triggered a breakpoint in CMPT135_Assignment1.exe.
This may be due to a corruption of the heap, which indicates a bug in Assignment1.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while CMPT135_Assignment1.exe has focus.
The output window may have more diagnostic information.
Please tell me what is going wrong with this.
You are not allocating enough memory for the new buffer. You are only allocating enough memory to copy this->getLength() number of characters from this, there is no room to also copy s.getLength() number of characters from s into that new buffer, so your second loop is corrupting random memory past the end of the new buffer.
Try something more like this instead:
void CMPT135_String::append(const CMPT135_String &s) /*12*/
{
int this_len = this->getLength();
int s_len = s.getLength();
int new_len = this_len + s_len;
char *temp = new char[new_len + 1];
for (int i = 0; i < this_len; ++i)
temp[i] = this->operator[](i);
for (int i = 0; i < s_len; i++)
temp[this_len + i] = s[i];
temp[new_len] = '\0';
delete[] this->buffer;
this->buffer = temp;
}
I have an array called int **grid that is set up in Amazon::initGrid() and is made to be a [16][16] grid with new. I set every array value to 0 and then set [2][2] to 32. Now when I leave initGrid() and come back in getGrid() it has lost its value and is now 0x0000.
I don't know what to try, the solution seems to be really simple, but I'm just not getting it. Somehow the data isn't being kept in g_amazon but I could post the code.
// Returns a pointer to grid
int** Amazon::getGridVal()
{
char buf[100];
sprintf_s(buf, "Hello %d\n", grid[2][2]);
return grid;
}
int Amazon::initGrid()
{
int** grid = 0;
grid = new int* [16];
for (int i = 0; i < 16; i++)
{
grid[i] = new int[16];
for (int j = 0; j < 16; j++)
{
grid[i][j] = 0;
}
}
grid[2][2] = 32;
return 0;
}
int **grid;
g_amazon = Amazon::getInstance();
g_amazon->initGrid();
grid = g_amazon->getGridVal();
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 16; j++)
{
int index;
index = (width * 4 * i) + (4 * j);
int gridval;
gridval = grid[i][j];
lpBits[index] = gridval;
lpBits[index + 1] = gridval;
lpBits[index + 2] = gridval;
}
}
It crashes when I run it at the line where sprintf_s prints out [2][2] and it also crashes when I get to gridval = grid[i][j] because it's at memory location 0x000000.
The variable
int** grid
in the initGrid() function is a local variable. Edit** When the function returns the variable is popped off the stack. However, since it was declared with the new operator the memory still exists on the heap; it is simply just not pointed to by your global grid variable.
#Dean said in comment:
I have grid as an int** grid; in class Amazon {}; so shouldn't it stay in memory or do I need a static var.
That is the problem:
local int **grid; on Amazon::initGrid::
is masking
member int **grid; on Amazon::
as the first context has higher priority in name lookup.
So initGrid() allocates memory referenced only by a local pointer. That pointer no longer exists when you return from this function, Amazon::grid was never touched on initialization and you're also left with some bad memory issues.
So, as commented by #Remy-Lebeau, I also suggest
Consider using std::vector> or std::array, 16> instead. There is no good reason to use new[] manually in this situation.
My class assignment is to create a program using OOP that creates a dynamic array that can act like a vector. My remove entry function is crashing when I run it. After messing around with it for a while I can't seem to make it stop crashing no matter what I do. Here are the instructions for this function in particular.
The function should search dynamicArray for the string.If not found, it returns false. If found, it creates a new dynamic array one element smaller than dynamicArray. It should copy all elements except the input string into the new array, delete dynamicArray, decrement size, and return true.
bool dynamicStringArray::deleteEntry(std::string oldString)
{
for (int i = 0; i < size; i++){
if (dynamicArray[i].compare(oldString) == 0){
std::string* shortArray = new std::string[size - 1];
delete &dynamicArray[i];
for (int j = 0; j < size - 1; j++)
shortArray[j] = dynamicArray[j];
size--;
for (int j = 0; j < size; j++)
dynamicArray[j] = shortArray[j];
return 1;
}
}
return 0;
}
You have a bit of misunderstanding about what
delete &dynamicArray[i];
does.
It does not remove the i-th entry from dynamicArray. It tries to deallocate memory of one objet -- the i-th object. That in itself is cause for undefined behavior.
You may not call delete on a pointer unless it was returned by a call to new.
The second problems is that dynamicArray continues to have that pointer as the i-th element.
Here's an updated if statement that should work.
if (dynamicArray[i].compare(oldString) == 0) {
std::string* shortArray = new std::string[size - 1];
// Copy everything form dynamicArray to shortArray except
// the i-th element.
for (int j = 0; j < i; j++)
{
shortArray[j] = dynamicArray[j];
}
for (int j = i+1; j < size; j++)
{
shortArray[j-1] = dynamicArray[j];
}
// Delete old array
delete dynamicArray;
// Make the newly allocated array the array of
// the object.
dynamicArray = shortArray;
// Decrement the size
--size;
return 1;
}
I've been tasked with implementing a stack using arrays However, when I run the program it says _BLOCK_TYPE_IS_VALID(pHead -> nBlockUse). The debugger directed me to the delete statement in the resize function, but I'm unsure how to fix the problem.
Note: I'm trying to do so without using vectors.
void resize(){
Type* temp = new Type[asz + 2]; // store old values
for (int i = 0; i < asz; ++i){ temp[i] = arr[i]; }
delete[asz] arr; // delete old array
arr = temp; // keep new larger arr
delete[] temp;
asz =+2; // array size
}
Here's a couple of changes that may fix your problem. You don't initialise sz, your final for-loop was copying according to the new increased size, yet tempwas only the old size. You also don't appear to set the new sz anywhere. Could be any or all of these that cause a memory overwrite invalidating the debug blocks and causing the assertion you have seen.
void resize(Type& arg){
Type* temp = new Type[arg.sz]; // store old values
for (int i = 0; i < arg.sz; ++i){ temp[i] = arg[i]; }
int oldSz = arg.sz, newSz=arg.sz + 2;
delete[] arg; // delete old array
arg = new Type[newSz]; // create new larger arr
arg.sz = newSz;
for (int i = 0; i < oldSz; ++i){ arg[i] = temp[i]; } //copy back
delete[] temp;
}
I am learning about C++ in school and creating a string class for an assignment. I have a couple of questions:
First, will the following create a memory leak?
MyString operator() (int sliceStart, int sliceEnd) {
sliceStart = sliceStart%_len;
if(sliceStart < 0)
sliceStart = _len + sliceStart;
sliceEnd = sliceEnd%_len;
if(sliceEnd < 0)
sliceEnd = _len + sliceEnd;
char* temp = new char[_len + 1];
if(sliceStart == sliceEnd)
return *this;
int i;
if(sliceStart < sliceEnd)
for(i = 0; sliceStart < sliceEnd; ++sliceStart && ++i)
temp[i] = _str[sliceStart];
else if(sliceStart > sliceEnd) {
for(i = 0; sliceStart < _len; ++sliceStart && ++i)
temp[i] = _str[sliceStart];
for(int k = 0; k < sliceEnd; ++i && ++k)
temp[i] = _str[k];
}
temp[i] = '\0';
//delete [] temp
return MyString(temp);
}
And if so, will adding the commented delete line return a valid value since it is freed right before the return. Or is it possible that the memory could possibly be snatched up between the two lines?
(I know that in this particular case I could simply create a MyString object before the return, but I am curious as if I HAD to return the temp char)
What is the common/proper way to manage dynamic local memory that you also wish to return by value?
Yes - there's a memory leak in your code, you allocate memory and then potentially return a different value on the next line.
Use encapsulation to help the user understand the lifetime of any allocations; either use something like std::shared_ptr or create a class that wraps ownership of the allocation.