Array of Arrays Help

Hi Guys,

I'm new here, although have a little programming experience.

Need a little help with the following array situation.

I have 16 arrays from patternA through to patternP each with 16 elements:
uint8_t patternA[16];
uint8_t patternB[16];
uint8_t patternC[16];
..
..
..
uint8_t patternP[16];

What I'm trying to achieve is an 'Array' of 'arrays' of sorts.
So when I create a 'for' loop I can cycle through and retrieve each element in each pattern.

Please see my example code. Its an example of going through ONLY two patterns, however rather than writing 16 of them, I would like to create a loop.

Thanks for your help.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  void recallPattern() {
  if (pattern == 1) {
    clearPattern();
    for (int i = 0; i < 16; i++) {
      if (patternA_StepState[i] == 1) {
        stepState[i] = 1;
      }
      if (patternA_buttonFlag[i] == true) {
        buttonFlag[i] = true;
      }
    }
  }
  if (pattern == 2) {
    clearPattern();
    for (int i = 0; i < 16; i++) {
      if (patternB_StepState[i] == 1) {
        stepState[i] = 1;
      }
      if (patternB_buttonFlag[i] == true) {
        buttonFlag[i] = true;
      }
    }
  }
}
Last edited on
Hello mtiger,

It looks like what you want is a 2D array unit_8 pattern[16][16];. Each row would be a pattern and each column would hold the 16 numbers for each pattern.

Hope that helps,

Andy
Hey Andy,

Thanks for your response.

That is something I thought I may need, however I'm a little confused as to how I would declare it first off and then set it up in my recallPattern() function.

As I have 16 individual arrays 'patternA_' through to 'patternP_', my initial thought would be to put it into another array...

1
2
3
4
5
6
7
8
9
10
uint8_t patternArray[16][16] =
{ {patternA_StepState[]} , {patternB_StepState[]} ,
  {patternC_StepState[]} , {patternD_StepState[]} ,
  {patternE_StepState[]} , {patternF_StepState[]} ,
  {patternG_StepState[]} , {patternH_StepState[]} ,
  {patternI_StepState[]} , {patternJ_StepState[]} ,
  {patternK_StepState[]} , {patternL_StepState[]} ,
  {patternM_StepState[]} , {patternN_StepState[]} ,
  {patternO_StepState[]} , {patternP_StepState[]} ,
}


However don't feel that is right...
Last edited on
Tried using a struct, however that didn't work

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct Pattern {
  uint8_t buttonFlag[16];
  uint8_t stepState[16];
};

Pattern patternArg[16];

void recallPattern() {
  for (int i = 0; i < 16; i++) {
    if (pattern == i) {
      clearPattern();
      if (patternArg[i].stepState[i] == 1) {
        stepState[i] = 1;
      }
      if (patternArg[i].buttonFlag[i] == true) {
        buttonFlag[i] = true;
      }
    }
  }
}
Wouldn't you be better with a 1-d array with 256 elements?
I'm with lastchance, along these lines
...
1
2
3
4
5
6
7
8
9
10
11
enum patz
{
   patternA,
   patternB = 16,
   patternC = 32,
    ...
  maxpatz = 256 
}
vector <uint8_t> patterns(maxpatz);

patterns[patternA] = ...;


function up the loop and all you need is the pattern# enum parameter and its good to go.
this has a small fragility, if you go out of bounds on a pattern you will mess up or read from the next pattern. But if you can handle iteration over a fixed length buffer, it is one simple way to solve the problem.
Last edited on
Thanks guys, however I need independent control over each pattern and each pattern[I] stepState.

Ideally, how can I put the following arrays into an array? So I can then loop through them?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
uint8_t patternA_StepState[16];
uint8_t patternB_StepState[16];
uint8_t patternC_StepState[16];
uint8_t patternD_StepState[16];
uint8_t patternE_StepState[16];
uint8_t patternF_StepState[16];
uint8_t patternG_StepState[16];
uint8_t patternH_StepState[16];
uint8_t patternI_StepState[16];
uint8_t patternJ_StepState[16];
uint8_t patternK_StepState[16];
uint8_t patternL_StepState[16];
uint8_t patternM_StepState[16];
uint8_t patternN_StepState[16];
uint8_t patternO_StepState[16];
uint8_t patternP_StepState[16];
Last edited on
You either put them in a 2-index array pattern_StepState[i][j] - as @handy andy advised you right at the start - and loop over the i index or i and j indices as you wish ...
... or you loop over a 1-index array pattern_StepState[k] with k going from 0 to 255.

Take your pick.
Last edited on
True, you can't iterate over a nonsequential enum as far as I know. There are ways to make it work, of course, either directly or with a little extra effort.

there are loads of ways to do what you want, if you don't like the above ideas.
here is one
typedef uint8_t pat[16];
pat arrayofpats[16];

the above can be done with vectors as well.

you can also do objects.
struct s //or a class
{
uint8_t pat[16];
};

s arrayofs[16]; //or a vector, or a pointer, or any other stl container

you can still use an enum to name array/vector/container index to track them by names if you like.

and you can do 2-d constructs (the typedef masks this but is identical and the struct is similar though not exactly identical) like
uint8_t pat[16][16]; //or doubled vectors, or pointers, etc


you can also just wrap what you have.
vector<uint8_t*> arrayofexisting(16);
arrayofexisting[0] = patternA;
arrayofexisting[1] = patternB;
...

and iterate the vector when you need to iterate all the guys, and use their direct variable names when you need that. Best of both worlds, minimal effort to add to existing code.





Ok, what confuses me as how I would write that out for my code:

I'm looping through the pattern [16] (1 of 16 patterns), then patternA [16] (1 of 16 pattern variables), then stepState[16] (1 of 16 spots in the array)

