How to declare an array of pointers to multidimensional arrays - c++

// LED definitions for each step
static uint8_t route1Step0LedsOn[] = { 0x30, 0xff };
static uint8_t route1Step0LedsOff[] = { 0x26, 0xff };
static uint8_t route1Step1LedsOn[] = { 0x18, 0x45, 0x21, 0xff };
static uint8_t route1Step2LedsOn[] = { 0x56, 0x33, 0x42, 0x31, 0xff };
// First route (consisting of 3 steps + terminator).
static uint8_t* routeLeds1[][2] =
{
{ route1Step0LedsOff, route1Step0LedsOn },
{ NULL, route1Step0LedsOn },
{ NULL, route1Step0LedsOn },
{ NULL, NULL }
};
// Second route.
static uint8_t* routeLeds2[][2] =
{
// LED elements not shown, but similar to route 1.
{ NULL, NULL }
};
// Array of routes.
static ??? routes[] =
{
NULL,
routeLeds1,
routeLeds2,
NULL
};
I'm not sure of the correct type for routes[].
I'd like to know what the ??? should be?
I'm using a micro controller and MUST use arrays in order to force the arrays into flash memory instead of RAM.

You can't convert arrays to "pointers to pointers... to pointers" because they're dereferenced differently; trying to use a multidimensional array as a "pointer to... pointer" to something will cause undefined behaviour the same way dereferencing an invalid pointer would.
In memory, a "pointer to a pointer..." to an object is represented by
a -> b -> c -> ... -> object
Where a, b, c, ..., and object are in completely different parts of memory. To index a pointer, the pointer is dereferenced.
Arrays, however, are stored in a contiguous memory. For instance, int a[2][2] would be
[0,0][0,1][1,0][1,1]
Indexing a multidimensional array does not dereference a pointer, it changes the arithmetic that is used to calculate the offset from the beginning of the array that the desired value is at. The formula would be
address of array + index1 * sizeof(first dimension) + index2 * sizeof(second dimension) + ... + indexn * sizeof(object)
Where sizeof(nth dimension) is the size of all the subdimensions put together. For instance with int a[3][2] which is represented by
[0,0][0,1][1,0][1,1][2,0][2,1]
, the index a[2][1] would be
address of a + 2 * (sizeof(int) * 2) + 1 * sizeof(int)
Which, in C++, would be (char*)a + 16 + 4, the last element of the array.
To solve this problem, you need to use pointers only. You should not (and cannot) be storing multidimensional arrays alongside pointers in the same array.
I'm having a hard time putting this all into words; if I'm not making sense, please say so.

Try this:
typedef uint8* Array1; // first column/row
typedef Array1 Array2[2]; // uint* name[2]
typedef Array2* Array3; // get the idea?
// Array of routes.
static Array3 routes[] =
{
NULL,
routeLeds1,
routeLeds2,
NULL
};

Your problem is the multidimensional array:
If you need to go the array route, you can just add an extra step:
static uint8_t route1Step0LedsOn[] = { 0x30, 0xff };
static uint8_t* route1Step0[] = { NULL, route1Step0LedsOn };
static uint8_t** routeLeds1[] = { route1Step0 };
static uint8_t*** routes[] =
{
NULL,
routeLeds1,
NULL
};
If some of the arrays are fixed lengths, it may be possible to clean some of this up a little.
But IMO this is getting pretty ugly and could do with some real structs, rather than raw arrays.

