0

I wrote an app to recreate the matrix digital rain of the movie. It works ok if I set N_DROPS to low number (5). If I set it to (10), the characters start to flicker and if I set it to 15, I get a segfault. I tried to you valgrind but it seems that I could not install it properly on my MacOS 11.6.1. What is the origin of the problem, I could I diagnose it with print statements and how can I solve it?

Here is the code:

/*matrix_digital_rain.c*/

#include <curses.h>
#include <unistd.h>
#include <locale.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include "set_characters.h"
#include "hyperparameters.h"
#include "functions.h"

int main() {
  srand((unsigned) time(NULL));   // Initialization, should only be called once.
  setlocale(LC_ALL, "");
  int max_y = 0, max_x = 0;
  Drop_init_vals drop_init_vals_array[N_DROPS] ;

  for (int drop_num = 0; drop_num < N_DROPS; drop_num++){

    drop_init_vals_array[drop_num] = drop_init_vals_array_to_zero(drop_init_vals_array[drop_num]);
    drop_init_vals_array[drop_num].rand_iter_start = rand() % ITER_START_RANGE;
  } 

  int iter = 0;
 
  initscr();
  noecho();
  curs_set(FALSE);
  start_color();
  init_color(CUSTOM_GREEN1, 90, 280, 90);
  init_color(CUSTOM_GREEN2, 100, 500, 100);
  init_color(CUSTOM_GREEN3, 100, 900, 100);
  init_color(COLOR_BLACK, 0, 0, 0);

  char char_set[DIM_1_ARRAY_STRING][BYTES_PER_CHAR] = {SET_CHAR};
  char str_display[DIM_0_ARRAY_STRING][DIM_1_ARRAY_STRING][BYTES_PER_CHAR];
  for (int i = 0; i<DIM_0_ARRAY_STRING; i++){
    for (int j = 0; j<DIM_1_ARRAY_STRING; j++){
      strcpy(str_display[i][j], char_set[rand() % N_COMMAS]);
    }
  }

  while(1) 
  {
    getmaxyx(stdscr, max_y, max_x);
 
    clear();

    for (int drop_num = 0; drop_num<N_DROPS; drop_num++){

      if (iter % ITER_REFRESH == drop_init_vals_array[drop_num].rand_iter_start){
        drop_init_vals_array[drop_num].n_dim_str = drop_num;
        drop_init_vals_array[drop_num].x1 = rand() % X1_RANGE;
        drop_init_vals_array[drop_num].n_string = 20 + rand() % N_STRING_RANGE;
        drop_init_vals_array[drop_num].iter_init = iter;
        drop_init_vals_array[drop_num].rand_iter_start_bool = 1;
      }

      if(drop_init_vals_array[drop_num].rand_iter_start_bool == 1){
        print_n_string_from_string_array_struct(
          drop_init_vals_array[drop_num],
          str_display,
          iter
        );
        if (iter == drop_init_vals_array[drop_num].iter_init + ITER_REFRESH){
          drop_init_vals_array[drop_num].rand_iter_start_bool = 0;
        }
      }
    }

    iter++;

    refresh();
    usleep(DELAY);
 
  }
  attron(COLOR_PAIR(1));
  attron(COLOR_PAIR(2));
  attron(COLOR_PAIR(3));
 
  endwin();
  refresh();
  use_default_colors();
}
/*functions.h*/

#ifndef FUNCTIONS_H
#define FUNCTIONS_H

typedef struct {
  int x1, y1, n_string, n_dim_str, iter_init, rand_iter_start, rand_iter_start_bool; 
} Drop_init_vals ;


void print_n_string_from_string_array_struct(Drop_init_vals drop_init_vals, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR], int iter);

Drop_init_vals random_drop_init_vals(Drop_init_vals drop_init_vals);
Drop_init_vals drop_init_vals_to_zero(void);

void print_GREEN1(int y1, int x1, int i, int n_string, int n_dim_str, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR]);
void print_GREEN2(int y1, int x1, int i, int n_string, int n_dim_str, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR]);
void print_GREEN3(int y1, int x1, int i, int n_string, int n_dim_str, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR]);

Drop_init_vals drop_init_vals_array_to_zero(Drop_init_vals drop_init_vals);

#endif
/*functions.c*/

#include "hyperparameters.h"
#include "functions.h"
#include <curses.h>
#include <time.h>
#include <stdlib.h>


void print_GREEN1(int y1, int x1, int i, int n_string, int n_dim_str, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR])
{
  init_pair(1, CUSTOM_GREEN1, COLOR_BLACK);
  attron(COLOR_PAIR(1));
  mvprintw(y1+i-n_string, x1, str_display[n_dim_str][i]);
}

void print_GREEN2(int y1, int x1, int i, int n_string, int n_dim_str, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR])
{
  init_pair(2, CUSTOM_GREEN2, COLOR_BLACK);
  attron(COLOR_PAIR(2));
  mvprintw(y1+i-n_string, x1, str_display[n_dim_str][i]);
}

