Running out of memory when using many if statements

I’m working on a code that read user message then check what letter is it at now then it make copy of that letter to be displayed on LED matrix
my problem is when I use many if statements I run out of memory

the problem is in this->copy_letter(letter_xxx); when it’s called many times it consumes memory so fast
is there a way around it ?

the full code

#include "Animate_LED_matrix.h"
#include "user_letters.h"
#include "user_custom_letters.h"
//#define DEBUG

Animate_LED_matrix::Animate_LED_matrix(char local_rows[9],char local_cols[9]){
//#ifdef DEBUG
//  Serial.begin(9600);
//#endif  

//copy cols&rows pins numbers from user array to our local copy
  for(int i=0; local_rows[i]; ++i){
    this->rows[i]=local_rows[i];
    ++this->num_of_rows;
  }
  for(int i=0; local_cols[i]; ++i){
    this->cols[i]=local_cols[i];
    ++this->num_of_cols;    
  }

// Set rows and cols pins as output
  for(int i=0; this->rows[i]; ++i){
    pinMode(this->rows[i],OUTPUT);
    this->turn_off_everything();
  }

  for(int i=0; this->cols[i]; ++i){
    pinMode(this->cols[i],OUTPUT);
    this->turn_off_everything();
  }

}

void Animate_LED_matrix::turn_off_everything(){
  for(int i=0; rows[i]; ++i){
    digitalWrite(rows[i],HIGH);
    }
  for(int i=0; cols[i]; ++i){
    digitalWrite(cols[i],LOW);
    }    
 }
  
void Animate_LED_matrix::turn_on_everything(){
  for(int i=0; rows[i]; ++i){
    digitalWrite(rows[i],LOW);
  }
  for(int i=0; cols[i]; ++i){
    digitalWrite(cols[i],HIGH);
  }    
}

void Animate_LED_matrix::copy_letter(char letter_to_copy[8][8]){
  for(int i=0; i<this->num_of_cols; ++i){
    for(int x=0; x<this->num_of_rows; ++x){
      if(this->get_next_letter==true){
        this->next_letter_to_print[x][i]=letter_to_copy[x][i];
      }else{
        this->letter_to_print[x][i]=letter_to_copy[x][i];
      }
    }
  }  
}

void Animate_LED_matrix::get_letter(char letter_to_get){
    if(letter_to_get=='a'){this->copy_letter(letter_a);}
    if(letter_to_get=='b'){this->copy_letter(letter_b);}
    if(letter_to_get=='c'){this->copy_letter(letter_c);}
    if(letter_to_get=='d'){this->copy_letter(letter_d);}
    if(letter_to_get=='e'){this->copy_letter(letter_e);}
    if(letter_to_get=='f'){this->copy_letter(letter_f);}
    if(letter_to_get=='g'){this->copy_letter(letter_g);}
    if(letter_to_get=='h'){this->copy_letter(letter_h);}
    if(letter_to_get=='i'){this->copy_letter(letter_i);}
    if(letter_to_get=='j'){this->copy_letter(letter_j);}
    if(letter_to_get=='k'){this->copy_letter(letter_k);}
    if(letter_to_get=='l'){this->copy_letter(letter_l);}
    if(letter_to_get=='m'){this->copy_letter(letter_m);}
    if(letter_to_get=='n'){this->copy_letter(letter_n);}
    if(letter_to_get=='o'){this->copy_letter(letter_o);}
    if(letter_to_get=='p'){this->copy_letter(letter_p);}
    if(letter_to_get=='q'){this->copy_letter(letter_q);}
    if(letter_to_get=='r'){this->copy_letter(letter_r);}
    if(letter_to_get=='s'){this->copy_letter(letter_s);}
    if(letter_to_get=='t'){this->copy_letter(letter_t);}
    if(letter_to_get=='u'){this->copy_letter(letter_u);}
    if(letter_to_get=='v'){this->copy_letter(letter_v);}
    if(letter_to_get=='w'){this->copy_letter(letter_w);}
    if(letter_to_get=='x'){this->copy_letter(letter_x);}
}

void Animate_LED_matrix::parse_msg(int index){
  char local_current_letter;
  bool is_symbol=false;
  //String symbol;
  if(index < this->user_msg.length()){
    char local_current_letter=this->user_msg.charAt(index);
    //here it checks if it's start of custom character 
      if(local_current_letter== "&" ){
        is_symbol=true;
        ++index;
        if(!this->get_next_letter) ++this->current_letter;
      }else{
          if(this->get_next_letter){
            this->get_letter(local_current_letter);
          }else{
            if(local_current_letter != this->user_last_letter){
              this->get_letter(local_current_letter);
              this->user_last_letter=local_current_letter;
            }
          }
      }
    
  }
}

