This code works but there must be a better/more elegant way

Using this example from:

http://arduino.cc/forum/index.php/topic,43587.0.html

typedef struct
  {
      int one;
      int two;
      int three;
  }  record_type;

record_type record[8];

void setup()
{
}

void loop()
{
  record[0].one = 1;
  record[0].two = 2;
  record[0].three = 3;
  record[1].one = 4;
  record[1].two = 5;
  record[1].three = 6;
  record[2] = (record_type) {1,2,3};
}

I have come up with this:

typedef struct
  {
      int Ch1;
      int Ch2;
      int Ch3;
      int Ch4;
      int Ch5;
      int Ch6;
      int Ch7;
      int Ch8;
  }  record_type;

record_type record[4];

void setup()
{
  record[0].Ch1 = 1; record[0].Ch2 = 2; record[0].Ch3 = 3; record[0].Ch4 = 4; record[0].Ch5 = 5;  record[0].Ch6 = 6; record[0].Ch7 = 7; record[0].Ch8 = 8;
  record[1].Ch1 = 5705; record[1].Ch2 = 5685; record[1].Ch3 = 5665; record[1].Ch4 = 5645; record[1].Ch5 = 5885; record[1].Ch6 = 5905; record[1].Ch7 = 5925; record[1].Ch8 = 5945;
  record[2].Ch1 = 0; record[2].Ch2 = 1; record[2].Ch3 = 0; record[2].Ch4 = 1; record[2].Ch5 = 0; record[2].Ch6 = 1; record[2].Ch7 = 0; record[2].Ch8 = 1;
  record[3].Ch1 = 0; record[3].Ch2 = 0; record[3].Ch3 = 1; record[3].Ch4 = 1; record[3].Ch5 = 0; record[3].Ch6 = 0; record[3].Ch7 = 1; record[3].Ch8 = 1;
  record[4].Ch1 = 0; record[4].Ch2 = 0; record[4].Ch3 = 0; record[4].Ch4 = 0; record[4].Ch5 = 1; record[4].Ch6 = 1; record[4].Ch7 = 1; record[4].Ch8 = 1;
  //record[5] = (record_type) {1,2,3};
}

void loop()
{
  
}

I moved it from loop to setup - it didn't seem to be in the right place.

The problem is, although it compiles, it was done mostly by rote and I do not fully understand it. More important, if it works, how do I use the data?

Regards

Alan

I was really imagining the structure containing, say, a "float" for the frequency, and possibly a digit (byte) for the channel selector, though this could be derived from the index.
Then you would have an array of these.

Think of a structure as a single card in a card index.

Yes. Factor it along the other axis: make a struct with the bits and pieces for one channel, and then an array of that struct, one for each channel.

Then you can refer to the items of a particular channel as channels[3].name and channels[3].selector, or whatever you name the per-channel fields.

-br

thanks guys - card index it is - but not today.

goodnight

void setChan (byte chan)
{
  digitalWrite(ChSet1, bitRead (chan, 0));
  digitalWrite(ChSet2, bitRead (chan, 1));                          
  digitalWrite(ChSet3, bitRead (chan, 2));
}

Uncompiled, untested, but should save a fair amount of code.

record_type record[4];

So, you have 4 elements in the array.

  record[0].Ch1 = 1; record[0].Ch2 = 2; record[0].Ch3 = 3; record[0].Ch4 = 4; record[0].Ch5 = 5;  record[0].Ch6 = 6; record[0].Ch7 = 7; record[0].Ch8 = 8;
  record[1].Ch1 = 5705; record[1].Ch2 = 5685; record[1].Ch3 = 5665; record[1].Ch4 = 5645; record[1].Ch5 = 5885; record[1].Ch6 = 5905; record[1].Ch7 = 5925; record[1].Ch8 = 5945;
  record[2].Ch1 = 0; record[2].Ch2 = 1; record[2].Ch3 = 0; record[2].Ch4 = 1; record[2].Ch5 = 0; record[2].Ch6 = 1; record[2].Ch7 = 0; record[2].Ch8 = 1;
  record[3].Ch1 = 0; record[3].Ch2 = 0; record[3].Ch3 = 1; record[3].Ch4 = 1; record[3].Ch5 = 0; record[3].Ch6 = 0; record[3].Ch7 = 1; record[3].Ch8 = 1;
  record[4].Ch1 = 0; record[4].Ch2 = 0; record[4].Ch3 = 0; record[4].Ch4 = 0; record[4].Ch5 = 1; record[4].Ch6 = 1; record[4].Ch7 = 1; record[4].Ch8 = 1;