void print_GREEN3(int y1, int x1, int i, int n_string, int n_dim_str, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR])
{
  init_pair(3, CUSTOM_GREEN3, COLOR_BLACK);
  attron(COLOR_PAIR(3));
  mvprintw(y1+i-n_string, x1, str_display[n_dim_str][i]);
}

Drop_init_vals drop_init_vals_to_zero(void)
{
  Drop_init_vals drop_init_vals;
  drop_init_vals.y1 = 0;
  drop_init_vals.x1 = 0;
  drop_init_vals.n_string = 0;
  drop_init_vals.iter_init = 0;
  drop_init_vals.n_dim_str = 0;

  return drop_init_vals;
}

Drop_init_vals random_drop_init_vals(Drop_init_vals drop_init_vals)
{
  
  drop_init_vals.x1 = rand() % X1_RANGE;
  drop_init_vals.n_string = 20 + rand() % N_STRING_RANGE;
  return drop_init_vals;
}

void print_n_string_from_string_array_struct(Drop_init_vals drop_init_vals, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR], int iter)
{
  int y1 = drop_init_vals.y1;
  int x1 = drop_init_vals.x1;
  int n_string = drop_init_vals.n_string;
  int n_dim_str = drop_init_vals.n_dim_str;
  int y_start = iter - drop_init_vals.iter_init;


  int count = 0;
  for (int i=y_start; i<y_start+n_string; i++)
  {
    if (count == 0 || count == 1){
      print_GREEN1(y1, x1, i, n_string, n_dim_str, &str_display[n_dim_str]);
    }
    else if (count == 2 || count == 3 || count == 4){
      print_GREEN2(y1, x1, i, n_string, n_dim_str, &str_display[n_dim_str]);
    }
    else{
      print_GREEN3(y1, x1, i, n_string, n_dim_str, &str_display[n_dim_str]);
    }
    count++;
  }
}


Drop_init_vals drop_init_vals_array_to_zero(Drop_init_vals drop_init_vals)
{

  for (int drop_num = 0; drop_num < N_DROPS; drop_num++){
    drop_init_vals.y1 = 0;
    drop_init_vals.x1 = 0;
    drop_init_vals.n_string = 0;
    drop_init_vals.iter_init = 0;
    drop_init_vals.n_dim_str = 0;
  }
  return drop_init_vals;
}
/*set_characters.h*/

#ifndef SET_CHARACTERS_H
#define SET_CHARACTERS_H

#define N_COMMAS 56

#define SET_CHAR "ㇰ", "ㇱ", "ㇲ","ㇳ","ㇴ","ㇵ","ㇶ","ㇷ","ㇸ","ㇹ","ㇺ","ㇻ","ㇼ","ㇽ","ㇾ", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "<", "=", ">", "T", "H","E", "M", "A", "T", "R", "I", "X", "Z", ":", "・", ".", "=", "*", "+", "-", "<", ">", "¦", "|", "#", "_"


#endif
/*hyperparameters.h*/

#ifndef HYPERPARAMETERS_H
#define HYPERPARAMETERS_H

#define DELAY 60000 //480000
#define CUSTOM_GREEN1 8
#define CUSTOM_GREEN2 9
#define CUSTOM_GREEN3 10
#define COLOR_BLACK 0
#define DIM_0_ARRAY_STRING 20
#define DIM_1_ARRAY_STRING 100
#define BYTES_PER_CHAR 5

#define LEN_STRING_DISPLAY 100 
#define MAX_Y 100 
#define MAX_X 100 
#define N_STRING_MAX 20
#define N_DROPS 5

#define Y1_RANGE 20
#define X1_RANGE 30
#define N_STRING_RANGE 5
#define Y_START_RANGE 15
#define ITER_REFRESH 80
#define ITER_START_RANGE 80


#endif
#makefile

CC = gcc 
CFLAGS = -O2 -Wextra -Wall -Wfloat-equal -Wundef -Wshadow -Wpointer-arith -Wcast-align -Wstrict-prototypes -Wstrict-overflow=5 -Wwrite-strings -Waggregate-return -Wcast-qual -Wswitch-default -Wswitch-enum -Wconversion -Wunreachable-code -pedantic -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition

BINC=matrix_digital_rain

allc: $(BINC) 

$(BINC): $(BINC).o functions.o
    $(CC) $(CFLAGS) -ggdb3 $(BINC).o functions.o -o $@ -lncurses

$(BINC).o: $(BINC).c set_characters.h hyperparameters.h set_characters.h
    $(CC) $(CFLAGS) -c $(BINC).c

functions.o: functions.c functions.h
    $(CC) $(CFLAGS) -c functions.c 

clean:
    $(RM) -rf $(BINC) *.dSYM *.o

