1

I am trying to write a program simulating the matrix digital rain using curses.h library and random numbers. The program seems to be working but the startup of the program is very slow (up to 10 seconds on MacOS 11.6.1, 2.8GHz Quad-Core Intel Core i7). Why is that? Is it relate to how random numbers are used? How can I improve the code so that the start of the program becomes snappy

Here is a snapshot of the usage of the program when I launch it:

PID    COMMAND          %CPU TIME     #TH   #WQ #PORTS MEM    PURG  CMPRS  PGRP  PPID  STATE    BOOSTS      %CPU_ME  %CPU_OTHRS UID FAULTS   COW     MSGSENT   MSGRECV   SYSBSD    SYSMACH   CSW       PAGEINS IDLEW   POWER INSTRS      CYCLES     USER                   #MREGS RPRVT VPRVT VSIZE KPRVT KSHRD
55710  matrix_digital_r 99.7 00:06.77 1/1   0   10     768K   0B    0B     55709 55709 running  *0[1]       0.00000  0.00000    501 318      39      16        8         165       40        1333+     0       0       99.7  12800790099 3889519761 user01                  N/A    N/A   N/A   N/A   N/A   N/A  

after 10-20 second here is the same usage:

PID    COMMAND          %CPU TIME     #TH   #WQ #PORTS MEM    PURG  CMPRS  PGRP  PPID  STATE    BOOSTS      %CPU_ME  %CPU_OTHRS UID FAULTS   COW     MSGSENT   MSGRECV   SYSBSD    SYSMACH   CSW       PAGEINS IDLEW   POWER INSTRS      CYCLES     USER                   #MREGS RPRVT VPRVT VSIZE KPRVT KSHRD
65886  matrix_digital_r 0.4   00:36.54 1     0   10     632K   0B     0B     65846 65846 sleeping *0[1]        0.00000  0.00000    501 284      39      18        8         381+      39        14329+    0       19+      0.5   8935555     8242181    user01                  N/A    N/A   N/A   N/A   N/A   N/A  

(The PID are not the same because it was 2 different runs but, the result in one run is the same). One can notice the the numbers for %CPU, INSTRS and CYCLES drastically decreases after a while and that the STATE changes from running to sleeping

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_vals01;
  //Drop_init_vals drop_init_vals02;
  //Drop_init_vals drop_init_vals03;
  //Drop_init_vals drop_init_vals04;
  //Drop_init_vals drop_init_vals05;
  //Drop_init_vals drop_init_vals06;
  //Drop_init_vals drop_init_vals07;
  //Drop_init_vals drop_init_vals08;
  //Drop_init_vals drop_init_vals09;

  int iter_start01 = rand() % ITER_START_RANGE; 
  //int iter_start02 = rand() % ITER_START_RANGE; 
  //int iter_start03 = rand() % ITER_START_RANGE; 
  //int iter_start04 = rand() % ITER_START_RANGE; 
  //int iter_start05 = rand() % ITER_START_RANGE; 
  //int iter_start06 = rand() % ITER_START_RANGE; 
  //int iter_start07 = rand() % ITER_START_RANGE; 
  //int iter_start08 = rand() % ITER_START_RANGE; 
  //int iter_start09 = 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<LEN_STRING_DISPLAY; j++){
    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();

    if (iter % ITER_REFRESH == iter_start01){
      drop_init_vals01 = random_drop_init_vals(drop_init_vals01, iter);
      drop_init_vals01.n_dim_str = 0;
    }

    print_n_string_from_string_array_struct(
      drop_init_vals01,
      str_display,
      iter
    );