And, you initialize all 5 of them. Fail!

AlanGP:
@UkHeliBob - Wow! - thank you but unhelpful. If you are finding this topic too difficult then please feel free put your feet up and watch the tele instead.

Wow, another thread spirals out of control while I am working on PHP stuff. Amazing! Better cut down the snaky comments if you are initializing 5 elements in an array of 4 items.

How to use this forum

Don't worry Nick. We have kissed and made up.

Channel 1 5705 Mhz = 000
Channel 2 5685 Mhz = 001
Channel 3 5665 Mhz = 010
Channel 4 5685 Mhz = 011
Channel 5 5885 Mhz = 100
Channel 6 5905 Mhz = 101
Channel 7 5925 Mhz = 110
Channel 8 5945 Mhz = 111

Another thing that's going to bite you on the arse is that channel 2 and channel 4 seem to share the same frequency.
Also, you should revisit the datatypes of your input and output pin designators - "boolean" may well work, but they are not inherently boolean values.

Thanks Guys - I am mostly away until Sunday. I will look at all the help and come back to you - I was dreaming about arrays of structs last night - or was it a nightmare!

@AWOL - Channel 2 and 4 - Yeh another typo!! Learning all the time.

I think have got my head around the "struct" bit, I'll put up (my version of) the code later and give you all a laugh!

regards

Alan

Please don't let your eyes glaze over and ignore this code.

If you don't want to understand it now it could be useful in the future.

#define ENTRIES(ARRAY)    (sizeof(ARRAY) / sizeof(ARRAY[0]))

struct record_t
{
    union
    {
                 int  _v[8];
        struct { int _chan1, _chan2, _chan3, _chan4, _chan5, _chan6, _chan7, _chan8; };
    };

    // non-parameterized constructor
    record_t()
        : _chan1(0), _chan2(0), _chan3(0), _chan4(0)
        , _chan5(0), _chan6(0), _chan7(0), _chan8(0)
    {}

    // parameterized constructor
    record_t(int chan1, int chan2, int chan3, int chan4, int chan5, int chan6, int chan7, int chan8)
        : _chan1(chan1), _chan2(chan2), _chan3(chan3), _chan4(chan4)
        , _chan5(chan5), _chan6(chan6), _chan7(chan7), _chan8(chan8)
    {}
};


// declaring an array of 'record_t' will call the non-parameterized version of
// the constructor for 'record_t'

record_t    record[7];