runc: allc
    ./$(BINC)

EDIT

So as mentioned in a comment, I added -fsanitize=address,undefined to the compilation and got the following output:

make runc
gcc  -O2 -Wextra -Wall -Wfloat-equal -Wundef -Wshadow -Wpointer-arith -Wcast-align -Wstrict-prototypes -Wstrict-overflow=5 -Wwrite-strings -Waggregate-return -Wcast-qual -Wswitch-default -Wswitch-enum -Wconversion -Wunreachable-code -pedantic -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -c functions.
             ㇰ=en_US.UTF-8 2
               S.UTF-8      ㇰ
               -8           #
               CURITYSESSIONID=186a6
               YSESSIONID=186a6
               IONID=186a6  /
               =186a6       ㇺ
               6
               P_OPTIONS=--color=auto
               IONS=--color=autoAddressSanitizer:DEADLYSIGNAL
                                                             =================================================================
                                 ==37477==ERROR: AddressSanitizer: stack-overflow on address 0x7ffeeac8d253 (pc 0x000104fe2d90 bp 0x7ffeeac882e0 sp 0x7ffeeac882e0 T0)
                                                                             #0 0x104fe2d90 in __sanitizer::internal_strlen(char const*)+0x10 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x5dd90)
            #1 0x104fa7f75 in printf_common(void*, char const*, __va_list_tag*)+0x25 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x22f75)
                                                #2 0x104fa8a69 in wrap_vsnprintf+0x99 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x23a69)
                                                 #3 0x7fff40e9c161 in _nc_printf_string+0xba (libncurses.5.4.dylib:x86_64+0x1d161)
                                         #4 0x7fff40e93952 in vwprintw+0x13 (libncurses.5.4.dylib:x86_64+0x14952)
                        #5 0x7fff40e93abb in mvprintw+0xa7 (libncurses.5.4.dylib:x86_64+0x14abb)
       #6 0x104f76765 in print_n_string_from_string_array_struct+0x255 (matrix_digital_rain:x86_64+0x100003765)
                      #7 0x104f75e5b in main+0x74b (matrix_digital_rain:x86_64+0x100002e5b)
                                                                                               #8 0x7fff20506f3c in start+0x0 (libdyld.dylib:x86_64+0x15f3c)

                                                               SUMMARY: AddressSanitizer: stack-overflow (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x5dd90) in __sanitizer::internal_strlen(char const*)+0x10
                     ==37477==ABORTING
                                      make: *** [runc] Abort trap: 6

EDIT 2

I added the following to the compile -O0 -ggdb and got the following output:

 make runc
gcc  -O2 -Wextra -Wall -Wfloat-equal -Wundef -Wshadow -Wpointer-arith -Wcast-align -Wstrict-prototypes -Wstrict-overflow=5 -Wwrite-strings -Waggregate-return -Wcast-qual -Wswitch-default -Wswitch-enum -Wconversion -Wunreachable-code -pedantic -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -c functions.
2 f2
    =>0x1fffdca62250: f2 f2 f2 f2 f2[f2]f2 f2 f2 f2 f2 f2 f2 f2 f2 f2
                                                                       0x1fffdca62260: f2 f2 f2 f2 f2 f2 f2 f2 00 00 00 04 f3 f3 f3 f3
           0x1fffdca62270: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                                                                            0x1fffdca62280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                0x1fffdca62290: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                                                                                 0x1fffdca622a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                   Shadow byte legend (one shadow byte represents 8 application bytes):
                                                                                         Addressable:           00
                                                                                                                    Partially addressable: 01 02 03 04 05 06 07
                                     Heap left redzone:       fa
                                                                  Freed heap region:       fd
                                                                                               Stack left redzone:      f1
                                                                                                                            Stack mid redzone:       f2
                            Stack right redzone:     f3
                                                         Stack after return:      f5
                                                                                      Stack use after scope:   f8
                                                                                                                   Global redzone:          f9
                   Global init order:       f6
                                                Poisoned by user:        f7
                                                                             Container overflow:      fc
                                                                                                          Array cookie:            ac
          Intra object redzone:    bb
                                       ASan internal:           fe
                                                                    Left alloca redzone:     ca
                                                                                                 Right alloca redzone:    cb
                                                                                                                              Shadow gap:              cc
                            ==41647==ABORTING
                                             make: *** [runc] Abort trap: 6
                                                                           %
[@matrix_digital_rain]$
[@matrix_digital_rain]$

EDIT

I tried to implement the change suggested by @n. m. namely:

  • I checked if N_DROPS > DIM_0_ARRAY_STRING and made the program terminate if it is the case (lines 15-19 of script matrix_digital_rain.c)
  if (N_DROPS > DIM_0_ARRAY_STRING)
  {
    printf("error N_DROPS should be equal or lower than DIM_0_ARRAY_STRING");
    exit(EXIT_FAILURE);
  }
  • I did not increment twice str_display in print_GREENX and print_n_string_from_string_array_struct (in lines 64, 68 and 72 in script function.c)