/*
    if (iter % ITER_REFRESH == iter_start02){
      drop_init_vals02 = random_drop_init_vals(drop_init_vals02, iter);
      drop_init_vals02.n_dim_str = 1;
    }
    print_n_string_from_string_array_struct(
      drop_init_vals02,
      str_display,
      iter
    );


    if (iter % ITER_REFRESH == iter_start03){
      drop_init_vals03 = random_drop_init_vals(drop_init_vals03, iter);
      drop_init_vals03.n_dim_str = 2;
    }
    print_n_string_from_string_array_struct(
      drop_init_vals03,
      str_display,
      iter
    );

    if (iter % ITER_REFRESH == iter_start04){
      drop_init_vals04 = random_drop_init_vals(drop_init_vals04, iter);
      drop_init_vals04.n_dim_str = 3;
    }
    print_n_string_from_string_array_struct(
      drop_init_vals04,
      str_display,
      iter
    );


    if (iter % ITER_REFRESH == iter_start05){
      drop_init_vals05 = random_drop_init_vals(drop_init_vals05, iter);
      drop_init_vals05.n_dim_str = 4;
    }
    print_n_string_from_string_array_struct(
      drop_init_vals05,
      str_display,
      iter
    );


    if (iter % ITER_REFRESH == iter_start06){
      drop_init_vals06 = random_drop_init_vals(drop_init_vals06, iter);
      drop_init_vals06.n_dim_str = 5;
    }
    print_n_string_from_string_array_struct(
      drop_init_vals06,
      str_display,
      iter
    );


    if (iter % ITER_REFRESH == iter_start07){
      drop_init_vals07 = random_drop_init_vals(drop_init_vals07, iter);
      drop_init_vals07.n_dim_str = 6;
    }
    print_n_string_from_string_array_struct(
      drop_init_vals07,
      str_display,
      iter
    );

    if (iter % ITER_REFRESH == iter_start08){
      drop_init_vals08 = random_drop_init_vals(drop_init_vals08, iter);
      drop_init_vals08.n_dim_str = 7;
    }
    print_n_string_from_string_array_struct(
      drop_init_vals08,
      str_display,
      iter
    );

    if (iter % ITER_REFRESH == iter_start09){
      drop_init_vals09 = random_drop_init_vals(drop_init_vals09, iter);
      drop_init_vals09.n_dim_str = 8;
    }
    print_n_string_from_string_array_struct(
      drop_init_vals09,
      str_display,
      iter
    );

*/

    iter++;

    refresh();
    usleep(DELAY);
 
  }
  attron(COLOR_PAIR(1));
  attron(COLOR_PAIR(2));
  attron(COLOR_PAIR(3));
 
  endwin();
  refresh();
  use_default_colors();
}
/*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 random_drop_init_vals(Drop_init_vals drop_init_vals, int iter)
{
  

  struct timespec ts;
  clock_gettime(CLOCK_MONOTONIC, &ts);

  srand((unsigned int) (time_t)ts.tv_nsec);

  drop_init_vals.y1 = 0;
  drop_init_vals.x1 = rand() % X1_RANGE;
  drop_init_vals.n_string = 5 + rand() % N_STRING_RANGE;
  drop_init_vals.iter_init = iter;
  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++;
  }
}

//int gen_rand_int(){
//  struct timespec ts;
//  clock_gettime(CLOCK_MONOTONIC, &ts);
//
//  srand((unsigned int) (time_t)ts.tv_nsec);
//
//  return rand();
//}
/*functions.h*/

#ifndef FUNCTIONS_H
#define FUNCTIONS_H

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


int gen_rand_int(void);
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, int iter);

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]);



#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 Y1_RANGE 10
#define X1_RANGE 30
#define N_STRING_RANGE 5
#define Y_START_RANGE 15
#define ITER_REFRESH 60
#define ITER_START_RANGE 25