void Animate_LED_matrix::shift_original_symbol(){
  char start_point=this->current_base;
  char current_col_of_current_letter=this->current_base;
  //copy the same column to all rows 
  for(char i=0; i<this->num_of_cols; ++i){
    for(char x=0; x<this->num_of_rows; ++x){
      if(current_col_of_current_letter >= 8){
        this->shifted_symbol[x][i]=this->next_letter_to_print[x][start_point-8];  
      }else{
        this->shifted_symbol[x][i]=this->letter_to_print[x][start_point];  
      }
    } // end row loop
    ++start_point;
    ++current_col_of_current_letter;
  } // end column loop
}  

void Animate_LED_matrix::check_cols_active_in_all(){
  bool is_active=false;
  for(char i=0; i<this->num_of_cols; ++i){
    for(char x=0; x<this->num_of_rows; ++x){
      if(this->shifted_symbol[x][i]){
        is_active=true;
      }else{
        is_active=false;
        break;
      }
    }
    if(is_active){
      this->which_col_active_in_all[i]=1;
    }
  }
  for(char i=0; i<this->num_of_cols; ++i){
    if(this->which_col_active_in_all[i]){
      for(char x=0; x<this->num_of_rows; ++x){
        this->shifted_symbol[x][i]=0;
      }
    }
  }
}
  
void Animate_LED_matrix::turn_on_cols_active_in_all(){
  this->check_cols_active_in_all();
  for(char i=0; rows[i]; ++i){
    digitalWrite(rows[i],LOW);
  }
  
  for(char i=0; cols[i]; ++i){
    if(this->which_col_active_in_all[i]){
      digitalWrite(cols[i],HIGH);
    }else{
      continue;  
    }
  }

  delay(this->global_delay);
}

void Animate_LED_matrix::check_cols_have_2_dots_turned_on_on_seris(){
  char num_of_dots_active=0;
  for(char i=0; i<this->num_of_cols; ++i){
    for(char x=0; x<this->num_of_rows; ++x){
      if(num_of_dots_active < 2){
        if(this->shifted_symbol[x][i]){
          ++num_of_dots_active;
        }  
      }else{
        break;
      }
    }
    if(num_of_dots_active>1){
      this->which_col_have_2_dots_turned_on_on_seris[i]=1;
    }
  }
}
  
  
void Animate_LED_matrix::turn_on_cols_have_2_dots_turned_on_on_seris(){
  this->check_cols_have_2_dots_turned_on_on_seris();

  for(char i=0; i<8; ++i){
    if(which_col_have_2_dots_turned_on_on_seris[i]){
      for(char x=0; rows[x]; ++x){
        if(this->shifted_symbol[x][i]){
          digitalWrite(rows[x],LOW);
        }
      }
    digitalWrite(cols[i],HIGH);
    delay(this->global_delay);
    this->turn_off_everything();
    }
  }

  for(char i=0; i<num_of_cols; ++i){
    if(this->which_col_have_2_dots_turned_on_on_seris[i]){
      for(char x=0; x<num_of_rows; ++x){
        this->shifted_symbol[x][i]=0;
      }
    }
  }
}
  
void Animate_LED_matrix::turn_on_cols_have_sperated_dots_turned_on(){
  for(char i=0; cols[i]; ++i){
    for(char x=0; rows[x]; ++x){
      if(this->shifted_symbol[x][i]){
        digitalWrite(rows[x],LOW);
        digitalWrite(cols[i],HIGH);
      }
    }
  }
  delay(this->global_delay);
  this->turn_off_everything();
}
  
  
void Animate_LED_matrix::start_animation(){
  this->shift_original_symbol();
  

  this->turn_on_cols_active_in_all();
  this->turn_off_everything();

     
  this->turn_on_cols_have_2_dots_turned_on_on_seris();
  this->turn_off_everything();

  this->turn_on_cols_have_sperated_dots_turned_on();
}
  
void Animate_LED_matrix::reset_everything(){
  for(char i=0; i<8; ++i){
    this->which_col_active_in_all[i]=0;
    this->which_col_have_2_dots_turned_on_on_seris[i]=0;
  }
  if(this->current_base==8){
    this->current_base=0;
    if(this->current_letter+1 < this->user_msg.length()){
      this->current_letter+=1;
    }else if(this->current_letter+1 >= this->user_msg.length()){
      this->current_letter=0;
    }
    if(this->current_letter+2 <= this->user_msg.length()){
      this->is_there_next_letter=true;
    }else if(this->current_letter+2 > this->user_msg.length()){
      this->is_there_next_letter=false;
    }
  }  
}

