Resizable Array with pointers - c++

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.

Related

Can the same structures allocate different memory sizes in C++?

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.

resize an array of pointers without memory leak

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.

ProtocolBuffer object ByteSize is wrong

I have the following method:
void ConnectionManager::SendAll()
{
for (int t = 0; t < (int)m_Connections.size(); ++t)
{
if (m_Connections[t].socket != INVALID_SOCKET)
{
// Create the object
MessageID message;
message.set_type(MessageID::Type::MessageID_Type_PLAYERDATA);
for (int i = 0; i < (int)m_Connections.size(); ++i)
{
if (m_Connections[i].playerData.username() != google::protobuf::internal::kEmptyString)
{
auto temp = message.add_playerdata();
temp = &m_Connections[i].playerData;
}
}
if (message.playerdata_size() > 0)
{
// Serialize to byte array
int size = message.ByteSize();
void* buffer = malloc(size);
message.SerializeToArray(buffer, size);
Send(m_Connections[t].socket, buffer, size);
}
}
}
}
Now the problem lies at the end of this method, at the line:
int size = message.ByteSize();
I know that the data is loaded correctly (or it should be at least) but the size isn't right. It should be 30 and it returns 2. I have no idea what I'm doing wrong.
The data in m_Connections is available and should be reached by pointer temp. I think that, for some reason, the data is lost from the "message" object but I don't know how to solve it.
auto temp = message.add_playerdata();
temp = &m_Connections[i].playerData;
These lines look wrong. add_playerdata() returns a pointer. That means that the second line is just setting temp to some other pointer, not doing anything to the message which temp points at. It's more obvious if you write out the type rather than use auto:
MessageID::PlayerData* temp = message.add_playerdata();
temp = &m_Connections[i].playerData;
Maybe you wanted to do this instead:
*temp = m_Connections[i].playerData;
However, I do not see how this bug would lead to ByteSize() being 2. It looks like ByteSize() should only be 2 if you haven't added any players to the message, but then playerdata_size() would be zero, so you wouldn't get to the serialization step at all.

CAtlArray strange behavior using SetCount

I am having a strange issue with a CAtlArray. It works as expected if I use the Add function to add an element to the array. However, if I use SetCount before adding any elements, the program crashes. Strangely, it only works if I add elements directly with the [] operator (I know I know, the documentation says to only use [] to get an element, not to set one). I have been checking that SetCount returns true and it does.
Unfortunately, I can't get much debug info easily because this is a dll hooking another process. I can only debug by printing ...
I am wondering if this is typical behavior/if I am missing something (the documentation sucks, google did not return any helpful results, and the ATL code is hard for me to read/follow). My first thought was that SetCount(X) might have some behavior like calling Add() X times and shouldn't be called unless it is expanding the array, but SetAt doesn't work with SetCount either.
Any ideas about what might be going on here?
EDIT:
CAtlArray<MyClass*> arr;
...
size_t initialCount = 10;
if ( arr.SetCount(initialCount) ) {
for ( int i = 0; i < initialCount; i++ ) {
//arr.Add( new MyClass );//Does NOT work
//arr.SetAt( i, new MyClass );//Does NOT work
arr[i] = new MyClass;//This works
}
}
EDIT 2:
I forgot to mention, I also tried using the GetData method but it didn't work either:
MyClass **pData;
if ( arr.SetCount(initialCount) ) {
pData = arr.GetData();
for ( int i = 0; i < initialCount; i++, pData++ ) {
*pData = new MyClass;
}
}
All the three attempts to add elements DO work, but they don't do exactly the same thing, and - more important - the dangerous option does not crash the application and only creates a condition that causes crash later.
//arr.Add( new MyClass );//Does NOT work
//arr.SetAt( i, new MyClass );//Does NOT work
arr[i] = new MyClass;//This works
Let's see what the they actually do:
SetCount adds 10 NULL elements to the array
following Add leaves those ten nulls and adds your instances as 11th, 12th and on
following SetAt replaces NULLs with your instances
following indexed set replaces NULLs with your instances in the same way as #2 above
So items #2 and #3 do "work" and item #1 does a different thing: the array has 20 items and if you later attempt to access the elements, you hit NULLs where you expect to have valid pointers.
Have a look at small application that prints element count (you can see you have 10 or 20 elements), and then does element checking to verify if all elements of the array are "valid".
#include "stdafx.h"
#include <atlcoll.h>
class MyClass
{
private:
INT m_nValue;
public:
MyClass() :
m_nValue(0xDEADC0DE)
{
}
VOID Check()
{
ATLASSERT(m_nValue == 0xDEADC0DE);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
CAtlArray<MyClass*> arr;
size_t initialCount = 10;
if(arr.SetCount(initialCount))
{
for( int i = 0; i < initialCount; i++ )
{
arr.Add( new MyClass );//Does NOT work
//arr.SetAt( i, new MyClass );//Does NOT work
//arr[i] = new MyClass; //This works
}
}
_tprintf(_T("arr.GetCount() %d\n"), arr.GetCount());
for(SIZE_T nIndex = 0; nIndex < arr.GetCount(); nIndex++)
arr[nIndex]->Check();
return 0;
}
An easier way to put elements to the array is as follows:
size_t initialCount = 10;
//if(arr.SetCount(initialCount)) -- not needed
{
for( int i = 0; i < initialCount; i++ )
{
arr.Add( new MyClass );
}
}

Trying to fill a 2d array of structures in C++

As above, I'm trying to create and then fill an array of structures with some starting data to then write to/read from.
I'm still writing the cache simulator as per my previous question:
Any way to get rid of the null character at the end of an istream get?
Here's how I'm making the array:
struct cacheline
{
string data;
string tag;
bool valid;
bool dirty;
};
cacheline **AllocateDynamicArray( int nRows, int nCols)
{
cacheline **dynamicArray;
dynamicArray = new cacheline*[nRows];
for( int i = 0 ; i < nRows ; i++ )
dynamicArray[i] = new cacheline [nCols];
return dynamicArray;
}
I'm calling this from main:
cacheline **cache = AllocateDynamicArray(nooflines,noofways);
It seems to create the array ok, but when I try to fill it I get memory errors, here's how I'm trying to do it:
int fillcache(cacheline **cache, int cachesize, int cachelinelength, int ways)
{
for (int j = 0; j < ways; j++)
{
for (int i = 0; i < cachesize/(cachelinelength*4); i++)
{
cache[i][ways].data = "EMPTY";
cache[i][ways].tag = "";
cache[i][ways].valid = 0;
cache[i][ways].dirty = 0;
}
}
return(1);
}
Calling it with:
fillcache(cache, cachesize, cachelinelength, noofways);
Now, this is the first time I've really tried to use dynamic arrays, so it's entirely possible I'm doing that completely wrong, let alone when trying to make it 2d, any ideas would be greatly appreciated :)
Also, is there an easier way to do write to/read from the array? At the moment (I think) I'm having to pass lots of variables to and from functions, including the array (or a pointer to the array?) each time which doesn't seem efficient?
Something else I'm unsure of, when I pass the array (pointer?) and edit the array, when I go back out of the function, will the array still be edited?
Thanks
Edit:
Just noticed a monumentally stupid error, it should ofcourse be:
cache[i][j].data = "EMPTY";
You should find your happiness. You just need the time to check it out (:
The way to happiness