There is no segfault anymore (which is a MAJOR improvement, many thanks to @n. m.) however, there is still the flickering of the characters. Does it have to do with the many different mvprintw statements?

Here is the full edited code:

/*matrix_digital_rain.c*/

#include <curses.h>
#include <unistd.h>
#include <locale.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include "set_characters.h"
#include "hyperparameters.h"
#include "functions.h"

int main() {

  if (N_DROPS > DIM_0_ARRAY_STRING)
  {
    printf("error N_DROPS should be equal or lower than DIM_0_ARRAY_STRING");
    exit(EXIT_FAILURE);
  }


  srand((unsigned) time(NULL));   // Initialization, should only be called once.
  setlocale(LC_ALL, "");
  int max_y = 0, max_x = 0;
  Drop_init_vals drop_init_vals_array[N_DROPS] ;

  for (int drop_num = 0; drop_num < N_DROPS; drop_num++){

    drop_init_vals_array[drop_num] = drop_init_vals_array_to_zero(drop_init_vals_array[drop_num]);
    drop_init_vals_array[drop_num].rand_iter_start = rand() % ITER_START_RANGE;
  } 

  int iter = 0;
 
  initscr();
  noecho();
  curs_set(FALSE);
  start_color();
  init_color(CUSTOM_GREEN1, 90, 280, 90);
  init_color(CUSTOM_GREEN2, 100, 500, 100);
  init_color(CUSTOM_GREEN3, 100, 900, 100);
  init_color(COLOR_BLACK, 0, 0, 0);

  char char_set[DIM_1_ARRAY_STRING][BYTES_PER_CHAR] = {SET_CHAR};
  char str_display[DIM_0_ARRAY_STRING][DIM_1_ARRAY_STRING][BYTES_PER_CHAR];
  for (int i = 0; i<DIM_0_ARRAY_STRING; i++){
    for (int j = 0; j<DIM_1_ARRAY_STRING; j++){
      strcpy(str_display[i][j], char_set[rand() % N_COMMAS]);
    }
  }

  while(1) 
  {
    getmaxyx(stdscr, max_y, max_x);
 
    clear();

    for (int drop_num = 0; drop_num<N_DROPS; drop_num++){

      if (iter % ITER_REFRESH == drop_init_vals_array[drop_num].rand_iter_start){
        drop_init_vals_array[drop_num].n_dim_str = drop_num;
        drop_init_vals_array[drop_num].x1 = rand() % X1_RANGE;
        drop_init_vals_array[drop_num].n_string = 20 + rand() % N_STRING_RANGE;
        drop_init_vals_array[drop_num].iter_init = iter;
        drop_init_vals_array[drop_num].rand_iter_start_bool = 1;
      }

      if(drop_init_vals_array[drop_num].rand_iter_start_bool == 1){
        print_n_string_from_string_array_struct(
          drop_init_vals_array[drop_num],
          str_display,
          iter
        );
        if (iter == drop_init_vals_array[drop_num].iter_init + ITER_REFRESH){
          drop_init_vals_array[drop_num].rand_iter_start_bool = 0;
        }
      }
    }

    iter++;

    refresh();
    usleep(DELAY);
 
  }
  attron(COLOR_PAIR(1));
  attron(COLOR_PAIR(2));
  attron(COLOR_PAIR(3));
 
  endwin();
  refresh();
  use_default_colors();
}
/*functions.h*/

#ifndef FUNCTIONS_H
#define FUNCTIONS_H

typedef struct {
  int x1, y1, n_string, n_dim_str, iter_init, rand_iter_start, rand_iter_start_bool; 
} Drop_init_vals ;


void print_n_string_from_string_array_struct(Drop_init_vals drop_init_vals, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR], int iter);

Drop_init_vals random_drop_init_vals(Drop_init_vals drop_init_vals);
Drop_init_vals drop_init_vals_to_zero(void);

void print_GREEN1(int y1, int x1, int i, int n_string, int n_dim_str, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR]);
void print_GREEN2(int y1, int x1, int i, int n_string, int n_dim_str, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR]);
void print_GREEN3(int y1, int x1, int i, int n_string, int n_dim_str, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR]);

Drop_init_vals drop_init_vals_array_to_zero(Drop_init_vals drop_init_vals);

#endif
/*functions.c*/

#include "hyperparameters.h"
#include "functions.h"
#include <curses.h>
#include <time.h>
#include <stdlib.h>


void print_GREEN1(int y1, int x1, int i, int n_string, int n_dim_str, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR])
{
  init_pair(1, CUSTOM_GREEN1, COLOR_BLACK);
  attron(COLOR_PAIR(1));
  mvprintw(y1+i-n_string, x1, str_display[n_dim_str][i]);
}

