Possible Out of Bounds Array?

Hello!
I was making a model password door look using a soft pot with marked “faux buttons”, 2 LEDs and 3 pushbuttons. It works! Then, I made a new file, and changed the code a bit. In the new code, I want the Arduino to buzz at you if you enter the code wrong.

New Code:

#include <EEPROM.h>

char* secretCode = "1234";
char* code;
int position = 0;
boolean locked = true;
int note[] = {
  262, 262, 392, 523, 392, 523};
int duration[] = {
  100, 100, 100, 300, 100, 300};
int redPin = 9;
int greenPin = 8;
byte button = 2;
byte sButton = 3;
byte nButton = 4;
byte piezo = 11;
void setup()                    
{
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  //EEPROM.write(0, 0);
  DDRD = 0;
  Serial.begin(9600);
  Serial.println(sizeof(&secretCode));
  PORTD = 0x1c;
  loadCode();
  flash();
  updateOutputs();
}

void loop()                    
{
  char key = getKey();
  if (key == '*'  && ! locked)
  {
    // unlocked and * pressed so change code
    position = 0;
    getNewCode();
    updateOutputs();
  }
  if (key == '#')
  {
    locked = true;
    position = 0;
    updateOutputs();
    for(int i = 1; i <= 3; i++){
      tone(11, 250, 250);
      delay(250);
    }
  }
  if (key != 0)///
  {
    code[position] = key;
    position++;
    delay(200);
  }
  if(!digitalRead(button)) tone(11, 500);
  else noTone(11);
  if (position == 4)//
  {
    if(code == secretCode){
      locked = false;
      updateOutputs();
      for (int thisNote = 0; thisNote < 6; thisNote ++) {
        // play the next note:
        tone(11, note[thisNote]);
        // hold the note:
        delay(duration[thisNote]);
        // stop for the next note:
        noTone(11);
        delay(25);
      }
    }
    else tone(11, 100, 1000);
  }
  delay(100);
}

void updateOutputs()
{
  if (locked)
  {
    digitalWrite(redPin, HIGH);
    digitalWrite(greenPin, LOW);  
  }
  else
  {
    digitalWrite(redPin, LOW);
    digitalWrite(greenPin, HIGH); 
  }
}

void getNewCode()
{
  flash();
  for (int i = 0; i < 4; i++ )//
  {
    char key;
    key = getKey();
    while (key == 0)
    {
      key = getKey();
    }
    flash();
    secretCode[i] = key;
  }
  saveCode();
  flash();
  flash();
}

void loadCode()
{
  if (EEPROM.read(0) == 1)
  {
    for(int i = 0; i < 4; i++)//
      secretCode[i] = EEPROM.read(i+1);
  }
}

void saveCode()
{
  for(int i = 0; i < 4; i++){//
    EEPROM.write(i+1, secretCode[i]);
  }
  EEPROM.write(0, 1);
  tone(11, 500, 1000);  
}

void flash()
{
  digitalWrite(redPin, HIGH);
  digitalWrite(greenPin, HIGH);    
  delay(500);
  digitalWrite(redPin, LOW);
  digitalWrite(greenPin, LOW);    
}
char getKey(){
  if(!digitalRead(button)){
    int reading = analogRead(A0);
    reading = map(reading, 0, 1023, 0, 7);
    return reading + 48;
  }
  if(!digitalRead(sButton)) return '*';
  if(!digitalRead(nButton)) return '#';
  return 0;
}

When I press button on pin 2, the buzzer beeps, and the L LED on pin 13 turns on! I suspected that the code array has gone out of bounds. What can I do instead to fix this problem, and what happens if you write to an out of bounds array? It was supposed to write the user password input to a char array “code”, and compare to secretCode when there are 4 characters in the code array. My old code works fine, but if you type the wrong 4 digit code, nothing happens. Out of Bounds means that I am accessing past the end of the array. Compiler doesn’t check for that.

Old code:

// Project 27 Keypad door lock
#include <EEPROM.h>

char* secretCode = "1234";
int position = 0;
boolean locked = true;
int note[] = {
  262, 262, 392, 523, 392, 523};
int duration[] = {
  100, 100, 100, 300, 100, 300};
int redPin = 9;
int greenPin = 8;
byte button = 2;
byte sButton = 3;
byte nButton = 4;
byte piezo = 11;
void setup()                    
{
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);

  DDRD = 0;
  Serial.begin(9600);
  Serial.println(sizeof(secretCode));
  PORTD = 0x1c;
  loadCode();
  flash();
  updateOutputs();
}

