C# Arrays: Store Values and Traverse Every Shape Safely
An array stores ordered elements, but safe processing depends on its size, references and shape. Learn to check empty sources, copy deliberately, and traverse rectangular and jagged data using the correct bounds.
What you will understand
- Create fixed-size arrays and replace individual elements.
- Explain default element values without treating them as validated data.
- Check zero-based positions and distinguish empty from null.
- Compare shared array references with copied integer elements.
- Calculate a guarded fractional average and maximum.
- Use GetLength for rectangular dimensions and Length for total cells.
- Traverse jagged rows using each current row’s length.
- Handle empty or absent rows through an explicit policy.
An array has one element type and a fixed instance size
An array groups ordered elements under one name. int[] scores means each element is an int. The initializer supplies the starting values and determines this array’s length. You have already traversed arrays; now distinguish the array object, its element values and its index positions.
An array instance has a fixed length after creation, but its elements can be replaced. Assigning scores[0] changes one value without adding or removing a slot. A variable can later refer to a different array, which is different from growing the existing instance. Resizable collection types belong to later study.
Use the earlier loops and numeric-type lessons as prerequisites. Every example is a complete Program.cs. Two examples intentionally fail at runtime to expose invalid boundaries. The lab summarizes a small score set and defines what happens when it has no elements.
Program.cs · Create ordered values and update one element
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Count: 3
First before: 60
First after: 65
int[] declares an array of integers. The initializer supplies three ordered elements. Replacing scores[0] changes that element without changing the array length. Position zero is the first element; the last position here is two.
Program.cs · New slots receive their element type default
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Count slot: 0
Flag slot: False
Name is null: True
Allocating an array initializes its elements: int gets zero, bool gets false and reference elements get null. The nullable string annotation describes the possible missing element. Zero-filled score slots are not evidence that a learner completed a test with score zero; defaults and domain data are separate.
Treat empty and absent arrays as different states
For an array of length n, valid indexes run from zero through n minus one. Length itself is outside the array. If a position comes from input or another calculation, check both position >= 0 and position < Length before accessing it.
An empty array is present and has zero elements. It is safe to traverse, but it has no first element or highest value to read. A null array is absent; reading Length on it would fail. Choose a presence policy before an empty check when the whole reference may be null.
Allocated slots receive default values, not validated application records. In particular, new string slots initially contain null references even if non-nullable annotations express a stronger intended contract. Initialize actual values or model missing data explicitly; compiler annotations do not populate storage.
Program.cs · Reject a position outside the array
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Position is outside the array.
Check both ends before accessing an externally supplied position. Length is not a valid element index. This guard also works for an empty array, because no index is allowed. If the whole array could be null, its presence must be checked before reading Length.
Program.cs · Inspect the failure from an invalid access
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Count: 2
Then execution fails with IndexOutOfRangeException.Both indexes zero and one exist; index two does not. The first message prints before execution fails. An array access outside its bounds is not automatically clamped or converted into a default element.
Assignment shares an array; a copy needs separate storage
Arrays are reference types. When alias = original is assigned, both variables identify the same array instance. Mutating an element through one name is visible through the other. This is different from copying the value of an int element into its own int variable.
To preserve independent element storage, allocate another array and copy the elements. Array.Copy is a library helper for that work. With int elements, changing one copied slot does not affect the original slot.
Copying reference-type elements still copies references. A copied array of mutable objects would not automatically duplicate each object. The int example demonstrates independent integer slots without claiming a recursive deep-copy operation for arbitrary data.
Program.cs · Two variables can refer to the same array
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Original first: 99
Alias first: 99
Assigning an array variable copies its reference, not all its elements. Both names refer to the same array instance, so an element change is visible through either. The int elements themselves are values; the shared object here is the array holding them.
Program.cs · Copy elements when independent storage is required
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Original first: 10
Copy first: 99
The destination is a separate array, and Array.Copy copies these int elements into it. Changing copy no longer changes original. For reference-type elements, copying elements copies references rather than recursively duplicating the objects they point to; this example does not claim a universal deep copy.
Handle the no-data case before calculating a summary
A sum can start at zero even when there are no elements, but an average needs a positive count and a maximum needs a defined policy for no data. Guard the empty source before dividing or reading the first element to initialize a maximum.
Convert before dividing when a fractional average is intended. total / Length with two int operands performs integer division before any double assignment. Formatting with F1 cannot reconstruct the discarded fraction.
State the numeric assumptions. The examples use small valid scores and an int sum that fits. A larger source or unconstrained numeric values may need a wider accumulator, validation or explicit overflow handling. The array structure alone does not enforce score rules.
Program.cs · Guard an empty source before an average
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Total: 225
Average: 75.0
The empty guard makes the denominator positive before division. Convert the total before dividing to preserve a fractional average. These small fixed scores fit int; a general implementation also needs a score-domain policy and a sufficiently wide sum type.
A rectangular grid is one array with several dimensions
int[,] declares a two-dimensional rectangular array. You may interpret its first index as a row and its second as a column. Access a cell with grid[row, column], using one bracket pair containing both indexes.
GetLength(0) returns the size of the first dimension and GetLength(1) returns the second. Length returns the total number of cells. A two-row, three-column array has six cells, but six is not a valid row or column bound.
Use a separate bound for each nested loop. Reset a row total inside the outer body so each row gets its own result. A rectangular grid can have a zero-length dimension; do not assume a nonzero total or an existing first cell without checking the shape.
Program.cs · A rectangular array has a length for each dimension
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Rows: 2
Columns: 3
Total elements: 6
Row 1, column 2: 50
int[,] is one two-dimensional array. GetLength(0) counts the first dimension and GetLength(1) counts the second. Length counts every element across both dimensions. The row and column interpretation is a convention of this report; both indexes are zero-based.
Program.cs · Traverse each rectangular dimension with its own bound
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Row 1 total: 210
Row 2 total: 240
The outer bound uses the row dimension, and the inner bound uses the column dimension. total resets once per row, not once per cell. Using scores.Length for either index would confuse six total cells with a valid row or column count.
A jagged structure is an array of separate arrays
int[][] is an outer array containing inner int arrays. Access a value with groups[row][column]. Each row is an independent array and may have a different length, including zero. The outer Length counts rows rather than scores.
Use the current row’s Length for its inner traversal. The first row’s length is not a promise about other rows. An empty first row must not hide later rows, and a long first row must not force access beyond a shorter later row.
Creating only the outer array leaves its row references null. Initialize each required row or handle a missing-row state deliberately before reading its Length. Empty and missing rows may mean different things, so do not silently substitute one for the other without a stated policy.
Program.cs · A jagged array stores separate row arrays
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Rows: 3
Row 1 entries: 2
Row 2 entries: 0
Row 3 entries: 1
int[][] is an array whose elements are int arrays. Its outer Length counts rows, not all scores. Each present row has its own Length and may be empty. Unlike a rectangular array, it does not require every row to have the same size.
Program.cs · An allocated outer array does not create each row
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Outer rows: 2
First row absent: True
First row now has: 2
The outer array initially contains null row references. Its non-nullable element spelling does not allocate those rows or guarantee that every slot is populated at runtime. Initialize rows explicitly or model and check missing rows. An absent row and an empty row can have different meanings.
Choose the shape from the meaning of the data
Use a single-dimensional array for one ordered sequence. A rectangular array is useful when every row shares a fixed set of columns, such as the same exercises across several sessions. A jagged array suits rows whose sizes legitimately differ, such as different numbers of readings per session.
Keep shape questions separate from domain questions. A valid index proves a slot exists, not that its score is acceptable. A present row can still be empty, and a copied array may still share referenced objects. Explain exactly what each check establishes.
Test an empty source, one item, several items, an empty row and rows of unequal lengths. For summaries, verify a fractional average and a correct highest value. For nested traversals, check every dimension independently instead of assuming the example’s first row describes the whole source.
Guided repair: traverse the current row
The second row is shorter than the first, so the program prints three valid scores and then fails. Repair the inner bound to describe the row currently being read, without assuming a uniform shape.
Program.cs · The first row length is not every row length
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
60
80
90
Then execution fails with IndexOutOfRangeException.The second row has only one entry, but the inner bound assumes two because it reads the first row’s length. Correct initial output hides a later boundary failure. A jagged traversal must use the current row’s own length.
Repair checkpoints
- Use groups[row].Length for the current inner bound.
- Keep the original source order and print 60, 80 and 90 once each.
- With an empty first row and a later nonempty row, still visit the later scores.
- An empty outer array produces no output.
- The repair assumes present rows; explain why a null row would require a separate policy.
Reveal the repair and explanation
Program.cs · Use the current jagged row as the inner source
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
60
80
90
groups[row].Length describes the row being accessed. This repair assumes all rows are present, as the initializer guarantees. An empty current row naturally produces no inner iterations; a null row would require a guard or a different initialization policy.
Independent lab: a score summary with an empty-input policy
Summarize a small fixed score array with a count, fractional average and highest value. Define an explicit empty-source response and preserve the original values.
Acceptance checklist
- Use scores 70, 81 and 90 for the reference run.
- Check Length before reading a first element or dividing.
- For an empty source, print No scores to summarize. and return.
- Initialize highest from a real element after the guard.
- Traverse the values once to calculate the sum and maximum.
- Convert before division and print the average with one fractional digit.
- Print Count: 3, Average: 80.3 and Highest: 90 for the reference input.
- Assume small scores in 0 through 100 and an int sum that fits; do not claim to validate arbitrary datasets.
Program.cs · Score report starter
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Count: 3
Average: 80.0
Highest: 0
Integer division discards the fraction before assigning average. The highest value is a placeholder rather than a computed result, and the program does not define an empty-source policy. Build the report from the actual elements and guard absence of data before the calculations.
Show hints
- The first element is safe only after the no-data guard.
- Keep total and highest outside the repeated body.
- A double destination alone does not fix int division.
Reveal the reference solution
Program.cs · Score report reference solution
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Count: 3
Average: 80.3
Highest: 90
The first element is read only after the empty check. Initializing highest from real data avoids a guessed zero baseline. The traversal computes a sum and maximum without changing the source. This lab assumes each supplied score is in 0 through 100 and the source is small enough for the int sum.
Changed-input checks
- An empty array prints only the no-data message.
- One score of 81 produces count 1, average 81.0 and highest 81.
- Scores 0 and 100 produce average 50.0 and highest 100.
- Three scores of 75 produce average and highest 75.
- Reorder the reference source: the summary should stay the same.
Recap: choose the array shape and its bounds
Check the whole reference, the number of elements and each row’s shape separately. Copying, validation and summary calculations answer different questions.
T[]- One ordered array of elements of type T.
new int[count]- Allocate fixed slots initialized to zero.
index < values.Length- Stay below the one-dimensional upper bound; also reject negative indexes.
alias = original- Share one array instance rather than copy its elements.
Array.Copy- Copy elements into separate storage; reference elements still share their referenced objects.
T[,] / GetLength- One rectangular multidimensional array with a length per dimension.
T[][] / row.Length- An array of row arrays, each with its own length and presence state.
empty guard- Handle the no-data case before first-element reads or division.
Frequently asked questions
Can an array grow after creation?
An individual array instance has a fixed length. A variable can refer to a different array; resizable collection types provide a different abstraction.
Are elements unassigned after new int[3]?
No. The slots start at zero. That does not mean those zeros are real completed scores or valid application records.
Does int[] copy = original make an independent copy?
No. Both variables refer to the same array. Allocate separate storage and copy elements when that is the requirement.
Why use GetLength instead of Length for a grid loop?
Length counts all cells. GetLength(dimension) gives the bound for a particular index dimension.
Is a jagged array always a rectangle?
No. It contains separate row arrays that may have different lengths, be empty, or be absent until initialized.
Should an empty average be zero?
Only if the domain explicitly defines that convention. This lesson reports no data rather than inventing a numeric average for no scores.
Can you explain the storage and shape?
Reason about defaults, references, dimensions and empty sources. Read each explanation after checking your answers.
Next step and references
Arrays have fixed instance sizes, zero-based positions and reference semantics. Check empty sources before calculating, use each rectangular dimension’s bound, and respect the separate shape and presence of jagged rows.
Next is C# Methods and Return Values. You will extract repeated work into named operations, distinguish performing an action from returning a result, and follow control between a caller and a method.
Official references
Original SovranCode explanations, examples and exercises. Technical details were checked against these references.
Last updated: .