0

I'm getting a Null reference exception on an array of strings (I think). So I put in a statement to check for null on my array, and it still gets thrown. I'm using Unity so my debugging tools aren't great. Is there anyway I can get Unity or Visual Studio to spit out exactly what is null here? I'm kind of at a loss. I'm fairly certain this array has been instantiated, since one, I know it isn't null due to my statement, and two, this code runs multiple times just fine. It is only after I fill up choices and then remove choices that I get the Null Reference. I'm using an engine (Dialoguer), but I'm hoping it isn't related.

--EDIT--

After a little debugging, I found out the following. Removing the choices.Length line removed the NRE the following code works as is, assuming that the number of input choices is two:

for (int i = 0; i < 2/*choices.Length*/; i++)
            {
                Debug.Log(choices[i]);
                if (GUI.Button(new Rect(10, 220 + (40 * i), 200, 30), choices[i]))
                {
                    Dialoguer.ContinueDialogue(i);
                }
            }

The code correctly prints the name of the two strings in choices[i]. So what I'm reading from this is that my array has elements, and is not null, but the Array.Length property is returning null for some reason. Is that correct?

Thanks for reading!

        if(choices != null && choices.Length > 0)
        {
            for (int i = 0; i < choices.Length; i++) //NRE is thrown here.
            {
                if (GUI.Button(new Rect(10, 220 + (40 * i), 200, 30), choices[i]))
                {
                    Dialoguer.ContinueDialogue(i);
                }
            }
        }

Full code (new):

using UnityEngine;

using System.Collections;

public class DialoguerGUI : MonoBehaviour {

private bool isShowing;

private string text;
private string[] choices;

// Use this for initialization
void Start() {
    choices = new string[19];
    Dialoguer.events.onStarted += onStarted;
    Dialoguer.events.onEnded += onEnded;
    Dialoguer.events.onTextPhase += onTextPhase;
}

void OnGUI()
{
    if (!isShowing)
        return;

    GUI.Box(new Rect(10, 10, 200, 150), text);

    if (choices == null)
    {
        if (GUI.Button(new Rect(10, 220, 200, 30), "continue"))
        {
            Dialoguer.ContinueDialogue();
        }
    } else
    {
            for (int i = 0; i < 2/*choices.Length*/; i++)
            {
                Debug.Log(choices[i]);
                if (GUI.Button(new Rect(10, 220 + (40 * i), 200, 30), choices[i]))
                {
                    Dialoguer.ContinueDialogue(i);
                }
            }
    }
}

// Update is called once per frame
void Update() {

}

private void onStarted()
{
    isShowing = true;
}

private void onEnded()
{
    isShowing = false;
}

private void onTextPhase(DialoguerTextData data)
{
    text = data.text;
    choices = data.choices;
}
}

Full Code (old):

using UnityEngine;
using System.Collections;

public class DialoguerGUI : MonoBehaviour {

private bool isShowing;

private string text;
private string[] choices;

// Use this for initialization
void Start() {
    Dialoguer.events.onStarted += onStarted;
    Dialoguer.events.onEnded += onEnded;
    Dialoguer.events.onTextPhase += onTextPhase;
}

void OnGUI()
{
    if (!isShowing)
        return;

    GUI.Box(new Rect(10, 10, 200, 150), text);

    if (choices == null)
    {
        if (GUI.Button(new Rect(10, 220, 200, 30), "continue"))
        {
            Dialoguer.ContinueDialogue();
        }
    } else
    {
        if(choices != null && choices.Length > 0)
        {
            for (int i = 0; i < choices.Length; i++)
            {
                if (GUI.Button(new Rect(10, 220 + (40 * i), 200, 30), choices[i]))
                {
                    Dialoguer.ContinueDialogue(i);
                }
            }
        }
    }
}

// Update is called once per frame
void Update() {

}

private void onStarted()
{
    isShowing = true;
}

private void onEnded()
{
    isShowing = false;
}

private void onTextPhase(DialoguerTextData data)
{
    text = data.text;
    choices = data.choices;
}
}
Manfred Radlwimmer
  • 13,257
  • 13
  • 53
  • 62