void Animate_LED_matrix::loop_animation() {
  if(this->current_letter == this->user_msg.length()-1){
    this->get_next_letter=true;
    this->parse_msg(0);
    this->get_next_letter=false;
  }else if(this->current_letter < this->user_msg.length()-1){
    this->parse_msg(this->current_letter);
    this->get_next_letter=true;
    this->parse_msg((this->is_there_next_letter? this->current_letter+1 : 0));
    this->get_next_letter=false;
  }

//repeat each animation n of times 
  int counter=0;
  start:
  this->start_animation();
  delay(1);
  if(counter<10){
    ++counter;
    goto start;
  }
  
#ifdef DEBUG
  Serial.println("finished animation");
#endif     
  this->turn_off_everything();
  ++this->current_base;
  this->reset_everything();
}
  if (letter_to_get == 'a')
  {
    this->copy_letter(letter_a);
  }

As you have noted there are numerous sections of code like this. It seems to me that you could use the ASCII value of letter_to_get as an index into an array of characters to remove the need for multiple tests.

UKHeliBob:

  if (letter_to_get == 'a')

{
   this->copy_letter(letter_a);
 }




As you have noted there are numerous sections of code like this. It seems to me that you could use the ASCII value of letter_to_get as an index into an array of characters to remove the need for multiple tests.

I guess this won't be memory friendly as the job of that function is to make copy_letter function copy the corresponding letter which is an array into another array

char letter_a[8][8]={{0,0,0,0,0,0,0,0},
                     {0,0,1,1,1,1,0,0},
                     {0,1,0,0,0,0,1,0},
                     {0,1,0,0,0,0,1,0},
                     {0,1,0,0,0,0,1,0},
                     {0,1,1,1,1,1,1,0},
                     {0,1,0,0,0,0,1,0},
                     {0,1,0,0,0,0,1,0} };

I guess this won't be memory friendly

It certainly won't

You could use the bits of a byte to hold each row of data.

UKHeliBob:
It certainly won't

You could use the bits of a byte to hold each row of data.

so it should be something like that char *(letters)[8]={letter_a,letter_b......,letter_z};

when I call it

copy_letter(*(letters)[letter_to_get]);

I was think more of each letter being declared like this

char letter_a[] =
{
  0b00000000,
  0b00111100,
  0b01000010,
  0b01000010,
  0b01000010,
  0b01111110,
  0b01000010,
  0b01000010
}

8 bytes per letter instead of 64 bytes per letter.

Combine this with using the ASCII value of the letter as an index to a 2 dimensional array of letters defined as above and the code would be vastly reduced in size.

UKHeliBob:
I was think more of each letter being declared like this

char letter_a[] =

{
  0b00000000,
  0b00111100,
  0b01000010,
  0b01000010,
  0b01000010,
  0b01111110,
  0b01000010,
  0b01000010
}



8 bytes per letter instead of 64 bytes per letter. 

Combine this with using the ASCII value of the letter as an index to a 2 dimensional array of letters defined as above and the code would be vastly reduced in size.

So currently I've done

char letter_a[8]={   0b00000000,
                     0b00111100,
                     0b01000010,
                     0b01000010,
                     0b01000010,
                     0b01111110,
                     0b01000010,
                     0b01000010 };

char letter_b[8]={   0b00000000,
                     0b01111100,
                     0b01000010,
                     0b01000010,
                     0b01111100,
                     0b01000010,
                     0b01000010,
                     0b01111100 };

char *(ascii_letters_symbols)[256];

ascii_letters_symbols['a']=letter_a;

ascii_letters_symbols['b']=letter_b;

this->copy_letter(ascii_letters_symbols[letter_to_get]);

it did reduced the momery usage (from 90 to 51) so is that good or I need to tweak it more ?

char *(ascii_letters_symbols)[256];What is it that you have got 256 of ?

UKHeliBob:
char *(ascii_letters_symbols)[256];What is it that you have got 256 of ?

I made the size of that array 256( i should have made it 128) so I can put each letter in its index which is corresponding to his ASCII code . for example letter a has ASCII value 97 so it will be stored in index 97 in the array then I access it like this->copy_letter(ascii_letters_symbols['a']);

How many different characters and/or symbols are you going to use in practice ?

Don’t store the non-printing characters if you don’t need them ASCII < ‘space’
You simply index in by the character minus ‘space’
Same for high value characters

The next step is to put your character bitmaps into FLASH (PROGMEM) along with the code - then RAM will only hold that single character that is being processed at that exact moment.