#endif
/*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
#makefile

CC = gcc 
CFLAGS = -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) $(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

According to comments: I changed the code as follow:

  • I renamed DIM_2_ARRAY_STRING in BYTES_PER_CHAR in all the files and changed its value from 4 to 5
  • I reduced the value of DIM_1_ARRAY_STRING from 200 to 100
  • in matrix_digital_rain.c I changed the line for (int j = 0; j<LEN_STRING_DISPLAY; j++){ in for (int j = 0; j<DIM_1_ARRAY_STRING; j++){
  • in the makefile I changed the line $(BINC): $(BINC).c $(BINC).o functions.o to $(BINC): $(BINC).o functions.o

EDIT 2

So I followed the advices of John Bollinger and made an array of drop_init_vals. This solved the problem of the slow startup (many thanks @JohnBollinger) and runs ok for low number of drops (#define N_DROPS in hyperparameters.h) but when there are many characters to be displayed on the screen, the characters are flickering and if I increase the number of drops to, let's say, 15, I get a segfault.

/*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] ;
  Drop_init_vals drop_init_vals_array[N_DROPS] ;

  //drop_init_vals_array[N_DROPS] = drop_init_vals_array_to_zero(&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] = random_drop_init_vals(drop_init_vals_array[drop_num], iter);
        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 (drop_init_vals_array[drop_num].iter_init == ITER_REFRESH){
        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.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, int iter)
Drop_init_vals random_drop_init_vals(Drop_init_vals drop_init_vals)
{
  
  //drop_init_vals.y1 = 0;
  drop_init_vals.x1 = rand() % X1_RANGE;
  drop_init_vals.n_string = 20 + rand() % N_STRING_RANGE;
  //drop_init_vals.iter_init = iter;
  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++;
  }
}

//int gen_rand_int(){
//  struct timespec ts;
//  clock_gettime(CLOCK_MONOTONIC, &ts);
//
//  srand((unsigned int) (time_t)ts.tv_nsec);
//
//  return rand();
//}

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 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;
}
/*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 ;


int gen_rand_int(void);
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, 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_array[N_DROPS]);
Drop_init_vals drop_init_vals_array_to_zero(Drop_init_vals drop_init_vals);

#endif
/*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 16

#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)
ecjb
  • 5,169
  • 12
  • 43
  • 79
  • `make: *** No rule to make target 'set_characters.h', needed by 'matrix_digital_rain.o'. Stop.` – Ted Lyngmo Mar 26 '23 at 11:18
  • Use a [*debugger*](https://stackoverflow.com/questions/25385173/what-is-a-debugger-and-how-can-it-help-me-diagnose-problems) to set a breakpoint at the `main` function entry. Is the startup time to load and get to the `main` function itself, or is it something inside your code that takes a lot of time? – Some programmer dude Mar 26 '23 at 11:19
  • After fixing the errors in compilation (`hyperparameters.c` should be `hyperparameters.h` and `set_characters.c` should be `set_characters.h`), the program starts directly for me – Ted Lyngmo Mar 26 '23 at 11:21
  • What happens if you link with `-lncursesw` instead? – Ted Lyngmo Mar 26 '23 at 11:27
  • Thank you for your comment @TedLyngmo. Thank you for pointing the error. Actually the file are misnamed in the question but they were correcly named in the machine. So the problem persists for me. And to be clear: the programs works, but the time to print the first few characters is very long – ecjb Mar 26 '23 at 11:28
  • Using `-lncursesw` yields the following: `ld: library not found for -lncursesw clang: error: linker command failed with exit code 1 (use -v to see invocation)` (on my Mac) – ecjb Mar 26 '23 at 11:31
  • Are you sure that `DIM_2_ARRAY_STRING` (4) is large enough? It looks like you're trying to accommodate UTF-8-encoded single-character strings. In that case, unless you're limiting yourself to characters from the BMP, you need to accommodate code sequences up to 4 bytes long, *plus* a string terminator, for a total of 5 bytes. – John Bollinger Mar 26 '23 at 12:13
  • The loop bounds for your initialization of `str_display` do not match the dimensions of the (leading) dimensions of that array. Some elements will be left uninitialized. – John Bollinger Mar 26 '23 at 12:22
  • `$(BINC).c` and `$(BINC).o` should not both be in the prerequisite list for `$(BINC)`, though it doesn't look like that will cause any actual harm in your case. The recipe refers only to the latter, so that's the one to keep as a prerequisite. – John Bollinger Mar 26 '23 at 12:26
  • The first dimension of `char_set` is (much) larger than the number of initializer elements presented for that object. Those elements not explicitly initialized will be implicitly initialized to all-zero. That's suspicious, but I'm not sure whether it's a problem in practice. – John Bollinger Mar 26 '23 at 12:38
  • Many thanks for your comment @JohnBollinger. I edited the question, explained the changes at the bottom of the question and changed the code accordingly. But the problem still persists – ecjb Mar 26 '23 at 13:10
  • If I may ask another question @JohnBollinger. If you uncomment the commented code in `matrix_digital_rain.c` you don't get a very slow startup time neither? – ecjb Mar 26 '23 at 13:44
  • Well that was not nice, @ecjb. The question should present the actual code you are asking about, not a modified version of it. I see no particular startup delay with the code as presented. I do see a startup delay if I uncomment the block-commented section of `matrix_digital_rain.c`. Please update the question appropriately. – John Bollinger Mar 26 '23 at 14:01
  • The `matrix_digital_rain.c` code suggests that you are aware that the RNG should be seeded only once. But the implementation of `random_drop_init_vals()` does not seem to have gotten that message. – John Bollinger Mar 26 '23 at 14:05
  • Sorry @JohnBollinger. I thank you for your support and did not mean to off-road by not following the rules. Tell me if I should backchange something – ecjb Mar 26 '23 at 14:10
  • I implemented your advice in setting an array of `drop_init_vals` which I initialized before. It solved the problem for low number of Drops (many thanks!! @JohnBollinger) but now the text is flickering and there is a segfault if N_Drops is set to 15. Now it's seems to be another question. Shall I accept your answer and ask another one? – ecjb Mar 27 '23 at 08:28
  • Did I missed it or your makefile doesn't set an optimization level, like `-O2`? – Bob__ Mar 27 '23 at 08:38
  • @Bob__. You are right. I did not. I added it – ecjb Mar 27 '23 at 09:37

1 Answers1

2

The main problem appears to be that you are using drop_init_vals01 - drop_init_vals09 uninitialized. Consider this ...

  int iter = 0;

  // ...

  while (1)
  {

    // ...

    if (iter % ITER_REFRESH == iter_start09){
      drop_init_vals09 = random_drop_init_vals(drop_init_vals09, iter);
      drop_init_vals09.n_dim_str = 8;
    }
    print_n_string_from_string_array_struct(
      drop_init_vals09,
      str_display,
      iter
    );

    // ...

    iter++;

    // ...
}

Remembering that none of the drop_init_valsXX have been initialized before loop entry, observe that drop_init_vals09 is passed to print_n_string_from_string_array_struct() on every iteration of the loop, but only when the value of iter reaches iter_start09 is drop_init_vals09 filled in. The same applies to all the other drop_init_valsXX variables, including drop_init_vals01. The program exhibits undefined behavior as a result.

I'm not sure why the manifestation of that UB is so different when you use nine variables than when you use only one, but "undefined" means what it says.

Additional notes:

  • The reason for the issue became clear to me after I identified the nature of the issue by running the program under Valgrind.

  • The program is begging for (more) use of arrays. Note all the code duplication in matrix_digital_rain.c. That source could be shrunk to less than half its current size while at the same time being made more flexible and robust by using an array of Drop_init_vals objects instead nine separate variables of that type (in conjunction with also using an array of int instead of nine separate int variables for the iter_start_vals). You then have an inner loop over those inside your while loop instead of separate code for each one.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157