This is the way that i have alocated the memory.
Expression = new char[MemBlock.length()];
VarArray = new char[Variables.length()];
for (unsigned int i = 0; i < MemBlock.length(); i++)
{
Expression[i] = MemBlock.at(i);
}
Expression[MemBlock.length() + 1] = NULL;
for (unsigned int i = 0; i < Variables.length(); i++)
{
VarArray[i] = Variables.at(i);
}
VarArray[Variables.length() + 1] = NULL;
when i try to delete it i get the error...
Logic::~Logic(){
delete[] VarArray; -> happens on this line.
VarArray = NULL;
delete[] Expression;
Expression = NULL;
}
in the entire code i dont not make any changes to the new array yet it tells me i hame some currpution, i cant pin point the problem , any help would be great.
VarArray[Variables.length() + 1] = NULL;
accesses memory you do not own since this array is allocated thus:
VarArray = new char[Variables.length()];
The final element in this array has index Variables.length() - 1.
Running this in a debugger ought be be instructive. Some static analysis tools (eg. lint) would highlight this misuse, I believe.
You could also consider using boost::scoped_array or similar to remove the need for manual deletion. A good lesson to learn early on for C++ is to adopt RAII instead of manual memory management, wherever you can.
VarArray = new char[Variables.length()];
VarArray[Variables.length() + 1] = NULL;
You can´t do that, it´s 2 elements to much.
Same for the other array.
Expression[MemBlock.length() + 1] = NULL;
Is Undefined Behavior. As is
VarArray[Variables.length() + 1] = NULL;
In the 1st case you can only index up to MemBlock.length() - 1, and in the 2nd case Variables.length() - 1.
In both cases you are writing past the end of the allocated array and are probably overwriting the control structures used (by the runtime library) to manage dynamically allocated memory.
Related
I know this question has been asked before, but I couldn't quite fix my code, even reading other topics.
Does anyone know why is it throwing this warning?
Warning C6386 Buffer overrun while writing to 'LINES_DATA.Lines': the writable size is 'LINES_DATA.NumLines4' bytes, but '8' bytes might be written.*
"
LINES_DATA.NumLines = line_i; //line_i = 100
LINES_DATA.Lines = new int* [LINES_DATA.NumLines];
line_i = 0;
for (rapidxml::xml_node<>* pNode = pRoot->first_node(); pNode; pNode = pNode->next_sibling())
{
LINES_DATA.Lines[line_i] = new int[COLUMNSIZE]; //COLUMNSIZE = 5
for (int pos_i = 0; pos_i < COLUMNSIZE; pos_i++)
{
LINES_DATA.Lines[line_i][pos_i] = pNode->value()[pos_i] - '0';
}
line_i++;
}
I get the warning in this line:
LINES_DATA.Lines[line_i] = new int[COLUMNSIZE];
Thank you so much
If the array (LINES_DATA.Lines) hasline_i elements then LINES_DATA.Lines[line_i] is not valid.
Arrays are zero based so LINES_DATA.Lines has elements 0 to line_i-1
It's just a Code Analysis warning. The compiler isn't smart enough to work out your program's entire runtime behaviour.
Your code does have major risks of buffer over-runs, particularly if the XML contains more than 100 elements. You should be using smart pointers and/or STL containers here.
My structure code is like this:
typedef struct Patterns {
int pattern_num;
char *chained_fail_log;
Patterns *next_pattern;
} Pat;
I made this structure for the linked-list, and the linked-lists are allocated by "new"
for( int num_of_pat = 1; num_of_pat < number_of_pattern+1; num_of_pat++) {
curpattern->next_pattern = new Pat;
curpattern = curpattern->next_pattern;
curpattern->next_pattern = NULL;
curpattern->pattern_num = num_of_pat;
curpattern->chained_fail_log = new char[chain_cell_length+1];
for(int i = 0; i < chain_cell_length; i++ ) curpattern->chained_fail_log[i] = '0';
curpattern->chained_fail_log[chain_cell_length] = '\0';
}
curpattern->next_pattern = NULL;
I deleted the structure by delete.
`void Circuit_Fail_Log::freepattern() {
Pat * delpattern = fail_pattern_log;
int i = 0;
while( delpattern != NULL ) {
i++;
fail_pattern_log = delpattern->next_pattern;
printf("pattern_num:%d\tchained_pattern:%s\n",delpattern->pattern_num,delpattern->chained_fail_log);
delete[] delpattern->chained_fail_log;
delpattern->chained_fail_log = NULL;
delete delpattern;
delpattern = fail_pattern_log;
}
As you see in the code, the pointer for the next list cannot point to the next list in some cases.
I assume that the memory size of the list became bigger than the size when it was allocated.
So, the linked list pointer cannot point to the next list.
error message is
*** Error in `fextraction': double free or corruption (out):0x0000000001de9de0 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x81679)[0x7f66390fb679]
fextraction[0x401ae4]
fextraction[0x401ed3]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x7f663909c505]
fextraction[0x4008d9]
How can I fix this?
It should not happen but actually you are doing it by writing to a memory address which does not belogs to chained_fail_log.
If chained_fail_log should have chain_cell_length characters length minus the null terminator then you should :
// one more for null terminator
curpattern->chained_fail_log = new char[chain_cell_length+1];
for(int i = 0; i < chain_cell_length; i++ ) curpattern->chained_fail_log[i] = '0';
curpattern->chained_fail_log[chain_cell_length] = '\0'
In your original code curpattern->chained_fail_log[chain_cell_length] = '\0' is breaking memory boundry of your chained_fail_log
I finally find the answer.
In some cases, data was inserted in the curpattern->chained_fail_log[-1] on my program.
I fixed these cases, then the memory deallocation(delete) works without errors.
Environment: Windows 7 pro x64, Microsoft Visual Studio 2015 Enterprise, Version 14.0.25424.00 Update 3
int testFunction()
{
std::string _orig = "[188 80% (1/2)O:152]";
std::string _orig2 = "[999 99% (1/1)O:999]";
char *orig = NULL;
char *orig2 = NULL;
orig = new char[_orig.length() + 1];
strcpy(orig, _orig.c_str());
orig2 = new char[_orig2.length() + 1];
strcpy(orig2, _orig2.c_str());
*orig++;
*orig2++;
int a = atoi(orig);
int b = atoi(orig2);
delete[] orig;
delete[] orig2;
return 0;
}
Running the above code crashes with the "_CrtIsValidHeapPointer(block)" error.
If I don't iterate (*orig++ and *orig2++), then no issues.
So my question is, how can I iterate through the pointers and then when I'm done doing what I need to do with them, delete[] them correctly?
You did not delete the pointers you allocated!
delete must be called on the original memory address returned by new. Since you did orig++, you cant delete the address being pointed at!
Iterating can be done with an index, and using array subscription to dereference:
orig[i] = 'a';
Which is the same as doing this:
*(orig+i) = 'a';
Or you can get another pointer onto the same data, and modify this one.
char* pOrig = orig;
++pOrig;
Why did you write
*orig++; // why dereferencing?
Just ++ by itself would do the iteration.
Avoid to use raw pointers. Your code can be simpler:
std::string orig = "[188 80% (1/2)O:152]";
std::string orig2 = "[999 99% (1/1)O:999]";
int a = atoi(orig.c_str() + 1);
int b = atoi(orig2.c_str() + 1);
Your mistake is that you try to delete the shifted pointers instead of the original pointers. As the result heap manager gets wrong allocated block information usually put before the allocated pointer and you got heap corruption.
how can I iterate through the pointers and then when I'm done doing what I need to do with them, delete[] them correctly?
Create a copy of the pointer:
char* orig = new char[size];
char* i = orig;
*i++ = 'a';
delete orig;
A perhaps more common idiom is to dereference a temporary:
for(int i = 0; i < size - 1; i++)
orig[i] = 'a';
I would love to [use std::string], but I need to use atoi(), which won't work on std::string
You are mistaken. atoi works with std::string just fine. Simply use std::string::c_str() just like you did with strcpy. There is absolutely no reason to allocate a block of memory with new.
int testFunction()
{
std::string _orig = "[188 80% (1/2)O:152]";
int a = 0;
for (std::string::iterator it = _orig.begin(); it != _orig.end(); ++it)
{
if (isdigit((char)*it))
a = (atoi(it._Ptr));
}
return 0;
}
I got it. Thanks for everyone who helped me come to this conclusion. Staying with std::string was in fact the best approach.
I have a pointer to an array of pointers-to-objects, and need to resize the array. I do realize this is a perfect time to use vectors, But I'm not permitted to do so. My code works, but I don't completely follow what I've written, and concerned i may have created memory leaks:
void foo (DataSet &add_data)
{
if (sets == NULL)
{
sets = new DataSet*[1];
sets[0] = &add_data;
}
else
{
DataSet **transfer;
transfer = new DataSet*[num_of_sets];
for (int i = 0; i < num_of_sets; i++) // Copy addresses?
transfer[i] = sets[i];
delete [] sets; // Free the array.
sets = new DataSet*[num_of_sets + 1]; // Create new sets
for (int i = 0; i < num_of_sets; i++) // Copy back
sets[i] = transfer[i];
sets[num_of_sets] = &add_data; // Add the new set
delete [] transfer;
transfer = NULL;
}
num_of_sets++;
}
Why does Visual Studio throw an exception for:
for (int i = 0; i < num_of_sets; i++) // Copy addresses?
*transfer[i] = *sets[i];
but not:
for (int i = 0; i < num_of_sets; i++) // Copy addresses?
transfer[i] = sets[i];
But both code segments compile and run without fault in linux. This code should copy the pointers-to-objects. Is that what is happening with:
for (int i = 0; i < num_of_sets; i++) // Copy addresses?
transfer[i] = sets[i];
And do I need to be concerned if I want to free these objects with say a remove function later?
You do not need to allocate twice, just allocate once the final size:
transfer = new DataSet*[num_of_sets + 1]; // Create new sets - final size
for (int i = 0; i < num_of_sets; i++) // Copy addresses?
transfer[i] = sets[i];
delete [] sets; // Free the array.
sets = transfer;
sets[num_of_sets] = &add_data; // Add the new set
// now no need to delete[] transfer
That way you also get improved exception safety btw. - in your original code, you deleted the sets before allocating the new data to it - if that would throw std::bad_alloc, not only your object will become inconsistent (having a dangling sets ptr because you do not assign null to it after delete) but also the memory allocated to transfer would leak. If you allocate transfer directly to final size before delete[] sets, if that will throw, sets will stay intact and transfer will not leak (because it threw during allocation i.e. did not allocate).
Of course, make sure that you delete[] sets in the destructor (and maybe the pointers as well, in case your set is owning them).
*transfer[i] = *sets[i];
Does not copy addresses, like the other sample (without asterisks) does, it tries to dereference the uninitialized pointer elements of transfer and call operator= on DataSet objects on these addresses.
It's undefined behavior, that's why it appears to work under changed circumstances.
My program works but my professor says that my code is incorrect but stated that he will get to why in the fall term... What is he talking about?
perhaps something is improper? Even if you are incorrect I would appreciate picking your brain :)
void CResizableArray::SetSize( int intNewSize )
{
int intIndex = 0;
if( intNewSize < 0 ) intNewSize = 0;
if( intNewSize > intMAXIMUM_ARRAY_SIZE )
{
intNewSize = intMAXIMUM_ARRAY_SIZE;
}
//////////////////////////////////////
// ---> HUGE BUG HERE <--- //
// Code works but is WRONG //
// WHY IS THIS HELP ME FIND THE BUG //
//////////////////////////////////////
m_intArraySize = intNewSize;
m_paintValues = new int [m_intArraySize];
// Initialize to zero
for( intIndex = 0; intIndex < m_intArraySize; intIndex++ )
{
*( m_paintValues + intIndex ) = 0;
}
}
Presumably before this line
m_paintValues = new int [m_intArraySize];
m_paintValues pointed to another array. That array has now been leaked -- you don't have a pointer to it, so it can never be freed. That memory can therefore never be reused. Write a program that does a lot of this, and it'll run out of memory before running very long.
When you're through with a block of memory, you need to free it. Here, the proper thing to do might look something like
delete[] m_paintValues;
m_paintValues = new int [m_intArraySize];
There are more issues, though. First of all, you can never use delete[] unless you know that m_paintValues definitely points to an array; you could ensure that in the constructor. More troubling is that fact that when you set a new size, any data previously in m_paintValues is discarded -- don't you want to copy the old values into the new array? Doing so would mean using a temporary variable to hold the new array when first allocated, copying the data, and then assigning the new array to the member variable.
He may mean that since it is a resize you should keep the old contents of the array and transfer them over to the new array, in your snippet you just throw away the old content creating a new empty array.
so instead of
m_paintValues = new int [m_intArraySize];
// Initialize to zero
for( intIndex = 0; intIndex < m_intArraySize; intIndex++ )
{
*( m_paintValues + intIndex ) = 0;
}
do
int* newBiggerArray = new int[m_intArraySize];
for (intIndex = 0; intIndex < m_intArraySize; ++intSize)
{
if ( intIndex < oldMaxSize )
{
newBiggerArray[intIndex] = m_paintValues[intIndex];
}
else
{
newBiggerArray[intIndex] = 0;
}
}
delete [] m_paintValues;
m_paintValues = newBiggerArray;
I will leave the part to handle a resize to a smaller value than previous for you to figure out.