I've made the areas that I need to index in bold.
Pattern = 1 of 16;
PatternA = 1 of 16 (A to P);
stepState[I] = 1 of 16;

Hope that makes sense.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  void recallPattern() {
  if (pattern == 1) {
    clearPattern();
    for (int i = 0; i < 16; i++) {
      if (patternA_StepState[i] == 1) {
        stepState[i] = 1;
      }
      if (patternA_buttonFlag[i] == true) {
        buttonFlag[i] = true;
      }
    }
  }
  if (pattern == 2) {
    clearPattern();
    for (int i = 0; i < 16; i++) {
      if (patternB_StepState[i] == 1) {
        stepState[i] = 1;
      }
      if (patternB_buttonFlag[i] == true) {
        buttonFlag[i] = true;
      }
    }
  }
}
Last edited on
which approach do you want to use, and I will try to show you.
you should mask that 16 as a constant. Magic numbers cause problems when you need to update / modify/ grow the code later.


from the looks of it you have a fair bit of code, making me recommend the vector of pointers approach at the end of my last post, but Im ok with anything.

that might look like this:

//don't need any if pattern number things.
clearPattern();
for(i = 0; i < magic; i++)
{
if(vecpattern[patternnumber][i] == 1) //vecpattern [n] is a pointer that is the array start location for PatternB or whatever, so you can dereference it exactly as if it were PatternB here
stepState[i] = 1;
}

you can get funky and have a class that contains pointers, one for stepstate and one for button, or you can have 2 decoupled vectors .. I dunno, its YOUR data structure. It looks to me like you would want to couple them, but ?? If you were doing it from scratch you wouldn't probably do it this way at all, this is a retro-fit that is simple. Just be aware of that for next time ... this is a band-aid.

if you do it with the class its just 1 more layer
vecpattern[patternnumber][buttonptr][i] and vecpattern[patternnumber][stepptr][i]
Last edited on
Thanks Jonnin. You'll have to excuse my language inexperience.

Yes, I have a fair bit of code all laid out in a very inefficient way!!! What I have works however its very long and feel that I can shrink it dramatically.

I tried using a struct above, to give an understanding as to how I could condense it, however that didn't work.

I need to have independent control over each, pattern, pattern(A-P), and stepState[1-16].

I edited my previous post to hopefully explain it better :)
Last edited on
Based on your example it would be:

if(vecpattern[patternnumber]stepState[i] == 1)

As need to address the step state array as well.
Yes, couple them.

My logic was laid out in the struct I wrote, however not sure why that wouldn't work...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ok, so wherever you define patternA ...

struct patternwrapper
{
    uint8_t* stepptr;
    uint8_t* buttonptr;  //or is this bool?  
};

vector <patternwrapper> somename(magicvaluefor16);
somename[0].stepptr = patternA_StepState;
somename[0].buttonptr = patternA_buttonFlag;
... do this for all of them...

...
then use it like above:

somename[pattern].stepptr[i]  etc. 
Does this make sense or do you need more?  


/shrug I am not sure what you have at this point, buy my understanding is it worked but you had all the variables loose rather than contained nicely? Any of several of the above code can build a structure that works but most involve rewrites. What I just gave you patches in on top of what's there to provide a cleaner access point, that is ALL it really does. You can still use patternA etc variables where you need to, if you need to. Its all the same memory and which access point you use is just whatever is simple in the current code block...

a total re-write gets rid of the pointers of course. Then you don't have the risks of going out of bounds on anything. But that is a lot of work .. up to you if you think a do-over is needed.


Last edited on
Ok thank you.

Can I ask why my struct wouldn't work??

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct Pattern {
  uint8_t buttonFlag[16];
  uint8_t stepState[16];
};

Pattern patternArg[16];

void recallPattern() {
  for (int i = 0; i < 16; i++) {
    if (pattern == i) {
      clearPattern();
      if (patternArg[i].stepState[i] == 1) {
        stepState[i] = 1;
      }
      if (patternArg[i].buttonFlag[i] == true) {
        buttonFlag[i] = true;
      }
    }
  }
}
your struct will work. Its effectively the same thing, but I think somewhere you need an array of them:

vector<pattern> allthepatterns(valueof16);
then much like what I did...

allthepatterns[patternnumber].buttonFlag[i] //look familiar?

I patched into what you had. This leads to a more invasive re-write.
If you are going to do that, you may as well make the struct members vectors to clean it up a bit. And use bool type, not uint8, for true/false values.

and I still recommend that enum for patternA etc names, to index into allthepatterns (or whatever you want to name it). If you find that useful anywhere ? looks like
allthepatterns[patternA].buttonFlag[i] //if this is meaningful. Here, the enum is a more natural 0,1,2,3.... values, not the skip list in the original idea, and if you add a max_value to the end of it, that can BE your (value of 16) above number and it will grow for you without any work if you insert a patternX value someday...

enum pats
{
patternA, patternB, ... patternS, max_pats
};
vector ...blah... (max_pats);

insert patternX and max_pats fixes itself..!


Last edited on
Success!!!

My original struct was the solution, however I had missed the additional iteration of for (int j = 0; j < 16; j++)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void recallPattern() {
  for (int i = 0; i < 16; i++) {
    if (pattern == i) {
      clearPattern();
      for (int j = 0; j < 16; j++) {
        if (patternArg[i].stepState[j] == 1) {
          stepState[j] = 1;
        }
        if (patternArg[i].buttonFlag[j] == true) {
          buttonFlag[j] = true;
        }
      }
    }
  }
}


Appreciate your suggestions and help everyone.
Last edited on
Topic archived. No new replies allowed.