Multidimensional array with different sizes using Arduino - c++

I would like to have a multidimensional array that allows for different sizes.
Example:
int x[][][] = {{{1,2},{2,3}},{{1,2}},{{4,5},{2,7},{1,1}}};
The values will be known at compile time and will not change.
I would like to be able to access the values like val = x[2][0][1];
What is the best way to go about this? I'm used to java/php where doing something like this is trivial.
Thanks

I suppose you could do this "the old fashioned (uphill both ways) way":
#include <stdio.h>
int main(void){
int *x[3][3];
int y[12] = {1,2,3,4,5,6,7,8,9,10,11,12};
x[0][0] = &y[0];
x[0][1] = &y[2];
x[1][0] = &y[4];
x[2][0] = &y[6];
x[2][1] = &y[8];
x[2][2] = &y[10];
// testing:
printf("x[0][0][0] = %d\n", x[0][0][0]);
printf("x[0][0][1] = %d\n", x[0][0][1]);
printf("x[0][1][0] = %d\n", x[0][1][0]);
printf("x[0][1][1] = %d\n", x[0][1][1]);
printf("x[1][0][0] = %d\n", x[1][0][0]);
printf("x[1][0][1] = %d\n", x[1][0][1]);
printf("x[2][0][0] = %d\n", x[2][0][0]);
printf("x[2][0][1] = %d\n", x[2][0][1]);
printf("x[2][1][0] = %d\n", x[2][1][0]);
printf("x[2][1][1] = %d\n", x[2][1][1]);
printf("x[2][2][1] = %d\n", x[2][2][0]);
printf("x[2][2][1] = %d\n", x[2][2][1]);
return 0;
}
Basically, the array x is a little bit too big (3x3) and it points to the "right place" in the array y that contains your data (I am using the digits 1…12 because it's easier to see it is doing the right thing). For a small example like this, you end up with an array of 9 pointers in x (72 bytes), plus the 12 integers in y (48 bytes).
If you filled an int array with zeros where you didn't need values (or -1 if you wanted to indicate "invalid") you would end up with 18x4 = 72 bytes. So the above method is less efficient - because this array is not "very sparse". As you change the degree of raggedness, this gets better. If you really wanted to be efficient you would have an array of pointers-of-pointers, followed by n arrays of pointers - but this gets very messy very quickly.
Very often the right approach is a tradeoff between speed and memory size (which is always at a premium on the Arduino).
By the way - the above code does indeed produce the output
x[0][0][0] = 1
x[0][0][1] = 2
x[0][1][0] = 3
x[0][1][1] = 4
x[1][0][0] = 5
x[1][0][1] = 6
x[2][0][0] = 7
x[2][0][1] = 8
x[2][1][0] = 9
x[2][1][1] = 10
x[2][2][1] = 11
x[2][2][1] = 12
Of course it doesn't stop you from accessing an invalid array element - and doing so will generate a seg fault (since the unused elements in x are probably invalid pointers).

Thanks Floris.
I've decided to just load all values into a single array, like
{1,2,2,3,1,2,4,5,2,7,1,1}
and have a second array which stores the length of each first dimension, like
{2,1,3}
The third dimension always has a length of 2, so I will just multiply the number by 2. I'm going to make a helper class so I can just do something like getX(2,0) which would return 4, and have another function like getLength(0) which would return 2.

Related

Binary files: write with C++, read with MATLAB

I could use your support on this. Here is my issue:
I've got a 2D buffer of floats (in a data object) in a C++ code, that I write in a binary file using:
ptrToFile.write(reinterpret_cast<char *>(&data->array[0][0]), nbOfEltsInArray * sizeof(float));
The data contains 8192 floats, and I (correctly ?) get a 32 kbytes (8192 * 4 bytes) file out of this line of code.
Now I want to read that binary file using MATLAB. The code is:
hdr_binaryfile = fopen(str_binaryfile_path,'r');
res2_raw = fread(hdr_binaryfile, 'float');
res2 = reshape(res2_raw, int_sizel, int_sizec);
But it's not happening as I expect it to happen. If I print the array of data in the C++ code using std::cout, I get:
pCarte_bin->m_size = 8192
pCarte_bin->m_sizel = 64
pCarte_bin->m_sizec = 128
pCarte_bin->m_p[0][0] = 1014.97
pCarte_bin->m_p[0][1] = 566946
pCarte_bin->m_p[0][2] = 423177
pCarte_bin->m_p[0][3] = 497375
pCarte_bin->m_p[0][4] = 624860
pCarte_bin->m_p[0][5] = 478834
pCarte_bin->m_p[1][0] = 2652.25
pCarte_bin->m_p[2][0] = 642077
pCarte_bin->m_p[3][0] = 5.33649e+006
pCarte_bin->m_p[4][0] = 3.80922e+006
pCarte_bin->m_p[5][0] = 568725
And on the MATLAB side, after I read the file using the little block of code above:
size(res2) = 64 128
res2(1,1) = 1014.9659
res2(1,2) = 323288.4063
res2(1,3) = 2652.2515
res2(1,4) = 457593.375
res2(1,5) = 642076.6875
res2(1,6) = 581674.625
res2(2,1) = 566946.1875
res2(3,1) = 423177.1563
res2(4,1) = 497374.6563
res2(5,1) = 624860.0625
res2(6,1) = 478833.7188
The size (lines, columns) is OK, as well as the very first item ([0][0] in C++ == [1][1] in MATLAB). But:
I'm reading the C++ line elements along the columns: [0][1] in C++ == [1][2] in MATLAB (remember that indexing starts at 1 in MATLAB), etc.
I'm reading one correct element out of two along the other dimension: [1][0] in C++ == [1][3] in MATLAB, [2][0] == [1][5], etc.
Any idea about this ?
Thanks!
bye
Leaving aside the fact there seems to be some precision difference (likely the display settings in MATLAB) the issue here is likely the difference between row major and column major ordering of data. Without more details it will be hard to be certain. In particular MATLAB is column major meaning that contiguous memory on disk is interpreted as detailing sequential elements in a column rather than a row.
The likely solution is to reverse the two sizes in your reshape, and access the elements with indices reversed. That is, swap the int_size1 and int_size2, and then read elements expecting
pCarte_bin->m_p[0][0] = res2(1,1)
pCarte_bin->m_p[0][1] = res2(2,1)
pCarte_bin->m_p[0][2] = res2(3,1)
pCarte_bin->m_p[0][3] = res2(4,1)
pCarte_bin->m_p[1][0] = res2(1,2)
etc.
You could also transpose the array in MATLAB after read, but for a large array that could be costly in itself

How exactly does a reference to an array work?

I am looking at a unique example here and am trying to understand why his snippet behaves the way it does
// uninitialized mem
char test[99999];
//
test[0] = 'a';
test[1] = 'b';
test[2] = 'c';
test[3] = 'd';
test[4] = 'e';
test[5] = 'f';
test[6] = 'g';
for (int i = 0; i < 99999; i++) {
cout << (&test[i])[i] << endl;
}
In particular, what is happening in memory for the output to skip a character?
output:
a
c
e
g
..
This is what is happening:
An array is just a contiguous chunk of memory.
&test
Is getting the address of that index of the starting point of array. Not the value.
When you add [some number], it counts up the number times the size of the data type, in this case each char is a byte.
So when you do
&test[i]
that means the starting address + i bytes.
when you do
(&test[i])[i]
You are doing i bytes from the starting address, and then treat that as the starting address and go up i more bytes.
So in your iterations:
(&test[0])[0] // index 0 + 0 = 0
(&test[1])[1] // index 1 + 1 = 2
(&test[2])[2] // index 2 + 2 = 4
(&test[3])[3] // index 3 + 3 = 6
It should become a bit more obvious when you consider what the array indexing is actually doing.
Given an array test, you usually access the nth element of test with test[n]. However, this is actually the equivalent of *(test+n). This is because addition on pointers automatically multiplies the amount you add with the size of the type being pointed to. This means the pointer will then be pointing at the second item in the array if you add one to the pointer, the third item if you add two, and so on.
The code you provide then references that value, so you end up with &(*(test+n)). The reference (&) and the dereference (*) operations then cancel each other out, which means you end up with just test+n.
The code then does another array index on that value, so you end up with (test+n)[n], which again may be written as *((test+n)+n). If you simplify that, you get *(test+n+n), which may be rewritten as *(test+2*n).
Clearly then, if you convert that back to array indexing notation, you end up with test[2*n], which indicates in simple form that you'll be querying every other element of the array.

cv::Mat_<Type> allocation error

I would like to instantiate a cv::Mat with a custom defined type, but the allocation seems to be failing. For example:
struct SType
{
int a;
char c[16];
};
cv::Mat m = cv::Mat_<SType>(1, 1);
printf("cols = %i rows %i step = %zi elemSize = %zi elemSize1 = %zi\n",
m.cols, m.rows, m.step[0], m.elemSize(), m.elemSize1() );
this provides the following output:
cols = 1 rows 1 step = 8 elemSize = 8 elemSize1 = 8
which is obviously wrong, since I'm expecting a elemSize of 20. Is this a bug or the cv::Mat_ wrapper is not supposed to be used with custom element types?
Edit:
When assigning the instance to a cv::Mat_ element instead
cv::Mat_<SType> m = cv::Mat_<SType>(1, 1);
printf("cols = %i rows %i step = %zi elemSize = %zi elemSize1 = %zi\n",
m.cols, m.rows, m.step[0], m.elemSize(), m.elemSize1() );
I get the following output:
cols = 1 rows 1 step = 8 elemSize = 20 elemSize1 = 20
Now, elemSize is correct, but step is wrong. As I understand, step is used to compute the specific element to access in the matrix via the operator() (row,col), and I'm observing problems when doing so. Anybody has a better insight on what's going on here?
Edit 2:
I submitted a bug report regarding this issue. http://code.opencv.org/issues/4415 . In the meantime, if anyone has an idea how to deal with it, please let me know. Thanks.
I think I spotted the mistake. You declare your variable as cv::Mat. Try:
cv::Mat_<SType> m = cv::Mat_<SType>(1, 1);

Iterate members of a bitfield

We have this example:
struct X {
int e0 : 6;
int e1 : 6;
int e2 : 6;
...
int e10 : 6;
};
struct X c;
How can I access the members "automatically", something like that:
c.e{0-10} ?
Say if I want to read c.e0, then c.e1 ...
If my struct would have 1000 elements, I do not think that I should write so much code, right ?
Can you help me with a workaround, an idea ?
I mention that I already read other posts related somehow to this problem, but I did not find a solution.
Thank you very much !
As others have said, you cannot do exactly what you want with bit fields. It looks like you want to store a large number of 6 bit integers with maximum space efficiency. I will not argue whether this is a good idea or not. Instead I will present an old-school C like way of doing exactly that, using C++ features for encapsulation (untested). The idea is that 4 6 bit integers require 24 bits, or 3 characters.
// In each group of 3 chars store 4 6 bit ints
const int nbr_elements = 1000;
struct X
{
// 1,2,3 or 4 elements require 3 chars, 5,6,7,8 require 6 chars etc.
char[ 3*((nbr_elements-1)/4) + 3 ] storage;
int get( int idx );
};
int X::get( int idx )
{
int dat;
int offset = 3*(idx/4); // eg idx=0,1,2,3 -> 0 idx=4,5,6,7 -> 3 etc.
char a = storage[offset++];
char b = storage[offset++];
char c = storage[offset];
switch( idx%4) // bits lie like this; 00000011:11112222:22333333
{
case 0: dat = (a>>2)&0x3f; break;
case 1: dat = ((a<<4)&0x30) + ((b>>4)&0x0f); break;
case 2: dat = ((b<<2)&0x3c) + ((c>>6)&0x03); break;
case 3: dat = c&0x3f; break;
}
return dat;
}
I will leave the companion put() function as an exercise.
It sounds like a struct isn't the right tool for what you're trying to do. You need either an array or a vector. Arrays are used for storing a number of the same type of data. Vectors are array wrappers that manage the addition and removal of items automatically.
If you need a list of the same data, and some other data (say a string) you can make an array or a vector part of your struct.
struct X {
int[10] numbs;
string name;
};
X c;
You can't. To do this would require some form of reflection, which is not supported in either C or C++.
Since your bitfields are of the same size, you could encapsulate std::bitset (or vector<bool>, gulp...) and provide your own iterators (each increment moving the bookmark six bits) and operator[] (etc) to allow your code to be more simple to write.
I am sure performance would suck compared to the bitfields though.
How about something like this:
char getByte(char *startPos, int index) {
int i = (index*6) / 8;
if (index % 4 == 0)
return 0b11111100 & startPos[i] >> 2;
else if (index % 4 == 3)
return 0b00111111 & startPos[i];
else if (index % 4 == 2)
return (0b00001111 & startPos[i] << 2) | (0b11000000 & startPos[i+1] >> 6);
else
return (0b00000011 & startPos[i] << 4) | (0b11110000 & startPos[i+1] >> 4);
}

Lookup tables in C++

I have to implement small multimage graphic control, which in essence is an array of 9 images, shown one by one. The final goal is to act as minislider.
Now, this graphic control is going to receive various integer ranges: from 5 to 25 or from 0 to 7 or from -9 to 9.
If I am going to use proportion - "rule of three" I am afraid is not technically suistainable because it can be a source of errors. My guess is to use some lookup tables, but has anyone an good advice for approach?
Thnx
I'm not sure look up tables are required. You can get from your input value to an image index between 0 and 9 proportionally:
int ConvertToImageArrayIndex(int inputValue)
{
int maxInputFromOtherModule = 25;
int minInputFromOtherModule = 5;
// +1 required so include both min and max input values in possible range.
// + 0.5 required so that round to the nearest image instead of always rounding down.
// 8.0 required to get to an output range of 9 possible indexes [0..8]
int imageIndex = ( (float)((inputValue-minInputFromOtherModule) * 8.0) / (float)(maxInputFromOtherModule - minInputFromOtherModule + 1) ) + 0.5;
return imageIndex;
}
yes, a lookup table is a good solution
int lookup[9] = {5, 25, ... the other values };
int id1 = floor(slider);
int id2 = id1+1;
int texId1 = lookup[id1];
int texId2 = lookup[id2];
interpolate(texId1, texId2, slider - float(id1));