void setup()
{
    // ... populate the array 'record' at index 0 ...
    const int array1[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
    for ( size_t i = 0; i < ENTRIES(array1); i++ )
    {
        record[0]._v[i] = array1[i];
    }

    // ... populate the array 'record' at index 1 ...
    const int array2[] = { 5705, 5685, 5665, 5645, 5885, 5905, 5925, 5945 };
    for ( size_t i = 0; i < ENTRIES(array2); i++ )
    {
        record[1]._v[i] = array1[i];
    }

    // ... populate the array 'record' at index 2 ...
    const int array3[] = { 0, 1, 0, 1, 0, 1, 0, 1 };
    for ( size_t i = 0; i < ENTRIES(array3); i++ )
    {
        record[2]._v[i] = array1[i];
    }

    // ... populate the array 'record' at index 3 ...
    const int array4[] = { 0, 0, 1, 1, 0, 0, 1, 1 };
    for ( size_t i = 0; i < ENTRIES(array4); i++ )
    {
        record[3]._v[i] = array1[i];
    }

    // ... populate the array 'record' at index 4 ...
    // ... from end of 'array5' to start of 'array5'
    const int array5[] = { 0, 0, 0, 0, 1, 1, 1, 1 };
    for ( size_t i = ENTRIES(array5); i--; )
    {
        record[4]._v[i] = array1[i];
    }

    // ... populate the array 'record' at index 5 using the parameterized
    // version constructor of 'record_t' ...
    record[5] = record_t(0, 1, 2, 3, 4, 5, 6, 7);

    // ... array 'record' at index 6 was initialize to 0 using the
    // non-parameterized constructor at declaration ...
}

void loop()
{}

@lloyddean

Thanks - I do want to understand the code and will work through the replies, all of which have exceeded my present level of skill and understanding. I have yet to experience the Eureka moment. With an array of structs, an existing set of fixed data and not having even used arrays before it might take some time. Thank you all for your patience.

Alan

OK - in card index form this time - here is the laugh I promised:

typedef struct
  {
      byte Channel_Number;    //Number in range 1-8 
      int Channel_Frequency;  //Whole Number in range 5705 to 5945 - I think that data type "Float" would allow me to use a decimal point to display in GHz instead of MHz.?
      boolean Output_Pin1;    // The pin is either HIGH or LOW, 1 or 0 - However, could also be type "byte" (same size)
      boolean Output_Pin2;    // Ditto
      boolean Output_Pin3;    // Ditto
    
  }  record_type;  //What does this do? I think it says thay the struct i.e. all the data is to be treated as a single (array like) record?

record_type record[9];  //I think this line names the record type "record" with a storage size of 9 (arrays) ?

void setup()
{
  record[0].Channel_Number = 1; record[0].Channel_Frequency = 5705; record[0].Output_Pin1 = 0; record[0].Output_Pin2 = 0; record[0].Output_Pin3 = 0;
  record[1].Channel_Number = 2; record[1].Channel_Frequency = 5685; record[1].Output_Pin1 = 1; record[1].Output_Pin2 = 0; record[1].Output_Pin3 = 0;
  record[2].Channel_Number = 3; record[2].Channel_Frequency = 5665; record[2].Output_Pin1 = 0; record[2].Output_Pin2 = 1; record[2].Output_Pin3 = 0;
  record[3].Channel_Number = 4; record[3].Channel_Frequency = 5645; record[3].Output_Pin1 = 1; record[3].Output_Pin2 = 1; record[3].Output_Pin3 = 0;
  record[4].Channel_Number = 5; record[4].Channel_Frequency = 5885; record[4].Output_Pin1 = 0; record[4].Output_Pin2 = 0; record[4].Output_Pin3 = 1;
  record[5].Channel_Number = 6; record[5].Channel_Frequency = 5905; record[5].Output_Pin1 = 1; record[5].Output_Pin2 = 0; record[5].Output_Pin3 = 1;
  record[6].Channel_Number = 7; record[6].Channel_Frequency = 5925; record[6].Output_Pin1 = 0; record[6].Output_Pin2 = 1; record[6].Output_Pin3 = 1;
  record[7].Channel_Number = 8; record[7].Channel_Frequency = 5945; record[7].Output_Pin1 = 1; record[7].Output_Pin2 = 1; record[7].Output_Pin3 = 1;
  
//The next line is a guess but it compiles in this form - why record [8] apart from it is the next numeric increase and won't compile without a number? ( Giving a record storage size of 9 - see above)
  
  record[8] = (record_type) {0,1,2,3,4}; 

/*
What is this - my guess is that it holds the output of the array of structs ? Is it correct and, if so, how do I use the information?

Like this?   record[channel number] {array cell 1, array cell 2,.....};?
*/
}

void loop()
{
  
}

I have almost got my head around the "array" and "structure" elements but still no "Eureka" moment. I am aware that there are a number of replies with code suggestions that don't feature here but I have yet to get past this point.

regards

Alan

      boolean Output_Pin1;    // The pin is either HIGH or LOW, 1 or 0 - However, could also be type "byte" (same size)

Not could. Should.

While boolean and byte are the same size, boolean implies something about the contents of the variable (true or false) and the context in which it will be used that are NOT appropriate for your variables.

//What does this do? I think it says thay the struct i.e. all the data is to be treated as a single (array like) record?

The typedef statement assigns a more intuitive name (at least, that is the intent) to an existing type. The existing type is anonymous struct which is hard to use elsewhere in the program, so it is necessary to assign it another name. One that IS usable later.

By creating a named structure (the name goes between struct and the {), the typedef is not as necessary. Still, it is often easier to type "someName" for a type than "struct someName".

record_type record[9];  //I think this line names the record type "record" with a storage size of 9 (arrays) ?

It creates an array (that is what the [] on the end means) named record, of type record_type (the typedef'd name of the anonymous structure).

//The next line is a guess but it compiles in this form - why record [8] apart from it is the next numeric increase and won't compile without a number? ( Giving a record storage size of 9 - see above)

You have an enter key, don't you. Use it. Mile long comments are a pain in the ass to read.

There are several ways to initialize a struct instance. You can assign values to each element of the struct, as you did in the previous lines, or you can assign values to all elements in the struct by providing a list of values in the proper order, as in the next line of code.

The second way works only when initializing the array object the first time.

@PaulS thank you - got most of that:

boolean - use only when TRUE or FALSE is relevant in the program. Otherwise, byte is appropriate, particularly in an ON - OFF hardware environment.

The first instance of Record_Type gives the anonymous struct a defined name that can be used later. The second instance (Record_Type Record[]) confirms that the data types defined in the struct "Record_Type" are intended to be used as an array called "record[]" The number "[9]" defines the storage space within the array.

Verbose commenting mode now off.

The line "record[8] = (record_type) {0,1,2,3,4};" is a one-off initialisation of the array object. So the contents of the array of structs can be expressed as I thought?

I.E. record[] = (record_type) {0,1,2,3,4}; giving something like record[1] (record_type[1]) = "5705"

My apologies if the concept or syntax or both are wrong.

regards

Alan

I.E. record[] = (record_type) {0,1,2,3,4}; giving something like record[1] (record_type[1]) = "5705"

You need a value in the brackets, because you are not creating a new array with one element. You are initializing one element of an array. The values in the {} are used to initialize the members of the structure, in the order that they appear in the structure (Channel_Number, Channel_Frequency, Output_Pin1, Output_Pin2, and Output_Pin3).

@PaulS - Sorry to be thick. If it answered my question I didn't understand how. Could you offer an example with the appropriate syntax.

Could you offer an example with the appropriate syntax.

Your code had an example.

  record[8] = (record_type) {0,1,2,3,4};

Sorry for the lack of verbose description but hopefully this will be somewhat self explanatory.

Roughly your code aped back at you in the form of arrays of structs as I interpreted the last code you posted above.

// logically this describes to the compiler what a block of memory we've named
// as 'record_t' will look like.
//
// From it the compiler will then know such a item in memory will have field
// names as given, in the order given and of the sizes as specified by the data
// 'types' specified before the field name.
//
// collectively a symbol when defined of type 'record_t' occupies 6 bytes

struct record_t
{
    byte    Channel_Number;         // this will occupy 1 byte space
    int     Channel_Frequency;      // this will occupy 2 bytes space
    boolean Output_Pin1;            // this will occupy 1 byte space
    boolean Output_Pin2;            // this will occupy 1 byte space
    boolean Output_Pin3;            // this will occupy 1 byte space
};


// here we actually declare an arrays of our user defined type 'record_t' we've
// specified the layout of above
//
// this array of type 'record_t' will reserve space in memory for the number of
// 'record_t' as specified by the provided initializer values
//
// in this case if I've added them correctly we will have reservered space for 8
// sequential 6 byte blocks of memory in the form of an 'record_t' as specified
// above

// the initial array values can be set during declaration only as follows

record_t records[] = 
{
      { 1, 5705, 0, 0, 0 }  // 0
    , { 2, 5685, 1, 0, 0 }  // 1
    , { 3, 5665, 0, 1, 0 }  // 2
    , { 4, 5645, 1, 1, 0 }  // 3
    , { 5, 5885, 0, 0, 1 }  // 4
    , { 6, 5905, 1, 0, 1 }  // 5
    , { 7, 5925, 0, 1, 1 }  // 6
    , { 8, 5945, 1, 1, 1 }  // 7
};

void setup()
{
    // copy the array members into the fields of the structure 'record_t' in the
    // order in which they appear listed n the array
    //
    //  'Channel_Number', 'Channel_Frequency', Output_Pin1, Output_Pin2, Output_Pin3
    //
    // the 'magic' that lets the compiler do this is the cast operator
    // '(record_t)' which tell the compiler the data is in the form of a
    // 'record_t'
    record[8] = (record_t){ 0, 1, true, false, false };
}

void loop()
{}