using sizeof() to calculate arrays passed as parameters

Hi folks. I'm trying to pass an array as a parameter in a function.it works fine other than the sizeof() element within the function which does not return the correct result.
I believe this is something to do with pointers according to some search results (which were in the context of the c language) so i just wanted to double check whether within the arduino envornoment there was an eloquent solution to my problem or do i have to calculate the sizeof() outside of the function?
Thanks in advance,
Dan.

void loop() {
motion(xMotion01,yMotion01);
delay(500);
}

void motion(byte xMotion[],byte yMotion[]){
    for(int i = 0; i < sizeof(xMotion); i++){//loop over both the x and y arrays, writing the values to the servo
   Serial.println(sizeof(xMotion));
         delay(1000);
    }
}

When you pass an array to a function what you are actually passing is a pointer to the array, so sizeof() will not give you the size of the array if used in the function. If the function needs to use the size of the array then it must be passed to the function explicitly.

so i just wanted to double check whether within the arduino envornoment there was an eloquent solution

The "Arduino environment" is C/C++, so no, there is no elegant solution, apart from, perhaps, encapsulation.

You could either pass in the count as a parameter or have some type of termination/end of array indicator in the array itself.
To use an indicator, make the array big enough to hold all your elements and room for one more.
Then when you populate the array, add one additional entry to the array with a value that indicates "this is the end of the array".
The key is to pick a value that can never occur.
If say 0 or 255 can't/won't happen you could use one of those.
If all values 0-255 can happen, then you are stuck passing in a count if the size of the data in the array varies from call to call.

--- bill

Thanks very much, all very informative responses. I've decided to just pass the value to the function as its not that much of a problem. Just seems a little 'clunky' of a solution but what the hey! Thanks again. Danny.

gonadgranny:
Thanks very much, all very informative responses. I've decided to just pass the value to the function as its not that much of a problem. Just seems a little 'clunky' of a solution but what the hey! Thanks again. Danny.

maybe an example helps... just pass the size of your array to the function along with the pointer to the array:

byte xMotion01[20];

void loop()
{
  motion(xMotion01, sizeof(xMotion01)/sizeof(xMotion01[0])); // size of the array divide by the size of the first element of the array = number of array elements
  delay(500);
}

void motion(byte* xMotion, size_t arraySize)
{
  for (int i = 0; i < arraySize; i++)  //loop over both the x and y arrays, writing the values to the servo
  { 
    // do something 
  }
}

I guess the real question is does the number of valid entries in the array ever differ from the size of the array?
--- bill

Quite often you'll see Bulldog's solution written as:

#define ARRAYCOUNT(x)     (sizeof(x)/sizeof(x[0]))

// more code...

void loop()
{
  motion(xMotion01, ARRAYCOUNT(xMotion01)); // size of the array divide by the size of the first element of the array = number of array elements
  delay(500);
}

There are two nice features of his approach: 1) if you change the size of the array, the remaining code is automatically adjusted, and 2) it is typeless. That is, the macro works for any array data type where sizeof() can be used.

1 Like

The arrays are constants.
So yes the size will always be the same.
Since you are all here I may as well increase the scope of my problem. I am trying to create a system which allows me to ‘play’ certain sequences of numbers which are fed to a servo. I have recorded my numbers which are stored(currently) in 2 arrays, x and y.
I created a function which enables me to loop over and ‘play’ these individual ‘motions’ but now I want to create a function which takes an array of numbers which represent individual motions and the timing value between them.
The problem I am having is thinking of how I can reference these ‘complex’ motions without doing a whole bunch of if statements. Would creating a motion object be the right approach?
I will include some of my current code to try and illustrate how I am thinking so far. The first function works, the second one is just a sketch. In the xMotions[] and yMotions[] array i want to store a reference to the xPos01[] yPos01[] etc. arrays. This is where i am struggling. If anyone understand what i am getting at and has a suggestion that would be fantastic. Thanks. Danny.

const byte xPos01[]  = {105, 104, 101, 96, 92, 86, 81, 76, 69, 67, 63, 62, 60, 60, 59, 59, 59, 59, 59, 59, 59, 60, 61, 64, 70, 79, 85, 96, 101, 103, 104, 104, 105, 106, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107};
const byte yPos01[]  = {62, 63, 64, 68, 70, 72, 75, 75, 75, 74, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 74, 74, 76, 76, 75, 73, 70, 68, 67, 66, 64, 62, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61};
const byte Motion02Size = sizeof(xPos02);


