Dynamic array of structs containing a dynamic array of structs - c++

I can't for the life of me figure out how to solve this in c.
I have the following structs:
typedef struct
{
uint8_t index = 0;
DLPageItem_t *pageItems = NULL;
uint8_t pageItemCount = 0;
uint8_t selectedItemIndex = 0;
} DLPage_t;
typedef struct
{
uint8_t index = 0;
void *valuePtr = NULL;
uint16_t tmpValue = 0;
DLItemType_t type = DLITEMTYPE::NOTYPE;
uint8_t row = 0;
uint8_t col = 0;
uint8_t targetPageId = 0;
DLItemAction_t action = DLITEMACTION::EDIT;
bool selectable = false;
bool editing = false;
} DLPageItem_t;
And I want to have a dynamic array of DLPage_t (with realloc) and then be able to anytime add DLPageItem_t to any of the already created DLPage_t array members.
So I tried to have a
DLPage_t *_pages = NULL;
and do
this->_pageCount++;
this->_pages = (DLPage_t*)realloc(this->_pages, this->_pageCount * sizeof(DLPage_t));
Then I'm accessing the "pages" and setting the values like this:
this->_pages[this->_pageCount - 1].index = this->_pageCount - 1;
The function which adds DLPageItem_t structs to a DLPage_t struct member, I do it like this:
this->_pages[pageId].pageItemCount++;
this->_pages[pageId].pageItems = (DLPageItem_t*)realloc(this->_pages[pageId].pageItems, this->_pages[pageId].pageItemCount * sizeof(DLPageItem_t));
I have some very funny business going on so I guess I'm doing something wrong and accessing/overwriting memory where I shouldn't.
Can someone please verify whether what I'm doing is correct? I tried to apply/adapt this to my issue but I just can't figure it out: https://stackoverflow.com/a/15397992
Thanks!

Related

How to affect memory allocated by new and casted to an array od class objects?

