Local array sizeof()

Hi all, new here, please forgive me if I err in etiquette.

I want to use a local array of ints in a function, and I want to pass a global array of changeable size to it. eg

setup(){
int global_array[] = {1,2,3};
int anotherglobal_array[] = {1,2,3,4};
int thirdglobal_array[] = {1,2,3,4,5};
}

loop(){
myfunction(one of the global_arrays, int parameter2)
}

void myfunction(local_array_name, 67){
int s = sizeof(localarray);
int w = local_array_name[3];
//other stuff
}



I can do something like:

void  myfunction(int local_name[]) {  

and then use eg local_name[13] as an int, but if I use
sizeof(local-name)

I always get 4.

Any idea why? Incidentally the roll-over of an example of local-name[] says it is an int* of value 4, I presume the star means it is an array?

Thanks

Welcome to the forum

When you pass an array to a function what you actually pass is a pointer to it. So, sizeof() used in the function returns the size of the pointer, not the number of elements in the array. Note too that even if it worked, sizeof() an array returns the number of bytes used by the array not the number of elements in the array

If you need to pass an array to a function then you must also explicitly pass the number of elements in the array.

No, it means that it is a pointer to an int.

To determine the number of elements in an array you can do this

int elementCount = sizeof(theArray) / sizeof(theArray[0]);

The arrays named "global_array", etc. below are in fact local to the function named setup, and vanish when setup() finishes.

To make them truly global, move the declarations to be outside of any function.

setup(){
int global_array[] = {1,2,3};
int anotherglobal_array[] = {1,2,3,4};

I cannot puzzle out what that line is supposed to do.

Thanks! That helps.

You write:
If you need to pass an array to a function then you must also explicitly pass the number of elements in the array.

but this is not so, as in the second example I gave

void myfunction(int local_name[])

which is actual deployed code, and works. (I am very beginnery, but in C++ wouldn't it be

void myfunction(int[] local_name)

? I digress

What I want is for the function to create a local copy of the global array, under a different name, which works just like an ordinary array or variable, and which can eg be changed without affecting the global array. Also it has to be of previously-unknown size.

Any ideas?

Thanks

@peteyf

you could use a template

int global_array[] = {1, 2, 3};
int anotherglobal_array[] = {1, 2, 3, 4};
int thirdglobal_array[] = {1, 2, 3, 4, 5};


template<size_t size> void myfunction(int (&array)[size], int another) {
  // int s = sizeof(array);
  int w = array[0];
  (void)another; // unused in the demo
  //other stuff
  Serial.print(size);
  Serial.print("\t");
  Serial.println(w);
}

void setup() {
  Serial.begin(115200);
  delay(500); // wait for Serial

  Serial.println("call by reference");

  myfunction(global_array, 42);
  myfunction(anotherglobal_array, 42);
  myfunction(thirdglobal_array, 42);
}

void loop() {

}

In the strictest sense you are correct. You do not need to pass the number of elements to the function but if you don't then you run the risk of accessing memory outside of the array bounds in your function

Suppose you pass an array with four elements and then write to the fifth element. What do you suppose would happen ?

As you seem to want to pass arrays of different sizes then checking that you are not reading or writing out of the array bounds would be a good idea. In your example code for the function you try to calculate the number of elements in the array using sizeof() so it is obviously important to you

Will the function always execute the same code whatever array is passed to it ? Maybe a for loop to read or write each element of the array

To do what you want the function must know how many elements are in the array

Maybe something like this ?

int array1[] = { 1, 2, 3 };
int array2[] = { 1, 2, 3, 4 };
int array3[] = { 1, 2, 3, 4, 5 };

void setup()
{
    Serial.begin(115200);
    aFunction(array1, sizeof(array1) / sizeof(array1[0]));
    aFunction(array2, sizeof(array2) / sizeof(array2[0]));
    aFunction(array3, sizeof(array3) / sizeof(array3[0]));
}

void loop()
{
}

void aFunction(int* arrayX, int count)
{
    int* p = &arrayX[0];
    for (int x = 0; x < count; x++)
    {
        Serial.print(*p + x);
        Serial.print(" ");
    }
    Serial.println();
}

Ignore my previous reply because the principle that it uses would allow alterations to the global array

If you gave us an idea what your function did it would help

You write:

When you pass an array to a function what you actually pass is a pointer to it.

That's stupid. Not you, the C++ people.

Inside a function one should either reference a global array (for which a pointer is fine) or have a local copy of it as a passed parameter, as happens with local variables etc. Pure laziness.

Reminds me of a couple of things, the first is blank lines in epubs. They aren't allowed because they might be a little difficult to implement and some nazi said so. Blank lines are widespread in printed books and magazines - compositors for printed books have many tricks to stop them from being on the first or last lines of pages and thus hard to recognise, but in flowed text there are no first or last lines on pages; however epub displaying programs could easily use the same tricks. More laziness.

The second is (or was) the tendency of FreeCAD to burp and refuse to continue when a union had less than two parts in it. No need, even if it's empty - it'll still be fine, and you shouldn't have to delete the union just because someone says so - you might want to add to it later, and if (where_the_union_should_be) is swamped in many layers of guff that need deconstructing and reconstructing ..

I have digressed more than enough.

On a somewhat related-to-the-subject note, I'd like to be able to do something like this:

void myfunction(int[] array_name, int name2){

called by eg

myfunction (int{1,2,3,4,5},11];

where {1,2,3,4,5} turns into a local array of five ints .

they say I'm a dreamer

A nice function which you can stuff anything into ..

Yes you have. Please stick to the subject of your topic

You can wish for whatever you like but it will not make it come true

What do you want your function to do in the real world ?

what's missing in my proposal #6?!?

Yeah, totally agree. They got so many things so wrong, it's no wonder almost no one uses either C or C++.

a7

You are forgiven for not having the slightest clue about the long history and remarkable success of C/C++, which began around 1970. You don't have to like the decisions that were made.

Very clever memory management from an age where total ram was in kbytes (by the way,this is the memory range as arduino uno...).

If you want to work with arrays with run time configurable size: take a look at std:: vector. It does not work for uno, but might work for other boards/chips.

You are also free to write custom classes...
On UNO like boards, you may quickly run into memory problems as heap memory may be eaten up by holes left after usage of your array.

Also: our small boards are not the fastest. Copying arrays is time consuming and may hamper time critical processes. Do not go there, people in 1970 were far smarter than today (did MS Word get any better after the ram was increased to 8 Gb)?

Everything is relative though. I was curious so wrote

const size_t totalSize = 512;
byte source[totalSize];
byte dest[totalSize];

void setup() {
  Serial.begin(115200);

  for (size_t i = 0; i < totalSize; i++) {
    source[i] = random(256);
  }

  TCCR1A = 0;          // Timer1 normal mode, OC1A/OC1B disconnected
  TCCR1B = 0;          // Stop Timer1, clear prescaler and mode bits
  TCNT1 = 0;           // Reset 16-bit counter
  TCCR1B = _BV(CS10);  // Start Timer1, no prescaler (16 MHz clock)

  noInterrupts();
  uint16_t t0 = TCNT1;
  memcpy(dest, source, totalSize);
  uint16_t t1 = TCNT1;
  interrupts();

  uint16_t ticks = t1 - t0;
  float time_us = ticks * 0.0625;
  Serial.println();
  Serial.println("------------------------------");
  Serial.print("Ticks = ");
  Serial.println(ticks);
  Serial.print("Time (µs) = ");
  Serial.println(time_us, 4);

  Serial.println("------------------------------");
  Serial.println(source[random(totalSize)]);
  Serial.println(dest[random(totalSize)]);
}

void loop() {}

➜ Duplicating 512 bytes (which would eat up half the memory on a UNO) takes ~256µs

so it's not nothing, but in the grand scheme of things (like handling buttons or reading a sensor) it's not huge either.

In their infinite wisdom, the C++ people gave you some choices :slight_smile:

Put your array in a struct and stop whining :)

struct ByteArray {
  uint8_t data[8];
};

// pass by value: a local copy of the struct is created on the stack and available  inside the function
// thus Modifications to this copy do not affect the original struct
void funcByValue(ByteArray b) {
  ...
}

// pass by pointer: no copy is made, the function works with the original struct via its memory address
void funcByPointer(ByteArray* b) {
  ...
}

// pass by reference: no copy is made, the function works directly with the original struct
void funcByReference(ByteArray& b) {
  ...
}

wouldn't it be wasteful to always provide a copy of an array, regardless of it's size. the user always has the option of copying the data using memcpy().

dispVec:    arr   1   2   3
dispVec:  local  -1  -2  -3
dispVec:    arr   1   2   3
#include <stdio.h>
#include <string.h>

void dispVec (
    char        vec [],
    int         nByte,
    const char *text )
{
    printf ("%s: %6s", __func__, text);
    for (int n = 0; n < nByte; n++)
        printf (" %3d", vec [n]);
    printf ("\n");
}

// -----------------------------------------------------------------------------
void myFunc (
    const char  vec [],
    int   nByte )
{
    char local [20];
    if (20 < nByte)
        nByte = 20;

    memcpy (local, vec, nByte);

    for (int n = 0; n < nByte; n++)
        local [n] = -vec [n];
    dispVec (local, nByte, "local");
}

// -----------------------------------------------------------------------------
int main ()
{
    char arr [] = { 1, 2, 3 };
    int  ArrSize = sizeof(arr);

    dispVec (arr, ArrSize, "arr");
    myFunc  (arr, ArrSize);
    dispVec (arr, ArrSize, "arr");

    return 0;
}

:rofl: :rofl: :rofl:

I still don’t understand what your target is, but about a function that must handle variable-sized arrays, it’s possible to use a ‘terminator mark’ at the very end of the array.

This ‘terminator mark’ is a value that is not supposed to occur in the array.

When your function reads it, it knows it reached the end of the array.