Search code examples
cmatrixrandomstartupcurses

Very long startup time in a program simulating a matrix digital rain using `curses.h` library and random numbers


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)

Solution

  • 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.