I had hard time describing it in the title, but basically I have to turn some code from C based on structures into C++ one based on objects. At the beginnig it was more or less (I'll try to simplify since it's a part of a big library-like project):
typedef struct Thing{
int param;
char* name;
void* data; //Either some arrays or more structures, hence void*
};
Thing* Initialise(void){
Thing* thing;
thing = (Thing*)malloc(sizeof(*thing));
param = 0;
name = NULL;
data = NULL;
return thing;
}
Thing* thing1 = malloc(bytesofdata);
Thing** smallthings = (Thing**) thing1->data; //Basically if "data" is a structure of other things
for ( i = 0; i < numberofsmallthings; i++ ) {
size_t k;
for ( k = 0; k < fieldsperthing; k++ ) {
smallthings[i*fieldsperthing+k] = Initialise();
}
}
Then I turned the structure into a class and the function into its method which resulted in:
class Thing{
private:
int param;
char* name;
void* data; //Either some arrays or more structures, hence void*
public:
int Initialise(void);
};
int Thing::Initialise(void){
this->param = 0;
this->name = NULL;
this->data = NULL;
}
thing1->data = new Thing;
this->data = new char [bytesofdata];
Thing** smallthings = (Thing**)this->data;
for (i = 0; i < numberofsmallthings; i++) {
size_t k;
for (k = 0; k < fieldsperthing; k++) {
smallthings[i*fieldsperthing + k]->Initialise();
}
}
And in this version, no matter if I try initialising the memory of not I am greeted by "access violation".
Is there any way to make this work? Casting to structure seemed to work fine so my guess is that something about objects makes it not work but I have no idea how to potentially bypass this. I would like to avoid making more objects since due to this part being buried pretty deep in functions, deleting those would be quite hard (especially since it's supposed to be a data reading function so exact structure of "data" might be not known).
When you do this:
smallthings[i*fieldsperthing + k]->Initialise();
You're attempting to dereference an unintialized pointer. You first need to assign something to it, then you can initialize it:
smallthings[i*fieldsperthing + k] = new Thing;
smallthings[i*fieldsperthing + k]->Initialise();
Better yet, change Initialise to a constructor. Then you won't have to do creation and initialization in separate steps. So now you have:
int Thing::Thing(){
this->param = 0;
this->name = NULL;
this->data = NULL;
}
...
thing1 = new Thing();
this->data = (void *)new Thing *[numberofsmallthings];
Thing** smallthings = (Thing**)this->data;
for (i = 0; i < numberofsmallthings; i++) {
size_t k;
for (k = 0; k < fieldsperthing; k++) {
smallthings[i*fieldsperthing + k] = new Thing();
}
}

Struct containing vector of pointers to other structs

I have a little complicated data structure but I have a problem with insertion to it, maybe I am thinking wrong.
This data structure is something like (we have a map which is a pair of uint16_t and structure, and three nested structures)
struct Struct4
{
uint8_t struct4ByteData1;
uint8_t struct4ByteData2;
uint16_t struct4ShortIntData1;
uint16_t struct4ShortIntData2;
};
struct Struct3
{
uint32_t struct3IntData1;
uint16_t struct3ShortIntData1;
uint16_t numOfElementsInVectorOfStruct4;
std::string struct3StringData;
std::vector<std::shared_ptr<Struct4>> struct4vector;
};
struct Struct2
{
uint32_t struct2IntData1;
uint16_t struct2ShortIntData1;
uint16_t numOfElementsInVectorOfStruct3;
int16_t struct2ShortIntData2;
std::string struct2StringData;
std::vector<std::shared_ptr<Struct3>> struct3vector;
};
struct Struct1
{
uint32_t struct1IntData1;
uint16_t numOfElementsInVectorOfStruct2;
std::vector<std::shared_ptr<Struct2>> struct2vector;
};
using uint16AndStruct1Map = std::multimap<uint16_t, Struct1>;
And here is a code snippet how data is inserted:
Struct1* struct1_ptr = new Struct1;
std::shared_ptr<Struct2> vectorOfStruct2;
std::shared_ptr<Struct3> vectorOfStruct3;
std::shared_ptr<Struct4> vectorOfStruct4;
uint16AndStruct1Map mapToBeInserted;
bool validData = false;
uint16_t numOfElementsInVectorOfStruct4;
uint16_t status;
uint16_t keyDataFromStruct2;
struct1_ptr->struct1IntData1 = getSomeData();
struct1_ptr->numOfElementsInVectorOfStruct2 = getSomeElements();
if (struct1_ptr->numOfElementsInVectorOfStruct2 == 0)
{
std::cout << "No Pim Avoidance Measurement in This Message, ignore" << std::endl;
return;
}
for(uint16_t i = 0; i < getNumOfElementsOfStruct2(); i++)
{
vectorOfStruct2 = std::make_shared<vectorOfStruct2>();
keyDataFromStruct2 = getKey();
vectorOfStruct2->struct2IntData1 = getSomeData();
vectorOfStruct2->struct2ShortIntData1 = keyDataFromStruct2;
vectorOfStruct2->struct2ShortIntData2 = getSomeData();
vectorOfStruct2->numOfElementsInVectorOfStruct3 = getSomeElements();
vectorOfStruct2->struct2StringData = getSomeStringData();
struct1_ptr->struct2vector.push_back(vectorOfStruct2);
for(uint16_t j = 0; j < getNumOfElementsOfStruct3(); j++)
{
vectorOfStruct3 = std::make_shared<vectorOfStruct3>();
vectorOfStruct3->struct3IntData1 = getSomeData();
vectorOfStruct3->struct3ShortIntData1 = getSomeData();
vectorOfStruct3->numOfElementsInVectorOfStruct4 = getSomeElements();
vectorOfStruct3->struct3StringData = getSomeStringData();
struct1_ptr->struct2vector[i]->struct3vector.push_back(vectorOfStruct3);
numOfElementsInVectorOfStruct4 = getNumOfElementsOfStruct4();
if(numOfElementsInVectorOfStruct4 < 10)
{
for(uint16_t k = 0; k < numOfElementsInVectorOfStruct4; k++)
{
vectorOfStruct4 = std::make_shared<vectorOfStruct4>();
status = getStatus();
if(status == SPECIAL_STATUS_TO_GET_INSIDE_THIS_IF_COND)
{
vectorOfStruct4->struct4ByteData1 = getSomeData();
vectorOfStruct4->struct4ByteData2 = getSomeData();
vectorOfStruct4->struct4ShortIntData1 = getSomeData();
vectorOfStruct4->struct4ShortIntData2 = status;
struct1_ptr->struct2vector[i]->struct3vector->struct4vector.push_back(vectorOfStruct4);
validData = true;
}
}
}
}
if(validData)
{
mapToBeInserted.insert (std::make_pair(keyDataFromStruct2,*struct1_ptr));
}
else
{
for (auto it = mapToBeInserted.begin(); it!=mapToBeInserted.end(); it++)
{
it->second.numOfElementsInVectorOfStruct2--;
}
}
validData = false;
}
After everything was inserted into map (and all of structures), when I want to get data from this map I probably get memory error. I am not 100% sure what the problem is.
The issue occurs at level of obtaining data from the map: mapToBeInserted.
Could you help?
if numOfElementsInVectorOfStruct4 is more than 10 you don't insert anything into struct4vector therefore this loop will access out of the bounds of struct4vector:
for(uint16_t l = 0; l < kv.second.struct2vector[j]->struct3vector[k]->numOfElementsInVectorOfStruct4; l++)
{
ss << "<"
<< kv.second.struct2vector[j]->struct3vector[k]->struct4vector[l]->struct4ByteData1 << ","
There are nothing wrong with the map insertion. The program crashed because of the vector index numOfElementsInVectorOfStruct4.
You have set the number of element :
vectorOfStruct3->numOfElementsInVectorOfStruct4 = getSomeElements();
But the data of struct4vector is inserted with CONDITION (there are two : < 10 and Status is OK)
So that the vector size struct4vector.size() and numOfElementsInVectorOfStruct4 can be different (when numOfElementsInVectorOfStruct4 < 10 and
one of its element has status OK).
Here are some advices :
Work with pointer (with map) to avoid the struct element copy
Work with vector size() function instead of getSomeElements() somewhere.
Check for the map element exists before used

typedef struct default initialization

How's possible to make default initialization for structs?
I'm trying to make default initialization for my struct but I get this error:
error: request for member 'type' in '((CCatManager::cat_shop_item*)this)->CCatManager::cat_shop_item::catAttr', which is of non-class type 'TCategoryAttribute [0]'
..........................
Here is my codes:
enum EMisc
{
CAT_MAX_NUM = 8,
};
typedef struct TCategoryAttribute
{
BYTE type;
short value;
} TCategoryAttribute;
typedef struct category_items
{
long price;
DWORD order;
TCategoryAttribute catAttr[CAT_MAX_NUM];
category_items()
{
price = 0;
order = 0;
catAttr.type[0] = 0;
.....
catAttr.type[7] = 0;
catAttr.value[0] = 0;
.....
catAttr.value[7] = 0;
}
} CATEGORY_ITEMS;
"price" and "order" are okay, they work but TCategoryAttribute doesn't work...
I'm really confused... thanks in advance, and I hope the question is right.
It's solved, thanks to #Michael.
That is because type isn't an array, rather, catAttr is. Secondly, there are 3 of them you declared, hence you third item is at index 2. remember, you count from 0. So change this portion of your code to:
category_items()
{
price = 0;
order = 0;
catAttr[0].type = 0;
catAttr[1].type = 0;
catAttr[2].type = 0;
//catAttr[3].type = 0; //you can't hit [3]
catAttr[0].value = 0;
catAttr[1].value = 0;
catAttr[2].value = 0;
//catAttr.value[3] = 0;
}
See full code that compiles (and works) here: http://coliru.stacked-crooked.com/a/abda47415ebb9938
BTW, that typedef is redundant. Just do this instead...
struct TCategoryAttribute
{
BYTE type;
short value;
};

How to Copy Data from One Array to Another Without Names? (C++)

I'm working on an assignment right now and have run into a roadblock. The assignment is an array list in C++ that dynamically expands by a factor of 2 every time it runs out of room to store new elements (initially starts with room for 2 elements). Here is the code I'm working on (some of it is included in a separate .h file provided by the professor, I won't post everything in order to keep this compact).
#include "array_list.h"
//initial size to create storage array
static const unsigned int INIT_SIZE = 2;
//factor to increase storage by when it gets too small
static const unsigned int GROW_FACTOR = 2;
unsigned int growthTracker = 1;
array_list::array_list()
{
m_storage = new unsigned int[INIT_SIZE];
m_capacity = INIT_SIZE;
m_current = -1;
m_size = 0;
}
array_list::~array_list()
{
delete m_storage;
}
void array_list::clear()
{
delete m_storage;
m_storage = new unsigned int[INIT_SIZE];
m_capacity = INIT_SIZE;
m_current = -1;
m_size = 0;
}
unsigned int array_list::size() const
{
return m_size;
}
bool array_list::empty() const
{
bool A = 0;
if(m_size == 0)
{
A = 1;
}
return A;
}
void array_list::insert(const unsigned int val)
{
m_storage[m_size++] = val;
m_current = m_size;
}
void array_list::grow_and_copy()
{
if(m_size == m_capacity)
{
new unsigned int[INIT_SIZE * (GROW_FACTOR ^ growthTracker)];
growthTracker++;
m_capacity = m_capacity * 2;
}
m_storage[m_size++] = val;
}
Now, my problem is trying to figure out how to copy the values of the old, smaller array into the new, larger one. If I wasn't using dynamic unnamed arrays, this would be very easy to do with a loop, a simple case of "for a certain range, arrayA[i] = arrayB[i]." However, because the arrays are just defined as new unsigned int[], I'm not sure how to go about this. There are no names, so I can't figure out how to tell C++ which array to copy into which. And since the grow_and_copy could be called multiple times, I'm fairly sure I can't give them names, right? Because then I would end up with multiple arrays with the same name. Can anyone point me in the right direction here? Thanks so much.
array_list::growList(int increase = GROW_FACTOR)
{
unsigned int* temp = m_storage;
m_storage = new unsigned int[m_capacity * increase];
for (int i = 0; i < m_capacity; i++)
m_storage[i] = temp[i];
m_capacity *= increase;
delete temp;
}
I don't know if there are other variables you want to change, but this should basically do what you are asking.

Array of structs declaration

I am trying to write this C++ function in which I am trying to set each Sequence in the array of Sequences, however when I follow the code on debug I notice that the array is not changing. In particular:
compressed.data[compressedDataCounter].c = pic.data[i];
compressed.data[compressedDataCounter].times = counter+1;
don't seem to add any new variables to the array, just override the first one.
I am thinking that the root of the problem is the declaration:
CompressedPic compressed;
compressed.data = new Sequence[pic.height * pic.width];
This is the portion of the code:
struct Sequence
{
char c;
int times;
};
struct CompressedPic
{
int height;
int width;
Sequence* data;
};
struct Picture
{
int height;
int width;
char* data;
};
CompressedPic compressThePicture(Picture pic) {
CompressedPic compressed;
compressed.data = new Sequence[pic.height * pic.width];
compressed.height = pic.height;
compressed.width = pic.width;
int compressedDataCounter=0;
for(int i=0; i<(pic.height * pic.width)-1; i++)
{
int counter = 0;
while(pic.data[i] == pic.data[i+1])
{
i++;
counter++;
}
compressed.data[compressedDataCounter].c = pic.data[i];
compressed.data[compressedDataCounter].times = counter+1;
compressedDataCounter++;
}
compressed.data[compressedDataCounter].times = -1;
return compressed;
}
It would be great if someone could figure out why this is happening.
You might want to change:
compressed.data[compressedDataCounter].c = counter+1;
to:
compressed.data[compressedDataCounter].times = counter+1;
So you can change the .times member otherwise you will be overriding your .c member. Right now you are setting .c to 'a' for example. Then you set .c to 103 (counter+1). Which is an int and likely with your archetecture the high bytes are aligning with .c and setting it to 0 as well.
So .c is getting 0'd and .times is never set