void loop()                    
{
  char key = getKey();
  if (key == '*'  && ! locked)
  {
    // unlocked and * pressed so change code
    position = 0;
    getNewCode();
    updateOutputs();
    tone(11, 500, 1000);
  }
  if (key == '#')
  {
    locked = true;
    position = 0;
    updateOutputs();
    for(int i = 1; i <= 3; i++){
      tone(11, 250, 250);
      delay(250);
    }
  }
  if (key == secretCode[position])
  {
    position ++;
  }
  if(!digitalRead(button)) tone(11, 500);
  else noTone(11);
  if (position == 4)//
  {
    locked = false;
    updateOutputs();
    for (int thisNote = 0; thisNote < 6; thisNote ++) {
      // play the next note:
      tone(11, note[thisNote]);
      // hold the note:
      delay(duration[thisNote]);
      // stop for the next note:
      noTone(11);
      delay(25);
    }
  }
  delay(100);
}

void updateOutputs()
{
  if (locked)
  {
    digitalWrite(redPin, HIGH);
    digitalWrite(greenPin, LOW);  
  }
  else
  {
    digitalWrite(redPin, LOW);
    digitalWrite(greenPin, HIGH); 
  }
}

void getNewCode()
{
  flash();
  for (int i = 0; i < 4; i++ )//
  {
    char key;
    key = getKey();
    while (key == 0)
    {
      key = getKey();
    }
    flash();
    secretCode[i] = key;
  }
  saveCode();
  flash();
  flash();
}

void loadCode()
{
  if (EEPROM.read(0) == 1)
  {
    for(int i = 0; i < 4; i++)//
      secretCode[i] = EEPROM.read(i+1);
  }
}

void saveCode()
{
  for(int i = 0; i < 4; i++){//
    EEPROM.write(i+1, secretCode[i]);
  }
  EEPROM.write(0, 1);  
}

void flash()
{
  digitalWrite(redPin, HIGH);
  digitalWrite(greenPin, HIGH);    
  delay(500);
  digitalWrite(redPin, LOW);
  digitalWrite(greenPin, LOW);    
}
char getKey(){
  if(!digitalRead(button)){
    int reading = analogRead(A0);
    reading = map(reading, 0, 1023, 0, 7);
    return reading + 48;
  }
  if(!digitalRead(sButton)) return '*';
  if(!digitalRead(nButton)) return '#';
  return 0;
}

My next step is to be able to create a password of any length, and to make the Arduino go to sleep in you enter the wrong password 3 times, but I have to fix this problem first. Also, I printed the sizeof(secretCode) to the Serial Monitor, but it returns 2! I thought that it should return 4! Why is that? This is a modified version of http://www.arduinoevilgenius.com/projects Keypad Door Lock using a soft potentiometer. Any help is appreciated!

char* secretCode is a char pointer that points to the char string "1234" somewhere in RAM. secretCode only holds the address of the character string and the address only takes up two bytes.

Try doing sizeOf(*secretCode) instead.

Try doing sizeOf(*secretCode) instead.

No, do "strlen (secretCode);"

Should I change "char* code" to "char code[5]" instead? I will try later when I have time.

If you take the sizeof what a char pointer points to, you just get 1.

How many bytes can char* code; store? I didn't give it a value, so is it legit to insert values into it afterward, like what I did (code[position] = key;)?

SunnyBoy stopped responding. This reply seemed to have been moved from "Serial.read crazy results". We are just adding pointless replies now. One question: can I declare a char* datatype like char* code; without giving it a value, then add values into it, such as code[position] = '2'; ? I had some problems: Arduino Forum

No you can't. I suggest you Google for an introduction to C string handling.

