A quirky problem with string arrays and Null Pointer Exception

I am not a Processing Pro but have a fair amount of experience with Processing sketches quite a bit more complex than the one below. As an exercise, I was trying to read strings from a text file (3 tab separated elements in each line) then split the lines into individual text elements. The code is listed below. Note that at the end of “draw” there is included, as a comment, a 5-line text file that you can use to create the necessary text file with the title vocab.txt and place it in a “data” folder for the sketch.

If this sketch - as listed below- is run with the most current version of Processing, it runs and note the only output is to the console - BUT - if you include the first CODE line in draw that is initially comment out - the run fails with a NullPointerException and this line is identical to the last line in setup which executes correctly in setup. So why the code works when this line is executed in setup but then not when immediately repeated in draw is perplexing.

I have tried everything I can think of to rectify this but to no avail. Since I am currently “sheltering in place” and expect there maybe some others doing the same thing and are willing to offer some advice - I thought I’d share this problem and see if anyone can show me where my “error” is.

Thanks in advance.

`

/**
 * adapted from the Processing example - LoadFile 1
 * 
 * Loads a text file that contains two strings separated by a tab ('\t').
 * and then....
 */
String[] words;
String[] french;
String[] english;
int iRun, iWord;

void setup() {
  
  size(200, 200);
  background(0);
  stroke(255);
  frameRate(12);

  words = loadStrings("vocab.txt");
  println("there are " + words.length + " word pairs");
  for (int i = 0 ; i < words.length; i++) {
    println(words[i]);
     }
     
  String[] french = new String[words.length+1];
  String[] english = new String[words.length+1]; 
  french[0]="French";english[0]="English";
  for(int i = 0; i < words.length; i = i+1) {
    String[] frenchEnglish = split(words[i], '\t');
    println(frenchEnglish[0]);
    int iWord=int(frenchEnglish[0]);
    println("French word ",iWord," is ",frenchEnglish[1]);
    println("English word ",iWord," is ",frenchEnglish[2]);
    int iPair=i+1;
    french[iPair]= frenchEnglish[1];
    english[iPair]= frenchEnglish[2];
    println("iPair = ",iPair,"    French = ",french[iPair],"    English =",english[iPair]);
    }
  for(int i=0; i < words.length+1; i++){println(i," ",french[i]," ",english[i]);}
  iRun=1;
  iWord=1;
  println("leaving setup");
}

void draw() {
// with the following line (a duplicate of the 2nd to the last line in setup) active, there is a null pointer exception
// with the following line commented out - it runs as intended
// for some reason the 2 strings "french[]" and "english[]" are not properly recognized in draw but they are in setup

//  for(int i=0; i < words.length+1; i++){println(i," ",french[i]," ",english[i]);}

  for(int iSteps = 1; iSteps <= 5; iSteps++){
    iWord = int(random(1.,float(words.length)+.99));
    println(iWord);
    println(words[iWord-1]);
    delay(200);}
    
  exit();
}

/*
 the following is the "data" file vocab.txt

1  oui  yes
2  alors  so, then
3  etre  to be
4  faire  to do
5  quoi  what

*/


`
1 Like

Hello an welcome to the forum!

I used ’ ’ instead of tab

 frenchEnglish = split(words[i], ' ');

Chrisir,

Thanks for taking the time to help try to resolve this issue. I should have mentioned in my original post that I had used a “tab” to space the entries in the vocab.txt file (Sorry - obviously the TAB wasn’t apparent when I attached a copy of that file to the end of the sketch.)

I used your suggestion, removed the tab in the txt file and replaced it with a space and the sketch executes correctly ONLY if the line in “draw” shown below is not active. That is what occurred with the tab separation, so the error does not seem to be associated with the split operation.

If the following line in draw

//  for(int i=0; i < words.length+1; i++){println(i," ",french[i]," ",english[i]);}

is “commented out” as shown above - success, but if I activate that line in draw the NullPointerException occurs.

Were you able to successfully run the sketch with that line active in draw?

That is the “quirky” part. That line executes correctly in setup but fails in draw … and that make no sense to me.

Again I appreciate your comment and would like to know if you were able to run this successfully with that line active in draw?

your error was simple

in setup you had this with String[] in front. Bad. That made both arrays local, meaning known in setup() only, not in draw().

This is the correct form in setup()

  french = new String[words.length+1];
  english = new String[words.length+1];
2 Likes

here is a version with text() in draw, formatted as a table


/**
 * adapted from the Processing example - LoadFile 1
 * 
 * Loads a text file that contains two strings separated by a tab ('\t').
 * and then....
 */
String[] words;
String[] french;
String[] english;
int iRun, iWord;