void print_GREEN2(int y1, int x1, int i, int n_string, int n_dim_str, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR])
{
  init_pair(2, CUSTOM_GREEN2, COLOR_BLACK);
  attron(COLOR_PAIR(2));
  mvprintw(y1+i-n_string, x1, str_display[n_dim_str][i]);
}

void print_GREEN3(int y1, int x1, int i, int n_string, int n_dim_str, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR])
{
  init_pair(3, CUSTOM_GREEN3, COLOR_BLACK);
  attron(COLOR_PAIR(3));
  mvprintw(y1+i-n_string, x1, str_display[n_dim_str][i]);
}

Drop_init_vals drop_init_vals_to_zero(void)
{
  Drop_init_vals drop_init_vals;
  drop_init_vals.y1 = 0;
  drop_init_vals.x1 = 0;
  drop_init_vals.n_string = 0;
  drop_init_vals.iter_init = 0;
  drop_init_vals.n_dim_str = 0;

  return drop_init_vals;
}

Drop_init_vals random_drop_init_vals(Drop_init_vals drop_init_vals)
{
  
  drop_init_vals.x1 = rand() % X1_RANGE;
  drop_init_vals.n_string = 20 + rand() % N_STRING_RANGE;
  return drop_init_vals;
}

void print_n_string_from_string_array_struct(Drop_init_vals drop_init_vals, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR], int iter)
{
  int y1 = drop_init_vals.y1;
  int x1 = drop_init_vals.x1;
  int n_string = drop_init_vals.n_string;
  int n_dim_str = drop_init_vals.n_dim_str;
  int y_start = iter - drop_init_vals.iter_init;


  int count = 0;
  for (int i=y_start; i<y_start+n_string; i++)
  {
    if (count == 0 || count == 1){
      //print_GREEN1(y1, x1, i, n_string, n_dim_str, &str_display[n_dim_str]);
      print_GREEN1(y1, x1, i, n_string, n_dim_str, str_display);
    }
    else if (count == 2 || count == 3 || count == 4){
      //print_GREEN2(y1, x1, i, n_string, n_dim_str, &str_display[n_dim_str]);
      print_GREEN2(y1, x1, i, n_string, n_dim_str, str_display);
    }
    else{
      //print_GREEN3(y1, x1, i, n_string, n_dim_str, &str_display[n_dim_str]);
      print_GREEN3(y1, x1, i, n_string, n_dim_str, str_display);
    }
    count++;
  }
}


Drop_init_vals drop_init_vals_array_to_zero(Drop_init_vals drop_init_vals)
{

  for (int drop_num = 0; drop_num < N_DROPS; drop_num++){
    drop_init_vals.y1 = 0;
    drop_init_vals.x1 = 0;
    drop_init_vals.n_string = 0;
    drop_init_vals.iter_init = 0;
    drop_init_vals.n_dim_str = 0;
  }
  return drop_init_vals;
}
/*set_characters.h*/

#ifndef SET_CHARACTERS_H
#define SET_CHARACTERS_H

#define N_COMMAS 56

#define SET_CHAR "ㇰ", "ㇱ", "ㇲ","ㇳ","ㇴ","ㇵ","ㇶ","ㇷ","ㇸ","ㇹ","ㇺ","ㇻ","ㇼ","ㇽ","ㇾ", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "<", "=", ">", "T", "H","E", "M", "A", "T", "R", "I", "X", "Z", ":", "・", ".", "=", "*", "+", "-", "<", ">", "¦", "|", "#", "_"


#endif
/*hyperparameters.h*/

#ifndef HYPERPARAMETERS_H
#define HYPERPARAMETERS_H

#define DELAY 60000 //480000
#define CUSTOM_GREEN1 8
#define CUSTOM_GREEN2 9
#define CUSTOM_GREEN3 10
#define COLOR_BLACK 0
#define DIM_0_ARRAY_STRING 30
#define DIM_1_ARRAY_STRING 100
#define BYTES_PER_CHAR 5

#define LEN_STRING_DISPLAY 100 
#define MAX_Y 100 
#define MAX_X 100 
#define N_STRING_MAX 20
#define N_DROPS 20

#define Y1_RANGE 20
#define X1_RANGE 50
#define N_STRING_RANGE 5
#define Y_START_RANGE 15
#define ITER_REFRESH 80
#define ITER_START_RANGE 80



#endif
#makefile

CC = gcc 
CFLAGS = -O2 -Wextra -Wall -Wfloat-equal -Wundef -Wshadow -Wpointer-arith -Wcast-align -Wstrict-prototypes -Wstrict-overflow=5 -Wwrite-strings -Waggregate-return -Wcast-qual -Wswitch-default -Wswitch-enum -Wconversion -Wunreachable-code -pedantic -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -fsanitize=address,undefined -O0 -ggdb

BINC=matrix_digital_rain