This is wrong too:

    if(code == secretCode){

You are comparing addresses not contents.

How many bytes can char* code; store?

As many as you dare, which should be zero, until "code" points to some memory.

Please don't hijack other threads.

I modified my code to this:

#include <MomentaryButton.h>
#include <Easy.h>
#include <avr/sleep.h>
#include <avr/power.h>
// Project 27 Keypad door lock
#include <EEPROM.h>
MomentaryButton button(2);
MomentaryButton sButton(3);
MomentaryButton nButton(4);
Song alarm(11);
String secretCode = "1234";
String code = "";
int position = 0;
boolean locked = true;
int note[] = {
  262, 262, 392, 523, 392, 523};
int duration[] = {
  100, 100, 100, 300, 100, 300};
int redPin = 9;
int greenPin = 8;
byte piezo = 11;
byte tries = 0;
boolean playing = 1;
void setup()                    
{
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  DDRD = 0;
  PORTD = 0x1c;
  loadCode();
  flash();
  updateOutputs();
  button.setup();
  sButton.setup();
  nButton.setup();
}

void loop()                    
{
  char key = getKey();
  if (key == '*'  && ! locked)
  {
    // unlocked and * pressed so change code
    position = 0;
    getNewCode();
    updateOutputs();
  }
  if (key == '#')
  {
    locked = true;
    playing = 1;
    code = "";
    position = 0;
    updateOutputs();
    for(int i = 1; i <= 3; i++){
      tone(11, 250, 250);
      delay(250);
    }
  }
  if (key >= '0' && key <= '9')///
  {
    code += (char)key;
    position++;
  }
  if(!digitalRead(2)) tone(11, 500);
  else noTone(11);
  //if (position == 4)//
  //{
  if(code == secretCode && position == 4){
    locked = false;
    tries = 0;
    updateOutputs();
    for (int thisNote = 0; thisNote < 6 && playing; thisNote ++) {
      // play the next note:
      tone(11, note[thisNote]);
      // hold the note:
      delay(duration[thisNote]);
      // stop for the next note:
      noTone(11);
      delay(25);
    }
    playing = 0;
  }
  else if (position == 4 && code != secretCode){
    noTone(11);
    alarm.siren();
    alarm.siren();
    noTone(11);
    position = 0;
    code = "";
    tries++;
  }
  if(tries >= 3){
    alarm.ambulance();
    alarm.ambulance();
    noTone(11);
    sleep();
  }
  //}
}

void updateOutputs()
{
  if (locked)
  {
    digitalWrite(redPin, HIGH);
    digitalWrite(greenPin, LOW);  
  }
  else
  {
    digitalWrite(redPin, LOW);
    digitalWrite(greenPin, HIGH); 
  }
}

void getNewCode()
{
  flash();
  for (int i = 0; i < 4; i++ )//
  {
    char key;
    key = getKey();
    while (key == 0)
    {
      key = getKey();
    }
    flash();
    secretCode[i] = key;
  }
  saveCode();
  flash();
  flash();
}

void loadCode()
{
  if (EEPROM.read(0) == 1)
  {
    for(int i = 0; i < 4; i++)//
      secretCode[i] = EEPROM.read(i+1);
  }
}

void saveCode()
{
  for(int i = 0; i < 4; i++){//
    EEPROM.write(i+1, secretCode[i]);
  }
  EEPROM.write(0, 1);
  tone(11, 500, 1000);  
}

void flash()
{
  digitalWrite(redPin, HIGH);
  digitalWrite(greenPin, HIGH);    
  delay(500);
  digitalWrite(redPin, LOW);
  digitalWrite(greenPin, LOW);    
}
char getKey(){
  button.check();
  sButton.check();
  nButton.check();
  if(button.wasClicked()){
    int reading = analogRead(A0);
    reading = map(reading, 0, 1023, 0, 7);
    return reading + 48;
  }
  if(sButton.wasClicked()) return '*';
  if(nButton.wasClicked()) return '#';
  return 0;
}
void sleep(){
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
  DDRD = 0;
  DDRB = 0;
  PORTD = 0;
  PORTB = 0;
  sleep_enable();
  power_adc_disable();
  power_spi_disable();
  power_timer0_disable();
  power_timer1_disable();
  power_timer2_disable();
  power_twi_disable();
  MCUCR = _BV (BODS) | _BV (BODSE);
  MCUCR = _BV (BODS);
  sleep_mode();
}

I have almost accomplished this project! It will shut itself off (go to sleep until reset) if you enter the wrong code 3 times. A nice addition could be a solenoid. Some modifications can still be made.

String secretCode = "1234";
String code = "";

Why? With such short collections of characters, char arrays and byte indices are so easy.

With such short collections of characters, char arrays and byte indices are so easy.

Next, I might change it so that you can change the code externally, and it can be 4 to 10 characters long. Now, I have another question: why does sizeof(secretCode) return 7? Too bad strlen only works with char arrays.

Now, I have another question: why does sizeof(secretCode) return 7?

Because "secretCode" is a String.

protected:
	char *buffer;	        // the actual char array
	unsigned int capacity;  // the array length minus one (for the '\0')
	unsigned int len;       // the String length (not counting the '\0')
	unsigned char flags;    // unused, for future features

2 + 2 + 2 + 1 = 7