-1

I am new to C# and I have wrote a program that gives me index out of bound in specific program. Theoretically I see no reason why should i get this. The error is outputted in console but doesn't crash the program. I have 3 classes Logic, Student and Main. When I try to to print out a list of all the students I get an error. Student contains a Name, FN, and array of grades in form of double.

in Student.cs The students are added into a list(not shown here) also the grades are with capacity of 40 but student doesn't practically have 40 grades so the empty spaces are nulls->

public Student (string namee, int FNe, double[] gradese)
{
    name = namee;
    FN = FNe;
    grades = gradese;
} 

public void print()
{
    Console.WriteLine(name);
    Console.WriteLine(FN);

    double z = 0;
    int j = 0;

    while(grades[j] != 0)
    {
        Console.Write(grades[j]);
        z += grades[j];
        j++;
    }

    Console.WriteLine($"average: {z/j}" );
}

In "logic.cs" The students are added into a list(not shown here) also the grades are with capacity of 40 but student doesn't practically have 40 grades so the empty spaces are nulls->

List<Student> myList = new List<Student>();

public void print()
{
    for (int i = 0; i < myList.Count ; i++)
    {
        myList[i].print();
    }
}

The error i get is this but in the console:

Unhandled Exception: System.IndexOutOfRangeException: Index was outside the bounds of the array.
at ConsoleApp6.Student.print() in C:\Users\sashk\Source\Repos\ConsoleApp6\ConsoleApp6\Class1.cs:line 73
at ConsoleApp6.Logic.print() in C:\Users\sashk\Source\Repos\ConsoleApp6\ConsoleApp6\Class2.cs:line 37
at ConsoleApp6.Program.Main(String[] args) in C:\Users\sashk\Source\Repos\ConsoleApp6\ConsoleApp6\Program.cs:line 22
Press any key to continue . . .

Line 73 and 37 are the loops (while and for) respectively in Student and Logic

Markus Safar
  • 6,324
  • 5
  • 28
  • 44
  • It seems you are running out of the array boundary of the array `grades`. Why don't you use a `for`-loop instead of a `while`-loop there? Like `for (int i = 0; i < grades.Length; i++)` – Markus Safar Nov 19 '18 at 22:38
  • In the second one, you're not adding anything to myList. You need to check that myList.Count is greater than zero and then you won't get the outside of bounds error. As myList has no values added, its trying to access -1 which doesn't exist. – MiscellaneousUser Nov 19 '18 at 22:38
  • 1
    The code shown tries to iterate an empty list. Why not simply use foreach instead? – Filburt Nov 19 '18 at 22:39
  • `while(grades[j] != 0)` will gladly violate the bounds of `grades` as long as the last item isn't ensured to be 0. You haven't shown such an assurance anywhere in your code. Use a `for` loop in the same styling as your Logic.print() function, a `foreach` loop, or look up the linq `Average()` method. – Glorin Oakenfoot Nov 19 '18 at 22:39
  • Is it an array or a list? In any case, you logically _can't_ assume a grade of zero is a non-entry; zero is a valid grade. If it's an array, swap to using a list. Then you can have an arbitrary number of grades. – Glorin Oakenfoot Nov 19 '18 at 22:41
  • 1
    You also have a logic error in your **logic.cs** for loop. How many times do you think your loop will run if you only have one item in `myList`? Hint: if `i == 0` and `myList.Count == 1`, what do you think will happen in the expression `i < myList.Count - 1`? – Chris Nov 19 '18 at 22:43
  • @Chris 1 time, because i increments, right? – Kristianne Nerona Nov 19 '18 at 22:47
  • @TambaySaPinas zero times. He initializes `i` to `0` and if `myList.Count` only has `1` item, the for loop will never get entered because `0` is not less than `0` (in which he has `myList.Count - 1` which would be `0`). – Chris Nov 19 '18 at 22:49
  • Does Linq average works for array of doubles? – Jatos Detking Nov 19 '18 at 22:52
  • @JatosDetking Your problem is that you're attempting to access `grades[j]` without actually *checking* to see if a.) `grades` has any items to begin with, and b.) checking to see if the index `j`, even exists before using it. Have you stepped through the debugger? What is the value of `grades` before your exception error? – Chris Nov 19 '18 at 22:53
  • 1
    @JatosDetking Please stop commenting and work on a [mcve] that we can copy and paste and run on our end. The _general_ problem here is simple - you are asking for an index that doesn't exist (see the duplicate link). If you want more specific advice then you need to show us code that compiles. – mjwills Nov 19 '18 at 22:53
  • Your new code is better, but is still not a [mcve]. As an example, your code lacks a `Main` method. Copy and paste your code into a console app. Make sure it compiles and shows the behaviour you are seeing. Then copy and paste that code into your question. _I know this seems like work - but what you are doing now is pointless discussion which will all disappear if you provide a nice, clear [mcve]._ – mjwills Nov 19 '18 at 23:02
  • I'm having a suspicion that your arrays might actually be of length zero, but I cannot be sure from the code you've posted. Show us how do you create the Student objects, because it's possible that you've messed up there, and tell us why are you sure that the grades array is of length 40. – Filip Milovanović Nov 19 '18 at 23:15

2 Answers2

0

Unhandled Exception: System.IndexOutOfRangeException: Index was outside the bounds of the array.

indicates that you are running out of the array boundary of the array grades.

while(grades[j] != 0)
{
    ...
    j++;
}

...is not the correct way, you need to check for the array boundary.

And you could combine this with a for loop like this:

for (int i = 0; i < grades.Length; i++)
{
   ...
}

And instead of this

...
double z = 0;
int j = 0;

while(grades[j] != 0)
{
    Console.Write(grades[j]);
    z += grades[j];
    j++;
}
...

you probably want something like this

...
double average = CalculateAverage(grades);
...

private double CalculateAverage(double[] grades)
{
    double sum = 0;
    int numberOfGrades = 0;

    for (int i = 0; i < grades.Length; i++)
    {
        if (grades[i] == 0)
            continue;

        sum += grades[i];
        numberOfGrades++;
    }

    return sum / numberOfGrades;
}
Markus Safar
  • 6,324
  • 5
  • 28
  • 44
  • But what if the grades are like array is 40 elements long but i fill only 20 for example? i want the average only of these 20 , the others will be nulls? Like I make array of X elements but I fill only Y elements, does it .AverageWork with Doubles – Jatos Detking Nov 19 '18 at 22:48
  • @JatosDetking, Then you either have to remember the number of values in the array somewhere - like as integer value in an integer variable or you can use another data structure that is able to grow and shrink dynamically, like a [generic list](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1?view=netframework-4.7.2). Another way is to exclude the value "0" as it most likely is not a valid grade. – Markus Safar Nov 19 '18 at 22:50
  • @JatosDetking: You can also make the condition be an AND condition: (grades[j] != 0 && j < grades.Length), assuming all zeros are at the tail end of the array. – Filip Milovanović Nov 19 '18 at 23:04
-1

Change your for loop to use a foreach loop

Change this:

for (int i = 0; i < myList.Count - 1; i++)
{
    myList[i].print();
}

To this:

foreach(var student in myList) {
    student.print();
}

A for-each loop will iterate over every element. You do not increment i in this case anywhere else in your code, so using a for-each is recommended.

Dom
  • 159
  • 1
  • 3
  • 16