int* array get ruined

I'm having a bit of an issue with my int* array, and I don't really know where to begin, so here goes...

I'm trying to build a "memory game" that gets increasingly harder, where some LEDs should blink in sequence and the user must remember the sequence.

For the first 3 "levels", everything seems to be just fine, but by the 4th (and following) stage, then my data in the sequence array seems to be messed up somehow. I cannot see any pattern in how the data is messed up.

I'm creating my sequence as a part of setup() and does not write to it since.

Am I missing something fundamental here?

I've dumped some output from the Serial interface (http://pastebin.com/5axEvZTf) for easier understanding of what's going on.

Unfortunately I haven't been able to narrow down where my error is, so I've attached my entire code below.

I'm hoping for some advice on what causes this strange behavior :slight_smile:

/*
 * TODO: Something smarter for blink and on/off methods
 *       so we can have a veriable amount of colors to 
 *       adjust the difficulty
 */

const int r_out = 8;
const int g_out = 9;
const int b_out = 10;
const int wait = 200;

int stage;
int* sequence;

void setup() {
  // Set up serial and wait for it to be ready
  Serial.begin(9600);
  while(!Serial){
  ;
  }
  // Building a sequence of X elements
  sequence = buildSequence(10);
  delay(5000);
  stage = 1;
 
  pinMode(r_out, OUTPUT);
  pinMode(g_out, OUTPUT);
  pinMode(b_out, OUTPUT);
  //test(); 
}

void loop() {
  Serial.print("Starting stage ");
  Serial.println(stage);

  for(int i = 0;i<3;i++){
    allOff();
    delay(wait);
    allOn();
    delay(wait);
    allOff();
    delay(wait);
  }

  Serial.println("Starting sequence");

  for(int i = 0;i<stage;i++){
    Serial.print("Blinking on port ");
    Serial.println(sequence[i]);

    switch(sequence[i]){
      case r_out:
        rBlink();
        break;

      case g_out:
        gBlink();
        break;

      case b_out:
        bBlink();
        break;
    }
  }
  stage++;
  Serial.println("Done with stage. Starting next");
  Serial.println();
  delay(10000);
}

// Test to see if all LEDs work as they should
void test(){

  for(int i = 0;i<5;i++){
    rBlink();
    gBlink();
    bBlink();
  }

  
  for(int i = 0;i<5;i++){
  allOn();
  delay(500);
  allOff();
  delay(500);  
  }

}

void rBlink(){
  rOn();
  delay(wait);
  rOff();
  delay(wait);
}

void gBlink(){
  gOn();
  delay(wait);
  gOff();
  delay(wait);
}

void bBlink(){
  bOn();
  delay(wait);
  bOff();
  delay(wait);
}

void allBlink(){  
  allOn();
  delay(wait);
  allOff();
}


void rOn(){
  digitalWrite(r_out, HIGH);
}

void gOn(){
  digitalWrite(g_out, HIGH);
  
}

void bOn(){
  digitalWrite(b_out, HIGH);
  
}

void rOff(){
  digitalWrite(r_out, LOW);
}

void gOff(){
  digitalWrite(g_out, LOW);
}

void bOff(){
  digitalWrite(b_out, LOW);  
}


void allOff(){
  rOff();
  gOff();
  bOff();
}

void allOn(){
  rOn();
  gOn();
  bOn();
}

int* buildSequence(int len){
  int pins[] = {r_out, g_out, b_out};
  int sequence[len];

  for(int i = 0;i<len;i++){
    int num = random(0,3);
    sequence[i] = pins[num];
    Serial.print("Adding to sequence:");
    Serial.print(pins[num]);
    Serial.println();
  }

  Serial.println();

  return sequence;
}
int* buildSequence(int len){
  int pins[] = {r_out, g_out, b_out};
  int sequence[len];

  for(int i = 0;i<len;i++){
    int num = random(0,3);
    sequence[i] = pins[num];
    Serial.print("Adding to sequence:");
    Serial.print(pins[num]);
    Serial.println();
  }

  Serial.println();

  return sequence;
}

"sequence" is on the stack.
Returning a pointer to any entity that is soon going to be out of scope is a bad idea.
Don't do it.

Hi,
I have had a brief look at your sketch.
I wonder if you are aware that an array that is declared as 10 items, has its contents addressed as item 0, item 1 up to item 9.

