I am trying to create a Sudoku in WinForms with C# as a school assignment. Everything in the sudoku MUST be object oriented so I have not chosen to structure the code like this, the teacher did.
When I put a number(int) in a Textbox in the SudokuGUI, it tries to put the number in the arrays but fails and give me the error well known:
An unhandled exception of type 'System.NullReferenceException'
occurred in WindowsFormsApplication5.exe Additional information:
Object reference not set to an instance of an object.
This is how the code look like:
First we send the Number when keyreleased from the TextBox to the method that will put the number in to the array
private void Valuechange_KeyUp(object sender, KeyEventArgs e)
{
TextBox text_box = sender as TextBox;
var position = tableLayoutPanel1.GetPositionFromControl(text_box);
int x = position.Row;
int y = position.Column;
if (int.TryParse(text_box.Text, out value) && int.Parse(text_box.Text) < 10 && int.Parse(text_box.Text) > 0 || value == 0)
{
add_value.Array_AddNumber(x, y, value);
}
else
{
MessageBox.Show("Skriv in en siffra mellan 1-9");
text_box.Clear();
}
}
Here is the method that will add the number from Textbox to the Array that will hold the numbers
class Ruta
{
Siffra number = new Siffra();
public Siffra[,] SudokuArray = new Siffra[9, 9];
public void Array_AddNumber(int x, int y, int value)
{
SudokuArray[x, y].nummer = value;
}
}
And here is the "Siffra" which means Number in Swedish, that is the the type of the Array
class Siffra
{
private int _nummer;
public int nummer
{
get { return _nummer; }
set { _nummer = value; }
}
}
What have I done wrong, I really don't understand, my teacher couldn't even help me :/
Here is the whole solution:
https://dl.dropboxusercontent.com/u/13409794/WindowsFormsApplication5.zip
The problem is a misunderstanding of this line:
public Siffra[,] SudokuArray = new Siffra[9,9];
That line creates a new 2-dimensional array object in memory, with space for 9 items x 9 items (81 in total). The misunderstanding is that the contents of each spot in the array is still null. Therefore, later on in your code, when you do this:
SudokuArray[x,y].nummer = value;
The code first looks up the array reference and uses that to find the element at position (x,y). That value is still null. The code then ties to use the nummer property of a null reference. Oops. You can't do that.
To fix it, you need to add this code to the constructor for your Ruta class:
for (int x = 0; x < 9; x++)
for (int y = 0; y < 9; y++)
SudokuArray[x,y] = new Siffra();
Since SudukuArray isn't null, the problem (the null value) must be the thing in it.
Siffra is a class - a reference type. That means instances of it are null by default (unlike structs, or value types).
So when you create a 9x9 array of them, you are creating a 9x9 array of nulls.
The rest is homework.
You are initializing the array:
public Siffra[,] array = new Siffra[9,9];
But never creating individual Siffra instances. Therefore, when you attempt to access one, you are actually getting a null. You then attemp to get a nummer from the null instance... which leads to the exception.
Solution
Initialize each instance in the array before you use it:
for(int i=0; i<9; i++)
for(int j=0; j<9; j++)
array[i,j] = new Siffra();
You have allocated the array to have a size that can hosts 9x9 Siffra, and that is right, but the 81 slots present in the array are all NULL.
None contains a Siffra so, when your code executes
SudokyArray[x,y].nummer = value;
it is like you are writing
null.nummer = value;
of course this is a NullReferenceException
Somewhere, possibly in the constructor of your class Ruta you need to fill the array with 81 instances of the class Siffra
class Ruta
{
public Siffra[,] SudokyArray;
public Ruta()
{
SudokyArray = new Sufra[9,9]
for(int i = 0; i < 9; i++)
{
for(int y = 0; y < 9; y++)
SudokuArray[i, y] = new Suffra();
}
}
}
Related
public List<Musteri> musteriListesi;
public void Ekleme()
{
int adet= 0;
Console.WriteLine("Kaç Adet Müşteri Eklenecek?");
adet= Convert.ToInt32(Console.ReadLine());
musteriListesi=Enumerable.Repeat(default(Musteri), adet).ToList();
for (int i = 0; i < adet; i++)
{
Console.WriteLine("Müşteri Adı:");
musteriListesi[i].Name=Console.ReadLine(); //==> Error Line
Console.WriteLine("Müşteri Soyadı:");
char ch;
char.TryParse(Console.ReadLine(), out ch);
musteriListesi[i].Gender = ch;
Console.WriteLine("Enter a date: ");
DateTime userDateTime;
if (DateTime.TryParse(Console.ReadLine(), out userDateTime))
{
Console.WriteLine("The day of the week is: " + userDateTime.DayOfWeek);
}
else
{
Console.WriteLine("You have entered an incorrect value");
}
musteriListesi[i].BirthDate=userDateTime;
}
}
I created a List from the customer class. I try to add value to the props in the Musteri class into the List I created, but it gives an error. customer =Musteri class
Error Message:
Unhandled exception. System.NullReferenceException: Object reference
not set to an instance of an object. at
ClassMetotDemo.MusteriManager.Ekleme()
This default(Musteri) evaluates to null, if Musteri is a reference type, it's default value is null, you'll need to create a new instance of Musteri when you generate the musteriListesi list.
Replace your Repeat logic with:
musteriListesi = Enumerable.Range(0, adet).Select(_ => new Musteri()).ToList();
You are adding null entries to your list because the default value of a class is null, not an empty object of this class. However, using Repeat(new Musteri(), adet) would not solve the problem, as it would add the same object to all positions of the list, but you must create a new object for every entry.
Use the Add method to add entries to the list"
musteriListesi = new List<Musteri>(adet);
for (int i = 0; i < adet; i++)
{
musteri = new Musteri();
musteriListesi.Add(musteri);
...
musteri.Name = Console.ReadLine();
...
}
Note, using the adet argument when creating the new list is not strictly necessary as it does not create a list of this size. It only reserves that much space in advance to the list's internal array. This makes adding entries more efficient, as the internal array will not have to be resized. If you don't know the size of the list in advance, you can just write musteriListesi = new List<Musteri>();.
What I'm trying to do is define my own type that contains 2 ints to use in a 2-dimensional array. The application for this is using the array indexes as x,y coordinates for objects in 2-d space to be displayed. So object with data stored at array[13,5] would be displayed at x=13,y=5, and the properties of that object could be retrieved with array[13,5].property1, for example. The type I've defined is extremely simple:
chunkBlocks.cs:
public class chunkBlocks {
public int blockType;
public int isLoaded;
}
then, I initialize the array:
chunkBlocks[,] _bData = new chunkBlocks[17, 17];
This all compiles/runs without error. The NRE is thrown when I try to assign a value to one of the properties of the type. For debugging, I have the code written as:
_bData[i, n].blockType = 5;
and the NRE is thrown specifically on the .blockType portion. I've tried changing the type to initialize with 0 values for both ints to no avail:
public class chunkBlocks {
public int blockType = 0;
public int isLoaded = 0;
}
I've Googled around and searched SO, and I've not been able to turn up anything. I'm sure it's a relatively simple matter, but I'm not experienced enough to be able to pinpoint it.
Thanks!
You need to initialize every instance of the array:
_bData[i, n] = new chunkBlocks();
Now assign the value to it:
_bData[i, n].blockType = 5;
You will have to initialize every instance, you just have declared them in the array.
I think you should do this:
for(int i = 0;i<17;i++)
{
for (int j = 0; j < 17; j++)
{
_bData[i, j] = new chunkBlocks ();
}
}
Here's a piece of code coming from a C# project using a 2d array. For a reason I don't understand my program compiles perfectly but during run-time it crashes.
public class Tile_Info
{
public int id;
public Tile_Info(int _id)
{
id = _id;
}
}
class Program
{
public static void Main(string[] args)
{
int width = 20;
int height = 30;
Tile_Info[,] my_tile;
my_tile = new Tile_Info[width, height];
for(int y = 0; y < height; y++)
{
for(int x = 0; x < width; x++)
{
my_tile[x, y].id = 0;
}
}
}
}
According to the debugger it's because "Object reference not set to an instance of an object", but I'm pretty sure it's what I'm doing here: my_tile = new Tile_Info[width, height];.
Anyone can tell what's wrong? Thank you for your support!
The creation of the array does not create the objects themselves, just like a creation of a parking lot does not create the cars that park there.
You still need to create the objects yourself. Change
my_tile[x, y].id = 0;
to
my_tile[x, y] = new Tile_Info(0);
This only happens when reference types (class) are used because the thing that is stored in the array is a reference to an instance, instead of the instance itself. On a lower level this (more or less) means that the memory for the instance is not yet allocated, just the memory for its reference, so you must new up an instance to initialize it. On the other hand if Tile_Info is a value type (struct) then the array will contain the actual instance, and the new Tile_Info[width, height] would have initialized the allocated memory to valid start state (all zeroes), which is exactly what the default parameterless constructor of a value type does.
So, if you had defined Tile_Info like this:
public struct Tile_Info
{
public int id; // this should be a property, public fields are baaad
public Tile_Info(int _id){ id = _id;}
}
both my_tile[x, y].id = 0 and my_tile[x, y] = new Tile_Info(0) would have been legal.
You have created a new 2D Tile_Info array by the first new keyword.
You have only created an empty array that can hold items of type Tile_Info. Its your job to create individual items and put them in the array.
I have some problem with this line of code:
if(String.IsNullOrEmpty(m_nameList[index]))
What have I done wrong?
EDIT: The m_nameList is underlined with red color in VisualStudio, and it says "the name 'm_nameList' does not exist in the current context"??
EDIT 2: I added some more code
class SeatManager
{
// Fields
private readonly int m_totNumOfSeats;
// Constructor
public SeatManager(int maxNumOfSeats)
{
m_totNumOfSeats = maxNumOfSeats;
// Create arrays for name and price
string[] m_nameList = new string[m_totNumOfSeats];
double[] m_priceList = new double[m_totNumOfSeats];
}
public int GetNumReserved()
{
int totalAmountReserved = 0;
for (int index = 0; index <= m_totNumOfSeats; index++)
{
if (String.IsNullOrEmpty(m_nameList[index]))
{
totalAmountReserved++;
}
}
return totalAmountReserved;
}
}
}
If m_nameList is null, that will still blow up, because it will try to find the element to pass to String.IsNullOrEmpty. You'd want:
if (m_nameList == null || String.IsNullOrEmpty(m_nameList[index]))
That's also assuming that index is going to be valid if m_nameList is non-null.
Of course, this is checking if the element of an array is null or empty, or if the array reference itself is null. If you just want to check the array itself (as your title suggests) you want:
if (m_nameList == null || m_nameList.Length == 0)
EDIT: Now we can see your code, there are two problems:
As Henk showed in his answer, you're trying to use a local variable when you need a field
You're also going to get an ArrayIndexOutOfBoundsException (once you've used a field) due to this:
for (int index = 0; index <= m_totNumOfSeats; index++)
That will perform m_totNumOfSeats + 1 iterations because of your bound. You want:
for (int index = 0; index < m_totNumOfSeats; index++)
Note that m_nameList[m_totNumOfSeats] is not valid, because array indexes
start at 0 in C#. So for an array of 5 elements, the valid indexes are 0, 1, 2, 3, 4.
Another option for your GetNumReserved method would be to use:
int count = 0;
foreach (string name in m_nameList)
{
if (string.IsNullOrEmpty(name))
{
count++;
}
}
return count;
Or using LINQ, it's a one-liner:
return m_nameList.Count(string.IsNullOrEmpty);
(Are you sure you haven't got it the wrong way round though? I would have thought reservations would be the ones where the name isn't null or empty, not the ones where it is null or empty.)
If it's the wrong way round, it would be this instead in LINQ:
return m_nameList.Count(name => !string.IsNullOrEmpty(name));
After Edit2:
You are defining m_nameList as a local variable of the constructor.
The rest of your code needs it as a field:
class SeatManager
{
// Fields
private readonly int m_totNumOfSeats;
private string[] m_nameList;
private double[] m_priceList;
// Constructor
public SeatManager(int maxNumOfSeats)
{
m_totNumOfSeats = maxNumOfSeats;
// Create arrays for name and price
m_nameList = new string[m_totNumOfSeats];
m_priceList = new double[m_totNumOfSeats];
}
....
}
To avoid the error you can perform some pre conditions in the if, like these :
if(m_nameList == null || index < 0 || m_nameList.Length < index || String.IsNullOrEmpty(m_nameList[index]))
This should works fine(without causing error) in almost any conditions ...
typedef struct {
int e1;
int e2;
int e3;
int e4;
int e5;
} abc;
void Hello(abc * a, int index)
{
int * post = (&(a->e1) + index);
int i;
for(i = 0; i<5; i++)
{
*(post + i) = i;
}
}
The problem I face here is how they able to access the next element in the struct by
*(post + i)
I'm not sure how all these would be done in C# and moreover, I don't want to use unsafe pointers in C#, but something alternate to it.
Thanks!
You should replace the struct with an array of 5 elements.
If you want to, you can wrap the array in a class with five properties.
edit...
When you say 'Wrap,' it generally means to write properties in a class that set or get the value of either a single variable, an array element, or a member of another class whose instance lives inside your class (the usual usage here = 'wrap an object'). Very useful for separating concerns and joining functionality of multiple objects. Technically, all simple properties just 'wrap' their private member variables.
Sample per comment:
class test
{
int[] e = new int[5];
public void Hello(int index)
{
for (int i = 0; i <= 4; i++) {
// will always happen if index != 0
if (i + index > 4) {
MsgBox("Original code would have overwritten memory. .Net will now blow up.");
}
e[i + index] = i;
}
}
public int e1 {
get { return e[0]; }
set { e[0] = value; }
}
public int e2 {
get { return e[1]; }
set { e[1] = value; }
}
//' ETC etc etc with e3-e5 ...
}
The problem with the C code is that if index is greater than 0 it runs off the end of the abc struct, thus overwriting random memory. This is exactly why C#, a safer language, does not allow these sorts of things. The way I'd implement your code in C# would be:
struct abc
{
public int[] e;
}
void Hello(ref abc a, int index)
{
a.e = new int[5];
for (int i = 0; i < 5; ++i)
a.e[index + i] = i;
}
Note that if index > 0, you'll get an out of bounds exception instead of possibly silent memory overwriting as you would in the C snippet.
The thinking behind the C codes is an ill fit for C#. The C code is based on the assumption that the fields of the struct will be placed sequentially in memory in the order defined the fields are defined in.
The above looks like either homework or a contrived example. Without knowing the real intent it's hard to give a concrete example in C#.
other examples here suggest changing the data structure but if you can't/don't want to do that, you can use reflection combined with an array of objects of the struct type to accomplish the same result as above.
void Hello(abc currentObj){
var fields = typeof(abc).GetFields();
for(var i = 0;i<fields.Length;i++){
fields[i].SetValue(currentObj,i);
}
}