void setup() {

  size(1200, 500);
  background(0);
  stroke(255);
  frameRate(12);

  words = loadStrings("vocab.txt");
  println("there are " + words.length + " word pairs");
  for (int i = 0; i < words.length; i++) {
    println(words[i]);
  }

  french = new String[words.length+1];
  english = new String[words.length+1]; 

  french[0]="French";
  english[0]="English";

  for (int i = 0; i < words.length; i = i+1) {
    String[] frenchEnglish = split(words[i], ' ');
    println(frenchEnglish[0]);
    int iWord=int(frenchEnglish[0]);
    println("French word ", iWord, " is ", frenchEnglish[1]);
    println("English word ", iWord, " is ", frenchEnglish[2]);
    int iPair=i+1;
    french[iPair]= frenchEnglish[1];
    english[iPair]= frenchEnglish[2];
    println("iPair = ", iPair, "    French = ", french[iPair], "    English =", english[iPair]);
  }
  for (int i=0; i < words.length+1; i++) {
    println(i, " ", french[i], " ", english[i]);
  }
  iRun=1;
  iWord=1;
  println("leaving setup ----------------------------------");
}

void draw() {

  background(0);

  // with the following line (a duplicate of the 2nd to the last line in setup) active, there is a null pointer exception
  // with the following line commented out - it runs as intended
  // for some reason the 2 strings "french[]" and "english[]" are not properly recognized in draw but they are in setup

  for (int i=0; i < words.length+1; i++) {
    //  println(i);
    //println(i, " ", french[i], " ", english[i]);
    textWithTab(i + "\t" + french[i] + "\t" + english[i], 
      110, 120+ 22*i);
  }

  for (int iSteps = 1; iSteps <= 5; iSteps++) {
    iWord = int(random(1., float(words.length)+.99));
    //   println(iWord);
    //   println(words[iWord-1]);
    // delay(200);
  }

  // exit();
}

void textWithTab(String s, float x, float y) {

  String[] sArray = s.split("\t");

  for (int i = 0; i < sArray.length; i++) {
    text(sArray[i], x, y);
    x+=211;
  }
}

/*
 the following is the "data" file vocab.txt
 
 1  oui  yes
 2  alors  so, then
 3  etre  to be
 4  faire  to do
 5  quoi  what
 
 */
1 Like

People like you, willing to assist anyone, are what makes this and similar forums great. Obviously, this was my “bad”…

I had tried so many different thing to remedy this problem including defining the strings as public, and knew I had to define “french” and “english” in setup but never realized that repeating the “String[]” prefix would localize that array. Lesson learned!

Thank you so much for your assistance - now I can move ahead and work on this sketch.

ALSO - somehow it shows that I “Solved” this question but obviously you are the individual who did the “solving”…

2 Likes

thank you for your kind words.

here is a version where I use a real Table to show the vocabulary

It’s just where you click solution, I think when you click it in my posts, this posts will be the solution.

Warmest Regards,

Chrisir


/**
 * adapted from the Processing example - LoadFile 1
 * 
 * Loads a text file that contains two strings separated by a tab ('\t').
 * and then....
 */
String[] words;
String[] french;
String[] english;
int iRun, iWord;

// class with tools 
Tools tools = new Tools(); 

// the table
Table tResources; 


void setup() {

  size(1200, 500);
  background(0);
  stroke(255);
  frameRate(12);

  words = loadStrings("vocab.txt");
  println("there are " + words.length + " word pairs");
  for (int i = 0; i < words.length; i++) {
    println(words[i]);
  }

  french = new String[words.length+1];
  english = new String[words.length+1]; 

  french[0]="French";
  english[0]="English";

  for (int i = 0; i < words.length; i = i+1) {
    String[] frenchEnglish = split(words[i], ' ');
    println(frenchEnglish[0]);
    int iWord=int(frenchEnglish[0]);
    println("French word ", iWord, " is ", frenchEnglish[1]);
    println("English word ", iWord, " is ", frenchEnglish[2]);
    int iPair=i+1;
    french[iPair]= frenchEnglish[1];
    english[iPair]= frenchEnglish[2];
    println("iPair = ", iPair, "    French = ", french[iPair], "    English =", english[iPair]);
  }
  for (int i=0; i < words.length+1; i++) {
    println(i, " ", french[i], " ", english[i]);
  }
  iRun=1;
  iWord=1;

  setupTable() ;

  println("leaving setup ----------------------------------");
}

void draw() {
  background(0);

  tools.showTable(tResources, 
    22, 22);
}

//---------------------------------------------------------------------

void setupTable() {

  // setting up table (column names / headlines)
  tResources = tools.newTable("No", "French", "English");
  // adding data (must match headlines)
  for (int i=0; i < words.length+1; i++) {
    tResources = tools.tableAddData ( tResources, str(i), french[i], english[i] );
  }
}

//===============================================================================
// Tools collection 