allc: $(BINC) 

$(BINC): $(BINC).o functions.o
    $(CC) $(CFLAGS) -ggdb3 $(BINC).o functions.o -o $@ -lncurses

$(BINC).o: $(BINC).c set_characters.h hyperparameters.h set_characters.h
    $(CC) $(CFLAGS) -c $(BINC).c

functions.o: functions.c functions.h
    $(CC) $(CFLAGS) -c functions.c 

clean:
    $(RM) -rf $(BINC) *.dSYM *.o

runc: allc
    ./$(BINC) 
#   ./$(BINC) >/dev/null
ecjb
  • 5,169
  • 12
  • 43
  • 79
  • 1
    This seems like a great time to learn how to [*debug*](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/) your programs. For example by using a [*debugger*](https://stackoverflow.com/questions/25385173/what-is-a-debugger-and-how-can-it-help-me-diagnose-problems) to catch the crash, and locate when and where in your code it happens. That will also give you the opportunity to examine variables and their values to make sure they're fine (or not). – Some programmer dude Apr 03 '23 at 08:51
  • This is not a code review site. Please post a minimal reproductible example. Also, show what you have already tried to debug your code. Valgrind can indeed be a pain to use on macOS. Use a Linux container or machine and use Valgrind. – Victor Apr 03 '23 at 08:52
  • Also, ,does your code build cleanly? There's no warnings? – Some programmer dude Apr 03 '23 at 08:54
  • Compile with `-fsanitize=address,undefined`. – n. m. could be an AI Apr 03 '23 at 08:55
  • Thank you for your comments @Someprogrammerdude dude. The code builds cleanly without warnings – ecjb Apr 03 '23 at 08:59
  • thanks for your comment @n.m. I added the line in the makefile and added the output in the edited question – ecjb Apr 03 '23 at 09:10
  • If you add `-O0 -ggdb`. you will know exactly at what line it breaks. You can also fire up `gdb` and set a breakpoint on `__asan::ReportGenericError`. (Be aware that your program will mess up gdb display, so you will need to figure out how to keep program display and gdb display separate). – n. m. could be an AI Apr 03 '23 at 09:22
  • many thanks for your comment @n.m. I add `-O0 -ggdb` to the makefile and copied the output in a second edit. But I have to say that I am still a little puzzled – ecjb Apr 03 '23 at 09:36
  • Your program messes up your display. Try running with `>/dev/null`. Better yet switch off calls to ncurses when the output is not a terminal (see `man isatty`). – n. m. could be an AI Apr 03 '23 at 09:48

2 Answers2

1

You call

print_GREEN1(y1, x1, i, n_string, n_dim_str, &str_display[n_dim_str]);

and inside print_GREEN1

mvprintw(y1+i-n_string, x1, str_display[n_dim_str][i]);

So you add n_dim_str to str_display twice, which overflows the array. You may want to try doing it just once.

Furthermore, your array size is DIM_0_ARRAY_STRING, and n_dim_str is limited by N_DROPS which is set independently. You probably should check that N_DROPS does not exceed DIM_0_ARRAY_STRING.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • Many thanks @n. m. Thanks to your answer which I implemented (with the code in the edited question), I could get rid of the segfault. Now the flickering of the characters remain. Do you havec a clue about this? More importantly, how did you spot the error of the over flow of the array which was for me the major error? Did you just read the code or did you debug it? and if yes how? – ecjb Apr 03 '23 at 15:55
  • Try `erase` instead of `clear`. – n. m. could be an AI Apr 03 '23 at 18:04
  • Awesome @n.m. many thanks! that removed the flickering. But now, I still get the following message now and then `functions.c:28:31: runtime error: index 101 out of bounds for type 'char [100][5] SUMMARY: UndefinedBehaviorSanitizer: undefine0-behavior functions.c:28:31` – ecjb Apr 03 '23 at 20:11
  • @ecjb I'm terribly sorry, but this is not an interactive course on debugging. You need to learn how to do it yourself. – n. m. could be an AI Apr 03 '23 at 20:14
  • ok. Fair enough. Many thanks for your help @n.m. – ecjb Apr 03 '23 at 20:20
  • 1
    I think I found the bug and posted it as an answer for completeness. Thanks again! – ecjb Apr 03 '23 at 21:07
0

The final bug was the the values of drop_init_vals_array[drop_num] where not reinitialized, which I added at the following to the line 73 of the script matrix_digital_rain.c:

drop_init_vals_array[drop_num] = drop_init_vals_array_to_zero(drop_init_vals_array[drop_num]);

Here is the final working code:

/*matrix_digital_rain.c*/

#include <curses.h>
#include <unistd.h>
#include <locale.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include "set_characters.h"
#include "hyperparameters.h"
#include "functions.h"
#include "test.h"

int main() {
  test_N_DROPS_more_than_DIM_0_ARRAY_STRING();


  srand((unsigned) time(NULL));   // Initialization, should only be called once.
  setlocale(LC_ALL, "");
  int max_y = 0, max_x = 0;
  Drop_init_vals drop_init_vals_array[N_DROPS] ;

  for (int drop_num = 0; drop_num < N_DROPS; drop_num++){

    drop_init_vals_array[drop_num] = drop_init_vals_array_to_zero(drop_init_vals_array[drop_num]);
    drop_init_vals_array[drop_num].rand_iter_start = rand() % ITER_START_RANGE;
  } 

  int iter = 0;
 
  initscr();
  noecho();
  curs_set(FALSE);
  start_color();
  init_color(CUSTOM_GREEN1, 90, 280, 90);
  init_color(CUSTOM_GREEN2, 100, 500, 100);
  init_color(CUSTOM_GREEN3, 100, 900, 100);
  init_color(COLOR_BLACK, 0, 0, 0);

  char char_set[DIM_1_ARRAY_STRING][BYTES_PER_CHAR] = {SET_CHAR};
  char str_display[DIM_0_ARRAY_STRING][DIM_1_ARRAY_STRING][BYTES_PER_CHAR];
  for (int i = 0; i<DIM_0_ARRAY_STRING; i++){
    for (int j = 0; j<DIM_1_ARRAY_STRING; j++){
      strcpy(str_display[i][j], char_set[rand() % N_COMMAS]);
    }
  }

  while(1) 
  {
    getmaxyx(stdscr, max_y, max_x);
 
    //clear();
    erase();

    for (int drop_num = 0; drop_num<N_DROPS; drop_num++){

      if (iter % ITER_REFRESH == drop_init_vals_array[drop_num].rand_iter_start){
        drop_init_vals_array[drop_num].n_dim_str = drop_num;
        drop_init_vals_array[drop_num].x1 = rand() % X1_RANGE;
        drop_init_vals_array[drop_num].n_string = 20 + rand() % N_STRING_RANGE;
        drop_init_vals_array[drop_num].iter_init = iter;
        drop_init_vals_array[drop_num].rand_iter_start_bool = 1;
      }

      if(drop_init_vals_array[drop_num].rand_iter_start_bool == 1){
        print_n_string_from_string_array_struct(
          drop_init_vals_array[drop_num],
          str_display,
          iter
        );
        if (iter == drop_init_vals_array[drop_num].iter_init + ITER_REFRESH){
          drop_init_vals_array[drop_num].rand_iter_start_bool = 0;
          drop_init_vals_array[drop_num] = drop_init_vals_array_to_zero(drop_init_vals_array[drop_num]);
        }
      }
    }

    iter++;

    refresh();
    usleep(DELAY);
 
  }
  attron(COLOR_PAIR(1));
  attron(COLOR_PAIR(2));
  attron(COLOR_PAIR(3));
 
  endwin();
  refresh();
  use_default_colors();
}
/*functions.h*/

#ifndef FUNCTIONS_H
#define FUNCTIONS_H

typedef struct {
  int x1, y1, n_string, n_dim_str, iter_init, rand_iter_start, rand_iter_start_bool; 
} Drop_init_vals ;


void print_n_string_from_string_array_struct(Drop_init_vals drop_init_vals, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR], int iter);

