Search code examples
vectorstructarduinoscopearduino-c++

Arduino - Vector of struct showing wrong values. How correctly fill Vector with struct?


I have some difficulties with Arduino specifically with struct and/or scope. I come from a Python background so I don't completely understand how things work in C/C++.

I want to define a global vector/array (I tried both) and fill it with struct using a function. I aim to keep the code separate and have as little as possible in the loop() function.

I also tried to do this using a class. Inside the class's function, structs have valid values, but if I create a getter and access the vector/array of struct outside the class they somehow hold random values.

Below is a working example in C++ of what I am trying to do in Arduino:

#include <iostream>
#include <vector>
#include <unistd.h>


struct Remote {
    unsigned int remote_id;
};


static std::vector<Remote> remotes = {};


void setup(){
    // put your setup code here, to run once:
    remotes.push_back({50});
    Remote remote = {90};
    remotes.push_back(remote);
}

void loop(){
    // put your main code here, to run repeatedly:
    std::cout<< remotes[0].remote_id <<std::endl;  // 50
    std::cout<< remotes[1].remote_id <<std::endl;  // 90
    sleep(1);
}

int main()
{
    setup();
    while (true){
        loop();
    }
    return 0;
};

I get this as output:

50
90

which is correct.


And my Arduino code:

#include <Vector.h>

struct Remote {
  unsigned int remote_id;
};

static Vector<Remote> remotes = {};

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
    while (!Serial)
        continue;

  Remote remotes_array[2];
  remotes.setStorage(remotes_array);

  remotes.push_back({50});
  Remote remote = {90};
  remotes.push_back(remote);

}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println(remotes[0].remote_id);
  Serial.println(remotes[1].remote_id);
  delay(1000);
}

And here I get this output:

48386
48130

Why is the Arduino code printing random values as output, unlike the C++ code above which prints the expected values? Am I missing something? Should using pointers solve this issue?


Solution

  • As pointed out by @user253751 in the comments, the remotes_array is a local variable and the memory assigned to it gets deallocated after setup() is done. This makes the remotes misbehave as its memory has been "snatched" away now and the memory locations referred to by remotes[0].remote_id and remotes[1].remote_id do not belong to remotes anymore.

    So, the correct code would be:

    #include <Vector.h>
    
    struct Remote {
      unsigned int remote_id;
    };
    
    static Vector<Remote> remotes;
    Remote remotes_array[2]; // --> Move memory allocating array here, outside of setup()
    
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(115200);
        while (!Serial)
            continue;
    
      remotes.setStorage(remotes_array);
    
      remotes.push_back({50});
      Remote remote = {90};
      remotes.push_back(remote);
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
      Serial.println(remotes[0].remote_id);
      Serial.println(remotes[1].remote_id);
      delay(1000);
    }
    

    This issue occurred because the Vector lib in Arduino is totally different from vector in c++ if we look at how the memory gets allocated. As mentioned by the Vector lib author:

    A sequence container similar to the C++ std::vector, but instead of allocating memory dynamically, this container points to an external, statically allocated c style array.