void playMotion(const byte xPos[], const byte yPos[], const byte s) {//function takes the array of positions
  for (int i = 0; i < s; i++) { //loop over both the x and y arrays, writing the values to the servo
    int yM = map(yPos[i], 0, 180, 180, 0); //invert the y value
    xServo.write(xPos[i]);
    yServo.write(yM);
    delay(20);
  }
}

byte xMotions[];//array containing the references to the motions
byte yMotions[];
byte motionSizes[];
int timings[];

void playSequence(byte xMotions[],byte yMotions[],byte motionSizes[],int timings[]),  {//loop over the array of motions and play them with the delay inbetween
  for (int i = 0; i < s; i++){
    playMotion(xMotions[i], yMotions[i], motionSizes[i]);//find the motion to play in the array
  delay(timing[i]);//fetch the timing value from the array
}

}

Why not a single array of ints with alternate servo positions and delay periods. A dummy (impossible) value as the last entry in the array, such as -1, could be used to signal the end of the sequence when read from the array.

One array, no need to pass the array size and easy to maintain, test and expand.

Having said that, I am not sure that delay() is the ideal method to use unless only one servo needs to move at a time and nothing else is happening in the program whilst the servo(s) are moving.

gonadgranny:
Would creating a motion object be the right approach?

I think it may be. create an array of xPos, yPos and the time to stay in that postion:

struct MotionParameters{
  byte xPos;
  byte yPos;
  int holdTime;
};