Drop_init_vals random_drop_init_vals(Drop_init_vals drop_init_vals);
Drop_init_vals drop_init_vals_to_zero(void);

void print_GREEN1(int y1, int x1, int i, int n_string, int n_dim_str, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR]);
void print_GREEN2(int y1, int x1, int i, int n_string, int n_dim_str, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR]);
void print_GREEN3(int y1, int x1, int i, int n_string, int n_dim_str, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR]);

Drop_init_vals drop_init_vals_array_to_zero(Drop_init_vals drop_init_vals);

#endif
/*functions.c*/

#include "hyperparameters.h"
#include "functions.h"
#include "test.h"
#include <curses.h>
#include <time.h>
#include <stdlib.h>


void print_GREEN1(int y1, int x1, int i, int n_string, int n_dim_str, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR])
{
  n_dim_str_morethan_DIM_0_ARRAY_STRING(n_dim_str);
  i_morethan_DIM_1_ARRAY_STRING(i);

  init_pair(1, CUSTOM_GREEN1, COLOR_BLACK);
  attron(COLOR_PAIR(1));
  mvprintw(y1+i-n_string, x1, str_display[n_dim_str][i]);
}

void print_GREEN2(int y1, int x1, int i, int n_string, int n_dim_str, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR])
{

  n_dim_str_morethan_DIM_0_ARRAY_STRING(n_dim_str);
  i_morethan_DIM_1_ARRAY_STRING(i);


  init_pair(2, CUSTOM_GREEN2, COLOR_BLACK);
  attron(COLOR_PAIR(2));
  mvprintw(y1+i-n_string, x1, str_display[n_dim_str][i]);
}