class Tools {

  // class not like a car class Car for an object but a collection of tools. 

  final color RED   = color(255, 0, 0); 
  final color GREEN = color(0, 255, 0); 
  final color BLUE  = color(0, 0, 255); 

  final color WHITE = color(255); 
  final color BLACK = color(0); 
  final color GRAY  = color(255/2); 

  boolean cursorSignShowFlag=false; 

  // ----------------------------------------------------------------

  void showTable(Table tableBtn, 
    int x, int y) { 

    int factorX=78; // column width 

    // rect
    stroke(WHITE);
    noFill();
    rect( x, y, 
      tableBtn.getColumnCount()*78-6, (tableBtn.getRowCount()+1) * 22 + 10 );

    // headline 
    showTableHeadline(tableBtn, x+6, y+19, factorX);

    // horizontal line 
    stroke(WHITE);
    line( x+2, y+5+19, 
      6+x+(tableBtn.getColumnCount())*factorX-13, y+5+19);

    // grid 
    // loop over rows (y)
    for (int i=0; i<tableBtn.getRowCount(); i++) {

      // current data row
      TableRow row = tableBtn.getRow(i);

      // loop over columns in that row (i2 is for x) 
      for (int i2=0; i2<tableBtn.getColumnCount(); i2++) {

        fill(WHITE);
        text(row.getString(i2), 
          i2*factorX+x+6, 25+ i * 22 +y+8, 
          factorX-8, 15);

        if (mouseInside(i2*factorX+x+6, 25+ i * 22 +y+8, 
          factorX-8, 15)) {
          text (row.getString(i2), 
            20, height-22);
        }//if

        // vertical line 
        line( i2*factorX+x, +y, 
          i2*factorX+x, tableBtn.getRowCount() * 22 + y + 31);
      }//for
    }//for
  }// method 

  boolean mouseInside( float x_, float y_, 
    float w_, float h_) {
    return mouseX>x_ &&
      mouseX<x_+w_ &&
      mouseY>y_ &&
      mouseY<y_+h_;
  }

  void showTableHeadline(Table tableBtn, 
    int x, int y, 
    int factorX) { 
    // headline for table 
    TableRow row0 = tableBtn.getRow(0);
    for (int i=0; i<tableBtn.getColumnCount(); i++) {
      // headline 
      fill(GREEN);
      text(row0.getColumnTitle(i), 
        i*factorX+x, y-2);
    }
  }//method 

  // ---
  // make table 

  Table newTable (String... listColumnNames) { 

    Table newT = new Table();

    // make columns
    for (String s1 : listColumnNames) {
      newT.addColumn(s1);
    }

    return newT;
  }//method

  Table tableAddData(  Table table1, String... data1  ) {

    // add rows with data 
    TableRow newRow = table1.addRow();

    // add rows with data 
    int i=0; 
    for (String s1 : data1) {
      newRow.setString(newRow.getColumnTitle(i), s1);
      i++;
    }


    return table1;
  }//method

  // --- 

  void printlnTable(Table tableBtn) { 

    // rect
    stroke(WHITE);
    noFill();

    println("------------------------------------");

    // headline 
    printlnTableHeadline(tableBtn);

    // grid 
    // loop over rows (y)
    for (int i=0; i<tableBtn.getRowCount(); i++) {

      // current data row
      TableRow row = tableBtn.getRow(i);

      // loop over columns in that row (i2 is for x)
      String s1="";
      for (int i2=0; i2<tableBtn.getColumnCount(); i2++) {
        s1+="   "+row.getString(i2);
        //
      }//for
      println(s1);
    }//for
    println("===========================================");
    //
  } // method 

  void printlnTableHeadline(Table tableBtn ) { 
    // headline for table 
    TableRow row0 = tableBtn.getRow(0);
    for (int i=0; i<tableBtn.getColumnCount(); i++) {
      // headline 
      print("   "+row0.getColumnTitle(i));
    }
    println("");
  }//method 

  // ------------------------------------------------------------------

  String cursorSign() {
    // blinking cursor sign | for Input Box 
    if (frameCount % 13 == 0)
      cursorSignShowFlag= ! cursorSignShowFlag;
    if (cursorSignShowFlag)
      return"|";
    else return"";
  }//method

  //
}//class
//

/*
 the following is the "data" file vocab.txt
 
 1  oui  yes
 2  alors  so, then
 3  etre  to be
 4  faire  to do
 5  quoi  what
 
 */
1 Like

In fact, since you have spaces in the vocabulary (“to be” to give an example), a tab as the delimiter would indeed be wiser…

Yes, I want to use the tab since, as I develop this little sketch, some words will have multiple meanings…

I also look forward to learning from the sketch you’ve provided.

Once again, thanks for your input.

2 Likes