If you're not tied to ussing arrays for some technical reason, you could change to use a structure like this: (Note if you're using C++11, then the constructors and construction can be made a lot nicer). You'll also need a make_vector helper, of which there are several floating around, if you want a nicer construction.
struct LedList
{
LedList( const std::vector<uint8_t> & v ) : leds( v ) {}
std::vector<uint8_t> leds;
};
struct LedStep
{
LedStep( const & LedList on_, const & LedList off_ ) : on_leds(on_), off_leds(off_) {}
RouteStepLedList on_leds;
RouteStepLedList off_leds;
};
struct LedRoute
{
LedRoute( const std::vector<LedStep> & steps_ ) : steps(steps_) {}
std::vector<LedStep> steps;
};
struct Route
{
Route( const std::vector<LedRoute> & routes_ ) : routes(routes_) {}
std::vector<LedRoute> routes;
};
//All routes
Route r( make_vector<LedRoute>()(
//First route
make_vector<LedStep>()(
//First step of first route
LedStep(
make_vector<uint8_t>()( 0x30 ),
make_vector<uint8_t>()( 0x26 )
) )(
//Second step of first route
LedStep(
make_vector<uint8_t>(),
make_vector<uint8_t>()( 0x18 )( 0x45 )( 0x21 )
) )(
//Third step of first route
LedStep(
make_vector<uint8_t>(),
make_vector<uint8_t>()( 0x56 )( 0x33 )( 0x42 )( 0x31 )
) ) ),
//Second route.
make_vector<LedStep>()(
//First step of second route
LedStep(
...
) ) (
//Second step of second route
...
);

Related

Arduino combine several arrays (c++)

I want to know how can I combine several byte arrays into 1?
I have this:
byte MessageStart [] = {0x02};
byte Next [] = {0x5C , 0x73};
byte messgae[] = {0x30 , 0x35};
byte BeforeEnd [] = {0x5C , 0x3B};
byte MessageEnd [] = {0x03};
I want to have one byte array with all of them, the final result needs to be:
byte Final [] = {0x02, 0x5C, 0x73, 0x30, 0x35, 0x5C, 0x3B, 0x03}
How do I do this?
Maybe something like this:
byte *concatbytes(const byte *source, byte *destination, int length)
{
for (int i = 0; i < length; i++)
{
*destination++ = *source++;
}
return destination;
}
...
byte MessageStart[] = { 0x02 };
byte Next[] = { 0x5C , 0x73 };
byte messgae[] = { 0x30 , 0x35 };
byte BeforeEnd[] = { 0x5C , 0x3B };
byte MessageEnd[] = { 0x03 };
byte Final[8]; // 8 is the hardcoded length of sum of all 5 arrays
byte *dest = Final;
dest = concatbytes(dest, MessageStart, sizeof(MessageStart));
dest = concatbytes(dest, Next, sizeof(Next));
dest = concatbytes(dest, messgae, sizeof(messgae));
dest = concatbytes(dest, BeforeEnd, sizeof(BeforeEnd));
dest = concatbytes(dest, MessageEnd, sizeof(Next));
The Final array may be obtained differently, for example by dynamic memory allocation. This is left as an exercise for the reader.

data segment too large while compiling

Here, I am passing an array of bits to some other function.
Since, array size is too large, it throws an error saying "data segment too large" while compiling.
I have newly edited the code. But, the error: data segment too large still exists
This is the code:
char TxBits[]={0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,
0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,1,0,0,1,0,1,0,1,1,0,1,1,0,1,1,1,0,
0,0,0,1,1,0,0,0,1,0,0,1,0,0,1,1,1,1,1,1,0,1,0,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int nTxBits = sizeof(TxBits)/sizeof(char);
void data(char *TxBits,int nTxBits, int loopcount)
{
int i;
for (i = 0;i < nTxBits;i++)
{
gpio=TxBits[i];
wait(loopcount);
}
}
So, I am thinking of converting bits in an array to bytes and passing to function. May I know how to proceed? open to suggestions.
Kindly reply
From your code I reckon you're working with some micro-controller so I'm not sure if you're serious about the C++ tag or not. If you are, this is a C++-style solution which uses std::bitset (specialised container for dealing with bits which will require less space):
std::bitset<134> foo (std::string("01010101010101010101010100101010101010101010101010010101010101010101010101001010101010101010101010100101010101010101010101010100000000"));
void data(const std::bitset& bitset, int loopcount) {
// if C++11
for (auto& bit : foo) {
gpio = bit;
wait(loopcount);
}
// if C++98
// for (int i = 0; i<bitset.size(); i++) {
// gpio = foo[i];
// wait(loopcount);
// }
}
You probably need this:
void data(char *TxBits, int size) // size of the number of elements of your table
{
int i;
for (i = 0;i < size; i++)
{
gpio=TxBits[i];
wait(loopcount);
}
}
Calling the function
data(TxBits, sizeof(TxBits) / sizeof(TxBits[0]);
To get the number of elements of an array we use sizeof(TxBits) / sizeof(TxBits[0] where sizeof(TxBits) is the number of bytes the array takes in memory and sizeof(TxBits[0] is the size of one element of the array.
I am passing an array of bits to some other function
No, you are passing an array of bytes, each byte having the binary value 00000000 or 00000001.
In order to save memory, you should store bit values as actual bits and not as bytes:
uint8_t TxBits[]=
{ 0x55, // 0,1,0,1,0,1,0,1,
0x55, // 0,1,0,1,0,1,0,1,
0x55, // 0,1,0,1,0,1,0,1,
0x00, // 0,0,0,0,0,0,0,0,
0x20, // 0,0,1,0,0,0,0,0,
...
};
size_t nTxBits = sizeof(TxBits) / 8;
You should also avoid the char type whenever doing arithmetic, since it has implementation-defined signedness.
Also if this is a small microcontroller system, you should allocate the data in ROM instead of RAM whenever possible. That is: const uint8_t TxBits[].
Your Parameter is not declared correctly. Replace this:
void data(char TxBits)
by this
void data(char [] TxBits)
Your function
void data(char TxBits)
Should be
void data(char *TxBits, size_t nTxBits)
{
int i;
for (i = 0;i < nTxBits;i++)
{
gpio=TxBits[i];
wait(loopcount);
}
}
You can call it by:
data ( TxBits, sizeof(TxBits)/sizeof(TxBits[0]) );
In this specific case, you have a char array, and you can also write:
data (TxBits, sizeof(TxBits));

C++ reference byte array

I have an issue with C++ and creating a reference byte[].
In C# my method is:
public static void SetBitAt(ref byte[] Buffer, int Pos, int Bit, bool Value)
{
byte[] Mask = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
if (Bit < 0) Bit = 0;
if (Bit > 7) Bit = 7;
if (Value)
Buffer[Pos] = (byte)(Buffer[Pos] | Mask[Bit]);
else
Buffer[Pos] = (byte)(Buffer[Pos] & ~Mask[Bit]);
}
I want to translate it to C++, but I can't get the refworking for C++. I saw something about the & symbol and I tried something like this:
void SetBitAt(byte& buffer[], int Pos, int Bit, bool Value)
{
byte Mask[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
if (Bit < 0) Bit = 0;
if (Bit > 7) Bit = 7;
if (Value)
{
buffer[Pos] = (byte)(buffer[Pos] | Mask[Bit]);
}
else
{
buffer[Pos] = (byte)(buffer[Pos] & ~Mask[Bit]);
}
}
but then I get the Error:
'buffer': arrays of references are illegal.
So how can I change my C++ code to work with a reference array?
EDIT:
I use this method for setting a buffer, but it doesn't change when I use this method.
other class:
buffer = ReadDB(2); //Read the values in the DataBlock
SetBitAt(buffer, 0,0 true); //Set bit 0,0 to 1(true)
WriteDB(2, buffer); //Write the values to the Datablock
but the buffer doesn't change. its the same value.
If you want to pass array by reference, you should
void SetBitAt(byte (buffer&)[10], int Pos, int Bit, bool Value)
But in your case, you don't need that, just
void SetBitAt(byte buffer[], int Pos, int Bit, bool Value)
Note in this case array will decay to pointer (i.e. byte*), that means the size of array won't be reserved as pass by reference would.
'buffer': arrays of references are illegal.
This is due to operator precedence. Saying byte &buffer[] is an array of references, while saying byte (&buffer)[size] is a reference to an array.
See C++ pass an array by reference for more details.
So how can I change my C++ code to work with a reference array?
When passing your array as a function argument, you should drop & symbol. You can still modify the contents of your array because the array's address is passed instead.
Assuming you have a typedef of char to byte, your function signature should look like this:
void SetBitAt(byte buffer[], int Pos, int Bit, bool Value) { ... }
Note that the above is equivalent to passing a pointer:
void SetBitAt(byte *buffer, int Pos, int Bit, bool Value) { ... }
Modifying the contents of your array is still a matter of saying buffer[Pos] = // some value;
This post on What is array decaying? should be useful.
Shouldn't it simply be like this:
void SetBitAt(byte buffer[], int Pos, int Bit, bool Value)
{
byte Mask[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
if (Bit < 0) Bit = 0;
if (Bit > 7) Bit = 7;
if (Value)
{
buffer[Pos] = (byte)(buffer[Pos] | Mask[Bit]);
}
else
{
buffer[Pos] = (byte)(buffer[Pos] & ~Mask[Bit]);
}
}
In this way, buffer is passed as a pointer, and buffer[Pos] references to the Pos-th element of buffer. It is plain C, but it should work.
You can pass it simply by address as:
void SetBitAt(byte* buffer, int Pos, int Bit, bool Value) { ... }
or simply as:
void SetBitAt(byte buffer[], int Pos, int Bit, bool Value) { ... }
Either one will tell the compiler that byte pointer is passed to function, althrough with second header you omit pointer arithmetics ;)

cpp custom std allocator

First timer with allocator.
I am really struggling with a custom allocator.
I would say its obvious I don't know what I'm doing here.
My goal is to put all of the memory for the object in the process's heap.
I want the allocation to come from the system so its not language / runtime dependent.
I don't really want a struct, I just want:
std::list< WCHAR[SIZE], TestAllocator<WCHAR[SIZE]>> list;
or, I'd allocate the memory outside of the list and then just store a pointer to it
std::list< void*, TestAllocator<void*>> list;
But I don't see how to do it with non struct / classes. So I have a struct.
This thing crashes all over the place.
The code below that instantiates the list crashes, it doesn't even have to get to a list item creation / insert.
The allocator is used for the list creation before I attempt to add an item. (which I don't understand.) It seems to me that the allocator should only be used for the struct type I'm trying to add to the list. If the allocator is used to create the list and the items it holds how do I create the memory for the 2 different types, the list type and the list entry type?
Some other observations / questions.
When my list is created, it is placed at the memory address created:
OSAllocator::allocate count:[1] bytes each:[8][0x8] bytes total:[8][0x8]addr:[4305640][0x41B2E8]
OSAllocator::construct placement new:[4305640][0x41B2E8] sizeof(val):[8][0x8]
However, when my entry is created, it is placed 2 bytes past the address created:
OSAllocator::allocate count:[1] bytes each:[8200][0x2008] bytes total:[8200][0x2008] addr:[8837144][0x86D818]
OSAllocator::construct placement new:[8837152][0x86D820] sizeof(val):[8192][0x2000]
Is there an explanation for that?
Please help point out what I'm missing.
Thanks.
// allocator...
pointer allocate(size_type size, TestAllocator<void>::const_pointer hint = 0)
{
pointer p = (pointer)::HeapAlloc( ::GetProcessHeap(),
HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE,
size*sizeof(T) );
gCountAllocate++;
if( OSAllocatorConsole )
wprintf( L"OSAllocator::allocate: [%u][0x%X]\n", p, p );
return p;
}
size_type max_size() const throw() {return size_t(-1) / sizeof(value_type);}
void construct(pointer p, const T& val)
{
gCountConstructPlaceNew++;
if( OSAllocatorConsole )
wprintf( L"OSAllocator::construct placement new:[%u][0x%X]\n", p, p );
::CopyMemory( p, &val, sizeof(val) );
}
typedef struct _LogLine
{
WCHAR _logLine[4*1024];
} LOGLINE, *PLOGLINE;
DWORD TestAllocatorChar(int argc, WCHAR* argv[])
{
WCHAR buf[32] = {0};
DWORD total = 1;
std::list< LOGLINE, TestAllocator<LOGLINE>> list;
PLOGLINE pll = NULL;
LOGLINE ll = {0};
for(int i=0; i<total; i++ )
{
::StringCchPrintfW( ll._logLine, 4*1024, L"count:[%u]", i );
list.push_back( ll );
}
for( int i=0; i<total; i++ )
{
//pll = list.front();
wprintf( L"%s\n", list.front()._logLine );
wprintf( L"HeapFree item:[%u]\n", i );
//::HeapFree( ::GetProcessHeap(), HEAP_NO_SERIALIZE, p );
list.pop_front();
}
return 0;
}

C++ Checking if param dynamic array. Is it necessary?

void Example1( char* ArrayA, unsigned int Length )
{
if( ArrayA == 0 )
{
ArrayA = new char[ Length + 1 ];
// Fill it with 2 - whatever
::memset( ArrayA, 0x02, sizeof( char ) * Length );
ArrayA[ Length ] = '0\n';
}
// Do whatever with ArrayA
// Clean-Up
// Error occurs
delete [ ] ArrayA;
};
void Example2( char* ArrayB, unsigned int Length )
{
bool IsDynamic = false;
if( ArrayB == 0 )
{
ArrayB = new char[ Length + 1 ];
// Fill it with 2 - whatever
::memset( ArrayB, 0x02, sizeof( char ) * Length );
ArrayB[ Length ] = '0\n';
IsDynamic = true;
}
// Do whatever with ArrayA
// Clean-Up
// Have to check...
if( IsDynamic )
delete [ ] ArrayB;
};
int main( void )
{
Example1( "\x01\x02\0x03", 3 ); // Example1 WILL NOT* declare ArrayA as a dynamic array - ERROR (caused by deleting non dynamic array)
Example2( 0, 3 ); // ArrayB will be a dynamic array - OK
Example1( 0, 3 ); // OK
Example2( "\x04\x05\0x06", 3 ); // ArrayB isn't a dynamic array - OK
return ( 0 );
};
The problem occurs when attempting to delete char* ArrayA in function Example1 because ArrayA is not a dynamic array. It will only be a dynamic array if it is equal to zero/null. So, to resolve that I created a similar function - Example2. The only difference is that Example2 has a boolean that checks to see if char* ArrayB is a dynamic array or not.
I know what I am doing is either incorrect or "noobish". So please help me. I will learn from my mistake.
How would you do it?
void Example3( char* ArrayC, unsigned int Length );
Maybe you could use this:
void Example2( char* ArrayB, unsigned int Length )
{
std::vector< char > internalArray;
if ( ArrayB != 0 )
{
internalArray.assign( ArrayB, ArrayB + Length );
}
else
{
internalArray.resize( Length, 0x2 );
}
// Do whatever with internalArray !!! <-------
// No (!!!) clenup need
};
I know what I am doing is either incorrect or "noobish". So please help me.
My overall recommendation would be to move from using C arrays to using std::vector instead.
Your example1 is definitely bad, since it tries to free an array that isn't dynamically allocated - that is NEVER right. As explained elsewhere, if you call across a DLL boundary, you may also have different allocators, so if the memory was not allocated where it is being deleted, things will go wrong. Let whoever allocated it delete it. Preferrably by using already existing standard functionality, such as std::vector
Your example2 only uses delete on something that was created within the function, which is perfectly fine. It doesn't try to delete something that it doesn't know is allocated in the same allocator. Yet, a std::vector would certainly be easier to handle.