Maxw3ll
  • 61
  • 1
  • 6
  • 1
    @Guy this isn't java... – Ashwin Gupta Aug 10 '16 at 05:41
  • One thing is this line: `if(choices != null && choices.Length > 0)`. This checks to see if the array is null (not initalized at all). But its very possible that the array is incorrectly initalized and is not big enough or has certain elements with no initalization. In that case, when you loop through the excep. will be thrown. – Ashwin Gupta Aug 10 '16 at 05:42
  • @AshwinGupta True. But same idea. – Guy Aug 10 '16 at 05:42
  • Exactly same problem as here: http://stackoverflow.com/questions/38865036/null-reference-on-array-in-for-statement – Zein Makki Aug 10 '16 at 05:45

2 Answers2

1

Not sure what the root of the problem is, but this is why your if statement check is not preventing the error:

This line: if(choices != null && choices.Length > 0) checks to see if the array has been initialized.

The issue is, even if the array has been initialized, that is not to say that it has the number of elements initialized that you need or that every element is properly initialized. After this check, you immediately loop through the array and try to work with the data within. If there is an initialization issue, it errors.

Ashwin Gupta
  • 2,159
  • 9
  • 30
  • 60
  • I think this is closer. My array itself doesn't throw the exception, but the Length property does. In the code above, the NRE is actually thrown two lines above where I indicated, where the first instance of the property is called. So I think something is wrong with one of the entries in the array? – Maxw3ll Aug 10 '16 at 06:45
  • well referencing an unallocated element would cause problems. However, not entirely sure why the Length property throws the exception if the array is not Null but is properly initialized. I'm assuming you have already implemented @Programmer s solution because that will reduce some of the errors. – Ashwin Gupta Aug 10 '16 at 15:52
0

You forget to specify the size of the array.

Simply put choices = new string[50]; in the Start() function. Replace the 50 with the amount/size of string array you want the choices variable to hold.

void Start()
{
    choices = new string[50]; //This should fix it
    Dialoguer.events.onStarted += onStarted;
    Dialoguer.events.onEnded += onEnded;
    Dialoguer.events.onTextPhase += onTextPhase;
}
Programmer
  • 121,791
  • 22
  • 236
  • 328
  • Ah yup that should do it. Good catch. I was far to lazy to look through and debug his error for him! That was very nice of you. xD – Ashwin Gupta Aug 10 '16 at 05:46
  • Yeah. The usual simple mistake for new programmers. – Programmer Aug 10 '16 at 05:48
  • OFC, in Java this wouldn't be an issue because his `null` check would've worked. (Since objects are `null` by default). I don't know C# so I learned something new here! Not just new programmers benefit from this. – Ashwin Gupta Aug 10 '16 at 05:51
  • You are not actually wrong in your answer. `choices != null && choices.Length > 0` should have stopped that. It is very likely that there is another place he used the `choices` without checking for `null`. He probably didn't post that part here. Anyways, I don't know what going on but adding `choices = new string[50];` should fix the problem. – Programmer Aug 10 '16 at 06:10
  • 1
    Ah okay, well that makes more sense. LOL hopefully yours fixes it. At the very least it should help the OP go in the right direction for debug. – Ashwin Gupta Aug 10 '16 at 06:12
  • This wasn't the issue, unfortunately. Whenever choices gets used at all, it has been set by an external function in onTextPhase. Instantiating the array in the start function still left it returning NRE. – Maxw3ll Aug 10 '16 at 06:35
  • Why not post the line of code that is causing that error? When you see that error, double click on it and it should bring up that line of code... – Programmer Aug 10 '16 at 06:38
  • In unity, I'm getting the following: NullReferenceException: Object reference not set to an instance of an object DialoguerGUI.OnGUI () (at Assets/DialoguerGUI.cs:36). This corresponds to the line commented in the code above. I think I may be misunderstanding your question. – Maxw3ll Aug 10 '16 at 06:41
  • 1.You still have to allocate memory **once** like I did in the `Start()` function even though it did not work for you. Now, to change the text, create a function that takes array as parameter then you can update the choice with something lie `data.choices(choices);`. I can't force you to do that but you always allocation memory with the method you use now. – Programmer Aug 10 '16 at 06:55
  • As for your problem,I asked for you to paste the line of code not the error message. If you click on it, it will take you on that line of code. Copy and past. That's it. – Programmer Aug 10 '16 at 06:58