void print_GREEN3(int y1, int x1, int i, int n_string, int n_dim_str, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR])
{
  n_dim_str_morethan_DIM_0_ARRAY_STRING(n_dim_str);
  i_morethan_DIM_1_ARRAY_STRING(i);


  init_pair(3, CUSTOM_GREEN3, COLOR_BLACK);
  attron(COLOR_PAIR(3));
  mvprintw(y1+i-n_string, x1, str_display[n_dim_str][i]);
}

Drop_init_vals random_drop_init_vals(Drop_init_vals drop_init_vals)
{
  
  drop_init_vals.x1 = rand() % X1_RANGE;
  drop_init_vals.n_string = 20 + rand() % N_STRING_RANGE;
  return drop_init_vals;
}

void print_n_string_from_string_array_struct(Drop_init_vals drop_init_vals, char str_display[][DIM_1_ARRAY_STRING][BYTES_PER_CHAR], int iter)
{
  int y1 = drop_init_vals.y1;
  int x1 = drop_init_vals.x1;
  int n_string = drop_init_vals.n_string;
  int n_dim_str = drop_init_vals.n_dim_str;
  int y_start = iter - drop_init_vals.iter_init;


  int count = 0;
  for (int i=y_start; i<y_start+n_string; i++)
  {
    if (count == 0 || count == 1){
      print_GREEN1(y1, x1, i, n_string, n_dim_str, str_display);
    }
    else if (count == 2 || count == 3 || count == 4){
      print_GREEN2(y1, x1, i, n_string, n_dim_str, str_display);
    }
    else{
      print_GREEN3(y1, x1, i, n_string, n_dim_str, str_display);
    }
    count++;
  }
}

Drop_init_vals drop_init_vals_array_to_zero(Drop_init_vals drop_init_vals)
{

  for (int drop_num = 0; drop_num < N_DROPS; drop_num++){
    drop_init_vals.y1 = 0;
    drop_init_vals.x1 = 0;
    drop_init_vals.n_string = 0;
    drop_init_vals.iter_init = 0;
    drop_init_vals.n_dim_str = 0;
  }
  return drop_init_vals;
}
/*set_characters.h*/

#ifndef SET_CHARACTERS_H
#define SET_CHARACTERS_H

#define N_COMMAS 56

#define SET_CHAR "ㇰ", "ㇱ", "ㇲ","ㇳ","ㇴ","ㇵ","ㇶ","ㇷ","ㇸ","ㇹ","ㇺ","ㇻ","ㇼ","ㇽ","ㇾ", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "<", "=", ">", "T", "H","E", "M", "A", "T", "R", "I", "X", "Z", ":", "・", ".", "=", "*", "+", "-", "<", ">", "¦", "|", "#", "_"


#endif
/*hyperparameters.h*/

#ifndef HYPERPARAMETERS_H
#define HYPERPARAMETERS_H

#define DELAY 60000 //480000
#define CUSTOM_GREEN1 8
#define CUSTOM_GREEN2 9
#define CUSTOM_GREEN3 10
#define COLOR_BLACK 0
#define DIM_0_ARRAY_STRING 30
#define DIM_1_ARRAY_STRING 150
#define BYTES_PER_CHAR 5

#define LEN_STRING_DISPLAY 100 
#define MAX_Y 100 
#define MAX_X 100 
#define N_STRING_MAX 20
#define N_DROPS 20

#define Y1_RANGE 20
#define X1_RANGE 50
#define N_STRING_RANGE 5
#define Y_START_RANGE 15
#define ITER_REFRESH 80
#define ITER_START_RANGE 80



#endif
#makefile

CC = gcc 
CFLAGS = -O2 -Wextra -Wall -Wfloat-equal -Wundef -Wshadow -Wpointer-arith -Wcast-align -Wstrict-prototypes -Wstrict-overflow=5 -Wwrite-strings -Waggregate-return -Wcast-qual -Wswitch-default -Wswitch-enum -Wconversion -Wunreachable-code -pedantic -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -fsanitize=address,undefined -O0 -ggdb

BINC=matrix_digital_rain

allc: $(BINC) 

$(BINC): $(BINC).o functions.o test.o
    $(CC) $(CFLAGS) -ggdb3 $(BINC).o functions.o test.o -o $@ -lncurses

$(BINC).o: $(BINC).c set_characters.h hyperparameters.h set_characters.h
    $(CC) $(CFLAGS) -c $(BINC).c

functions.o: functions.c functions.h
    $(CC) $(CFLAGS) -c functions.c 

test.o: test.c test.h
    $(CC) $(CFLAGS) -c test.c 

clean:
    $(RM) -rf $(BINC) *.dSYM *.o

runc: allc
    ./$(BINC) 
#   ./$(BINC) >/dev/null
ecjb
  • 5,169
  • 12
  • 43
  • 79