Same old ‘Object reference not set to an instance of an object’

Could someone explain the best way to avoid getting errors like ‘Object reference not set to an instance of an object’ please? I keep getting this type of error for different stuff and I would really like to know how to avoid it in the future and be able to fix it myself. I feel I am missing something fundamental. When I click on the error it takes me to line ‘int xPos = AIposStore[IDBest].xPos;’ So I am guessing the Array is not properly declared as an object or something?

Below is the script that currently has the error. Please excuse the sloppy code, this is the first time I tried to code some AI logic for a one player grid style puzzle game. Any other optimisations / better coding practices most welcome.

Full error:
NullReferenceException: Object reference not set to an instance of an object
AI.findBestPossition (System.Int32& returnx, System.Int32& returny, System.Int32& returnt, System.Int32& returnl) (at Assets/Scripts/AI.cs:38)
Game.Update () (at Assets/Scripts/Game.cs:79)
using UnityEngine;
using System.Collections;

public class AIpossitions
{
    public int xPos;
    public int yPos;
    public int Gtype;
    public int Glegal;
    public int howGood;
}

public class AI : MonoBehaviour {
    private Game game;
    private LegalGirder legalGirder;
    private int m_isLegalH;
    private bool m_isLegalV;
    private int m_GHmoves; // total number of leagle H moves
    private int m_GVmoves; // total number of leagle V moves
    private int m_Gtotal; // total number of leagle moves
    private AIpossitions[] AIposStore = new AIpossitions[1000];

	void Start () {
        game = GetComponent<Game>();
        legalGirder = GetComponent<LegalGirder>();
	}
	
	void Update () {
	}

    public void findBestPossition(out int returnx, out int returny, out int returnt, out int returnl)
    {
        GameData gameData = game.gameData;
        gameData.SetGameAIactive(1);
		storePossibleMoves(); // Tests and stores all possible moves into an Array.
		testGH_MakeBoxMoves(); // Tests from Array for good possition. If found adds 1 to its 'howGood' score.
		int IDBest = findBestScore(); // Find the highest scoring possition from the Array.
		returnx = AIposStore[IDBest].xPos;
		returny = AIposStore[IDBest].yPos;
		returnt = AIposStore[IDBest].Gtype;
		returnl = AIposStore[IDBest].Glegal;
    }

	// Tests and stores all possible moves into an Array.
    public void storePossibleMoves()
    {
        GameData gameData = game.gameData;
        int IDcount = 0;
        for (var y = 1; y < gameData.GetGridSize(); y++)
        {
            for (var x = 1; x < gameData.GetGridSize() - 1; x++)
            {
                m_isLegalH = legalGirder.TestHGirderLegal(x, y);
                if (m_isLegalH > 0)
                {
                    AIposStore[IDcount].xPos = x;
                    AIposStore[IDcount].yPos = y;
                    AIposStore[IDcount].Gtype = 0;
                    AIposStore[IDcount].Glegal = m_isLegalH;
                    AIposStore[IDcount].howGood = 1;
                    IDcount++;
                }
            }
        }
        int m_GHmoves = IDcount - 1;
        for (var x = 1; x < gameData.GetGridSize(); x++)
        {
            for (var y = 2; y < gameData.GetGridSize(); y++)
            {
                m_isLegalV = legalGirder.TestVGirderLegal(x, y);
                if (m_isLegalV == true)
                {
                    AIposStore[IDcount].xPos = x;
                    AIposStore[IDcount].yPos = y;
                    AIposStore[IDcount].Gtype = 1;
                    AIposStore[IDcount].Glegal = 0;
                    AIposStore[IDcount].howGood = 1;
                    IDcount++;
                }
            }
        }
        int m_GVmoves = IDcount - m_GHmoves - 1;
        int m_Gtotal = IDcount - 1;
    }