MotionParameters sequenceA = {
  { 20, 40, 325},
  { 25, 45, 500},
  ...

kind-of-thing...

Why not a single array of ints with alternate servo positions and delay periods. A dummy (impossible) value as the last entry in the array, such as -1, could be used to signal the end of the sequence when read from the array.

i do like the idea of a single array. my main reason for separating them was because i am planning on having quite a lot of data in the end so wanted to separate the timings which measured in ms will become quite large (int) and the servo positions which can be stored as bytes. The dummy value on the end is a fine idea, i shall look into that. as for the delay i wont be using that its just a 'logic placeholder' so to speak to keep me sane while i try and figure out my approach. (im familiar how to do things without delay but its still a bit more brain churning than good old 'simple as hell' delay)

With regards to using an object, i have tried to create one but am having a few errors pop up. i am familiar with OOP within the context of Processing but this is the first time ive tried to use it here.
Is it possible to make an object array in Arduino like in Processing? This would solve my problem of having to manage several arrays for each Motion as they could be encapsulated within an object and then these objects could be stored in an object array...
Ive included the code ive written so far:
ps. the error is:

incompatible types in assignment of 'byte* {aka unsigned char*}' to 'byte [0] {aka unsigned char [0]}'

Its something to do with how i have set up the arrays in my constructor but im not sure how they should be done...

const byte xMotion01[]  = {99, 100, 100, 99, 99, 99, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98};
const byte yMotion01[]  = {74, 64, 56, 51, 49, 49, 48, 48, 48, 48, 49, 52, 59, 62, 67, 71, 73, 75, 75, 75, 74, 66, 60, 56, 52, 50, 50, 50, 50, 51, 55, 63, 65, 71, 74, 76, 77, 77, 77, 77, 77};
const byte size01 = sizeof(xMotion01);


//object will be passed the arrays containing the sequence required.it contains methods to play forward and backwards
class Motion {//class to encapsulate the functionality required to play a motion
    byte xMotion[];//byte arrays
    byte yMotion[];
    byte s[];//sizes of byte arrays

  public:
    Motion(byte xMotion_[], byte yMotion_[], byte s_[]) {//pass the arrays containing the x and y motions and the sizes thereof
      xMotion = xMotion_;
      yMotion = yMotion_;
    }

    void play() { //play forward
      for (int i = 0; i < s; i++) { //loop over both the x and y arrays, writing the values to the servo
        xServo.write(xMotion[i]);
        yServo.write(yMotion[i]);
        delay(20);
      }
    }
    void playBack() { //play backwards
      for (int i = s; i > 0; i--) { //loop over both the x and y arrays, writing the values to the servo
        xServo.write(xMotion[i]);
        yServo.write(yMotion[i]);
        delay(20);
      }
    }

}

which measured in ms will become quite large (int) and the servo positions which can be stored as bytes.

How long do you anticipate the "delays" will be and how accurate do they have to be ? You could, for instance, hold the delay values as seconds in the array and multiply by 1000 when you need to use them as milliseconds. That way you could use an array of bytes and still get up to 255 seconds delay.

Other solutions are available such as putting the angle and delay values into a struct as a pair and creating an array of the structs. That would allow you to use appropriate (different) data types for both values.

As for the use of delay(). Whilst I appreciate your reasons for using it for now it will be increasingly difficult to change to millis() for timing when the program becomes more complicated so I suggest that you change the method used for timing as soon as possible.

As for the use of delay(). Whilst I appreciate your reasons for using it for now it will be increasingly difficult to change to millis() for timing when the program becomes more complicated so I suggest that you change the method used for timing as soon as possible.

Duly noted, thanks. I've been looking at an implementation of blink which uses objects (and delay without blink) and it looks like an approach i could use for my situation. I have tried to change it so that the 'Flasher' objects are stored in an array but the program stops working. Can anyone see where things might have gone wrong? The program compiles fine but the led does nothing.

class Flasher
{
  // Class Member Variables
  // These are initialized at startup
  int ledPin;      // the number of the LED pin
  long OnTime;     // milliseconds of on-time
  long OffTime;    // milliseconds of off-time

  // These maintain the current state
  int ledState;                 // ledState used to set the LED
  unsigned long previousMillis;   // will store last time LED was updated

  // Constructor - creates a Flasher 
  // and initializes the member variables and state
  public:
  Flasher(int pin, long on, long off)
  {
  ledPin = pin;
  pinMode(ledPin, OUTPUT);     
    
  OnTime = on;
  OffTime = off;
  
  ledState = LOW; 
  previousMillis = 0;
  }

  void Update()
  {
    // check to see if it's time to change the state of the LED
    unsigned long currentMillis = millis();
     
    if((ledState == HIGH) && (currentMillis - previousMillis >= OnTime))
    {
      ledState = LOW;  // Turn it off
      previousMillis = currentMillis;  // Remember the time
      digitalWrite(ledPin, ledState);  // Update the actual LED
    }
    else if ((ledState == LOW) && (currentMillis - previousMillis >= OffTime))
    {
      ledState = HIGH;  // turn it on
      previousMillis = currentMillis;   // Remember the time
      digitalWrite(ledPin, ledState);   // Update the actual LED
    }
  }
};


Flasher flashers[2] { { 3, 500,500},{4,100,100} };

void setup()
{
}

void loop()
{
  flashers[1].Update();
}

Ok I got it working, my syntax was a little out:
instead of this:

Flasher flashers[2] { { 3, 500,500},{4,100,100} };

its this:

Flasher flashers[2] = { Flasher(3, 500,500),Flasher(4, 500,500)};

I'm going to have a little fiddle around with this object oriented approach for the time being as it seems nice and 'tidy'. Thanks very much for all the help.

How long do you anticipate the "delays" will be and how accurate do they have to be ? You could, for instance, hold the delay values as seconds in the array and multiply by 1000 when you need to use them as milliseconds. That way you could use an array of bytes and still get up to 255 seconds delay.

Helibob, I dont quite get what you mean. here. This would limit your accuracy to 1 second would it not? making it pointless? Forgive me if i am not understanding you correctly...
( i need accuracy to within about a 10th of a second i suppose);

i need accuracy to within about a 10th of a second i suppose

That has given more insight into the requirements, but depending on how long the "delays" need to be you could still have accuracy to a 10th of a second using bytes to hold the "delay".

For instance, if a delay of 1.5 seconds is required then you could put 15 in the byte array and multiply it by 100 to get the actual delay in milliseconds.

What is the longest delay that you anticipate using ?

What is the longest delay that you anticipate using ?

Its difficult to say at this point but probably not more than about 5 seconds...

Its difficult to say at this point but probably not more than about 5 seconds...

Then a 2 digit entry in an array of bytes could give you your required resolution (not accuracy) of 1/10th of a second. For a 5 second delay an entry of 50 multiplied by 100 would give you 5000 milliseconds whilst an entry of 49 would give you 4900 milliseconds.

Would one not require an extra bit to tell the program that the result needs to be multiplied, and by what? I suppose i could get it to multiply if the number is lower than a threshold value since i will not be using timings less than 1/10 second. is that what you had in mind?

Would one not require an extra bit to tell the program that the result needs to be multiplied, and by what?

No. If the longest time period is 5 seconds and every entry is 2 digits then any 2 digit number can be multiplied by 100 to derive the millisecond value required for timing.

Want a 200 millisecond delay ? Put 2 in the arrays and multiply by 100. 200 milliseconds
Want a 4700 millisecond delay ? Put 47 in the array and multiply by 100. 4700 milliseconds
etc

The shortest delay available using this method is 100 milliseconds, which is 1/10th of a second, but as you said that you only wanted to have a resolution of that magnitude it fits the bill.