https://www.arduino.cc/en/Reference/Array

Not sure if this might be your problem.

Tom.... :slight_smile:

The use of two variables called sequence is a little confusing and possibly dangerous as you might

Your problem is that you create a sequence array in buildSequence; that array will be allocated on the stack. When you leave the function, the array basically no longer exists and can be overwritten by anything.

One solution might be using dynamic memory like below.

int* buildSequence(int len) {
  int pins[] = {r_out, g_out, b_out};

  // if already allocated, free first
  if (sequence != NULL)
  {
    free(sequence);
  }
  
  // allcoate memory
  sequence = (int*)malloc(len * sizeof(int));
  // check result; bail out if allocation failed
  if (sequence == NULL)
  {
    // error; memory could not be allocated
    return NULL;
  }

  // whatever you were doing here
  for (int i = 0; i < len; i++) {
    int num = random(0, 3);
    sequence[i] = pins[num];
    Serial.print("Adding to sequence:");
    Serial.print(pins[num]);
    Serial.println();
  }

  Serial.println();

  return sequence;
}

Notes:

  • whenever you call this version of buildSequence, you need to check the returned value for null
  • you can also make use of realloc (no need to free first) and calloc instead of malloc (calloc will initialize the allocated memory)
  • not tested

//Edit
You need to initialize your sequence pointer in the beginning of your code to NULL

int* sequence = NULL;
...
...
void setup()

//Edit PS
PS: changed null to NULL while editing

You need to initialize your sequence pointer in the beginning of your code to NULL

No, you don't - crt0 will do it for you.

your function returns a pointer... to AWOL's point, it returns a pointer to an array that was just destroyed when it went out of scope.

/*
 * TODO: Something smarter for blink and on/off methods
 *       so we can have a veriable amount of colors to 
 *       adjust the difficulty
 */

yeah, you have quite the assortment of functions...

here are some hints to get you going, with some ideas to make your life easier (like the ENUM resource):

enum color {
  RED = 0, 
  GREEN, 
  BLUE, 
  ALL_COLORS
};

const char* theColor[] = {"RED", "GREEN", "BLUE", "ALL"};

const byte ledPin[] = { 8, 9, 10};

int gameSequence[10];

void setup() 
{
  Serial.begin(9600);
  for (byte i = 0; i < 3; i++)
  {
    pinMode(ledPin[i], OUTPUT);
  }
  blinkLeds(ALL_COLORS, 3, 100);
  buildSequence(gameSequence, sizeof(gameSequence)/sizeof(gameSequence[0]));
  for (int i = 0; i < sizeof(gameSequence)/sizeof(gameSequence[0]); i++)
  {
    //Serial.print(gameSequence[i]);
    Serial.println(theColor[gameSequence[i]]);
  }
}
void loop() 
{
  
}

void blinkLeds(int myColor, int repeats, unsigned long holdTime)
{
  for (byte j = 0; j < repeats; j++)
  {
    for (byte i = 0; i < 3; i++)
    {
      if (myColor == ALL_COLORS) digitalWrite(ledPin[i], HIGH);
      else if (myColor == i) digitalWrite(ledPin[i], HIGH);
    }
    delay(holdTime);
      for (byte i = 0; i < 3; i++)
    {
      digitalWrite(ledPin[i], LOW);
    }
    delay(holdTime);
  }
}

void  buildSequence(int* array, size_t arraySize)
{
  for(int i = 0; i < arraySize; i++)
  { 
    array[i] = random(0,3);
    Serial.print("Adding to sequence:");
    Serial.println(array[i]);
  }
}

AWOL:
No, you don't - crt0 will do it for you.

So that will initialize all SRAM to zeroes?

Anything with global or static scope, if not explicitly set to any other value, will be set to zero (null, false) by crt0.

Thanks for your replies... I got it to work when I moved sequence to the global scope!

I think my confusion is from other programming languages where multiple variables can have same name, but live in diffrent scopes (e.g. JavaScript)....

Thank a lot!

EsbenBoye:
Thanks for your replies... I got it to work when I moved sequence to the global scope!

I think my confusion is from other programming languages where multiple variables can have same name, but live in diffrent scopes (e.g. JavaScript)....

Thank a lot!

Same as C++... multiple variables can have the same name in different scopes. You bumped into the issue of using one in GLOBAL scope with another of the same name local to a function... and that comes with its complications, to say the least!