Can't read from LinkedList outside of function

Hi guys,

I have 0 experience programming in C++ or for Arduino, however I know what I'm doing in Python. It's been a huge learning experience so far, but I just can't understand what I'm doing wrong here. Hopefully you guys can point out the obvious mistake I'm making.

What I want is to define a global LinkedList which I can write to and read from in functions. Writing and reading within the same function seems to work fine, however outside of it, it doesn't return the expected values.

This is the sample code:

#include <LinkedList.h>
byte buffer[16];
uint8_t bytesReceived;

struct Model {
  uint8_t *type;
  uint8_t *id;
};

LinkedList<Model> modelList = LinkedList<Model>();

void setup() {
  Serial.begin(19200);
}

void processBytes() {
  while (Serial.available() > 0 && bytesReceived < sizeof(buffer)) {
    buffer[bytesReceived++] = Serial.read();
  }
  if (bytesReceived > 0) {
    uint8_t mType[1] = {0x0A};
    uint8_t mId[1] = {0x0B};
    Model model = {mType, mId};
    modelList.add(model);
    Serial.print("Added type: ");
    Serial.print(modelList.get(modelList.size()-1).type[0], HEX);
    Serial.print(", added id: ");
    Serial.println(modelList.get(modelList.size()-1).id[0], HEX);
  }
  bytesReceived = 0;
}

void loop() {
  processBytes();
  Serial.print("modelList size: ");
  Serial.println(modelList.size());
  for (int i = 0; i < modelList.size(); i++){
    Serial.println(modelList.get(i).type[0],HEX);
    Serial.println(modelList.get(i).id[0],HEX);
  }
  delay(3000);
}

wokwi source: https://wokwi.com/projects/342364526785593940

Current output:

modelList size: 0
Added type: A, added id: B
modelList size: 1
0
0

Expected output:

modelList size: 0
Added type: A, added id: B
modelList size: 1
A
B

The two arrays are local to processBytes() so by the time loop() reads the pointers (.type and .id) out of the Model, they point to where the data used to be. The pointers stop being valid when the arrays go out of scope at the end of processBytes().

You could make the arrays static, but then every Model would share the same arrays. The data should either be in your struct or the pointers in your struct should point to static or dynamically allocated data.

Why don't you just put the data in the struct:

struct Model {
  uint8_t type;
  uint8_t id;
};

This works:

Model model = {{0x0a}, {0x0b}};

Why model fields are pointers?

This gives me:

sketch.ino:21:34: error: braces around scalar initializer for type 'uint8_t*' {aka 'unsigned char*'}
     Model model = {{0x0a}, {0x0b}};

Thanks for the explanation, I though that something like that was going on. Like I said, I have 0 experience in this: how would I point the pointers to the static or dynamic allocated data?
The idea is that I either create or update (or remove) objects based on the serial response. So I need a dynamic list of objects (with a max of course) that I can update.

Why don't you just put the data in the struct

What do you mean exactly?

In this example it's just 1 byte, but in my project there will be 2 for these attributes, and there is a settings attribute which has a variable length. I could remove the pointers though.

You probably followed the advice in post #4, which is incompatible with the suggestion in post #3.

Apparently, the code you shared in this thread differs from the one in the Wokwi link. The suggestion in post #3 only works for the latter.

Hmm, weird, the code in the thread is the same as the wokwi link, if I replace lines 21, 22, and 23 with your suggestion, I get the error I shared earlier.

You must have hit the save button then. The Model definition used to look like this:

struct Model {
  uint8_t type[2];
  uint8_t id[2];
};

Sorry for the confusion, I saved/refreshed to original form.

I noticed that if I make type and id just 1 byte (no pointers), and I create a struct with {0x0A, 0x0B} it all works, tried it out in a new wokwi: https://wokwi.com/projects/342451779865150036

@jfjlaros your suggestion does work if the array size is pre-defined, however will be a third attribute which can be variable in length. Must be something silly I don't know about yet regarding pointers.

Be sure to 'free' the data if you are ever done with it.

#include <LinkedList.h>
byte buffer[16];
uint8_t bytesReceived;

struct Model
{
  uint8_t *type;
  uint8_t *id;
};

LinkedList<Model> modelList;

void setup()
{
  Serial.begin(19200);
}

void freeModel(Model *m)
{
  free(m->type);
  free(m->id);
  delete m;
}

void processBytes()
{
  while (Serial.available() > 0 && bytesReceived < sizeof(buffer))
  {
    buffer[bytesReceived++] = Serial.read();
  }

  if (bytesReceived > 0)
  {
    uint8_t * mType = (uint8_t *)malloc(1);
    if (mType != NULL)
      *mType = 0x0A;
      
    uint8_t * mId = (uint8_t *)malloc(1);
    if (mId != NULL)
      *mId = 0x0B;
      
    Model *model = new Model;
    if (model != NULL)
    {
      model->type = mType;
      model->id = mId;
      modelList.add(*model);
    }
    Serial.print("Added type: ");
    Serial.print(modelList.get(modelList.size() - 1).type[0], HEX);
    Serial.print(", added id: ");
    Serial.println(modelList.get(modelList.size() - 1).id[0], HEX);
  }

  bytesReceived = 0;
}

void loop()
{
  processBytes();
  Serial.print("modelList size: ");
  Serial.println(modelList.size());
  for (int i = 0; i < modelList.size(); i++)
  {
    Serial.println(modelList.get(i).type[0], HEX);
    Serial.println(modelList.get(i).id[0], HEX);
  }
  delay(3000);
}
1 Like

This works, nice and thank you!

How could I assign multiple bytes to *mType and *mId e.g. *mType = {0x0A, 0x0A} doesn't work.

Pointer syntax and array syntax are often interchangeable.

    uint8_t * mType = (uint8_t *)malloc(2);
    if (mType != NULL)
    {
      mType[0] = 0x0A;
      mType[1] = 0x0B;
    }
      
    uint8_t * mId = (uint8_t *)malloc(2);
    if (mId != NULL)
    {
      *(mId) = 0x0C;
      *(mId+1) = 0x0D;
    }

Thank you very much!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.