	// Tests from Array for good possition. If found adds 1 to its 'howGood' score.
    public void testGH_MakeBoxMoves()
    {
        GameData gameData = game.gameData;
		int IDcount = 0;
        for (var s = 1; s < m_GHmoves; s++)
        {
            int testPosX = AIposStore[IDcount].xPos;
            int testPosY = AIposStore[IDcount].yPos;
            if ((testPosY < gameData.GetGridSize()) && (testPosY > 0))
            {
                if ((gameData.GetGirdersHState(testPosX, testPosY - 1) >= 1) && (gameData.GetGirdersVState(testPosX, testPosY - 1) == 1) && (gameData.GetGirdersVState(testPosX + 1, testPosY - 1) == 1))
                {
                    AIposStore[IDcount].howGood++;
                }
            } 
        }
    }

	// Find the highest scoring possition from the Array.
    public int findBestScore() 
	{
        int IDScore = 0;
        int IDBest = 0;
        for (var s = 1; s < m_Gtotal; s++)
        {
            if (AIposStore~~.howGood > IDScore)~~

{
IDScore = AIposStore~~.howGood;
IDBest = s;
}
}
return IDBest;
}
}~~

I think you are not storing the data as you are intending. you have the line:

int m_GVmoves = IDcount - mGHmoves - 1;
int m_Gtotal = IDcount - 1;

so you are actually making them local variables because you are declaring them with “int”. you aren’t saving them in the instance as you are intending so your loops aren’t going all the way though, so it would seem. So when it tries to access something it hasn’t been setup at that index in the array because it’s still using 0 for your moves and total but an actual number for best as a returned value.

What you’re getting is a NullReferenceException. This means that you’re trying to access something - a variable, a method or a property - of something that doesn’t exist.

When you declare an variable in C#, it’s automatically set to the default value of the type of the variable. For value types, like ints or Vector3s or bools, the default is defined to something specific; for ints it’s 0, for Vector3s it’s (0,0,0), and for bools it’s false.

For any Objects, though, the default value is always null. I’ll not go into why, you just have to trust this dude with a degree CS that there are Good Reasons for this. And if you try to call a method or get a variable from null, you’ll be getting those NullReferenceExceptions, as the object* you’re referencing isn’t set to an instance of an object, but rather to null.

Now, if you’re getting a NullReference on something that looks like this:

foo.bar

then it’s pretty simple: foo is null. If foo had a value, but bar was null, that’d still be a valid value, it’s just a statement that returns null.

If you’re getting a NullReference on something like this, on the other hand:

foo.bar.tan[idx].foo2

it could be because foo is null, or because foo.bar is null, or because foo.bar.tan is null, or because foo.bar.tan[idx] is null. You don’t know which, you just know that in some part of the chain, you’re trying to access something on nothing.

So, when you have this line giving an error:

int xPos = AIposStore[IDBest].xPos

It’s either because the AIposStore array is null, or because the object at the index IDBest in the AIposStore is null. Since you’re declaring the AIposStore where you’re declaring it at the top of your script, it’s probably the second case. Which means that you should have put something in the array at one point, but didn’t.

Remember, the default value for the Object type AIpossitions you have made is null. So when you make the AIPosStore array like this:

private AIpossitions[] AIposStore = new AIpossitions[1000];

every element of that array is not an AIpossitions object, it’s null. You’ll have to fill the array with objects if you want to use it like you’re doing. You haven’t shown the AIpossitions class, but I’ll guess you’ll get by fine with a for-loop that puts a new object in every index of the array.

EDIT: missed the AIpossitions class (thanks, commenters!). You might want to turn that into a struct, that’d save you the trouble of having to fill the array, as the default value of a struct is the default value of all it’s components.

  • Actually, you’re not dealing directly with Objects, but rather with pointers that’s referencing somewhere in memory where there’s an object.

My apologies ‘tanoshimi’.
The error is in this line [returnx = AIposStore[IDBest].xPos;]
I cleaned up the code a little before posting it and forgot to update my text.

Thank you for everyone’s reply’s.
I will test and tag answers/votes as soon as I get home.