Search Forum
(53671 Postings)
Search Site/Articles

Archived Articles
712 Articles

C# Books
C# Consultants
What Is C#?
Download Compiler
Code Archive
Archived Articles
Advertise
Contribute
C# Jobs
Beginners Tutorial
C# Contractors
C# Consulting
Links
C# Manual
Contact Us
Legal

GoDiagram for .NET from Northwoods Software www.nwoods.com


 
Printable Version

Simple, Rectangular, Mixed, and Jagged Arrays, Foreach Loops and Nested For Loops
By Bryan Miller

Welcome to the 8th tutorial in the "C# for the Completely Uninitiated" series..

Source code used in this tutorial:

  • namesarray.cs
  • boundslength.cs
  • deptstore.cs
  • jobcandidates.cs
  • simplenested.cs
  • threed.cs




Single Dimension Arrays

An array is a collection of contiguous storage spaces in memory that are set aside to hold a group of variables of the same type. These individual variables are accessed using the name of the array in conjunction with an index value specifying the offset into the array at which the variable in question is located.

How's that for a mouthful, eh? Arrays can be confusing to the uninitiated. But after a few examples I think you'll have an "Aha!" reaction. Imagine that you are taking a group of kids on a field trip. If this scenario is painfully aversive, then substitute taking a group of cheerleaders to the beach. It is your responsibility to keep track of the names of everyone on the trip, because you have to do a head-count of the bus riders. This is a good time to use an array. Since names are strings of characters, it makes sense that we'd use a string array.

Now, admittedly, you could opt to use a separate string variable for each bus rider, i.e.,



string name1 = "Zoey";
string name2 = "Bryan";
string name3 = "Beth";
string name4 = "Carl";
string name5 = "Glenda";
string name6 = "Eric";
string name7 = "Frank";
string name8 = "Gary";
string name9 = "David";
string name10 = "Hubert";   //Poor guy; imagine how much he got picked on in school...
string name11 = "Helga";    //Probably Hubert's sister and partner in parental misfortune...
string name12 = "Mike";
string name13 = "Sarah";
string name14 = "Allan";

The above code is functional, but it is not smart. The smart thing to do is to use the structure that C# provides for handling this sort of data storage need: the array. To declare a string array and initialize it to contain these names, we'd do the following:



       string[] names = {"Zoey","Bryan","Beth","Carl","Glenda","Eric",
                "Frank","Gary","David","Hubert","Helga","Mike",
                "Sarah","Allan"};

This is an example of a single-dimensional array (you'll learn about multidimensional arrays later). In C#, array indices start at zero. This means that in our names array, the first name, "Zoey", is held in the 0th element of the array. In other words...

Console.Write(names[0]);

...would write the name "Zoey" to the console. What name does names[5] hold? If you said "Eric", you're correct. Now, what I hope you've noticed is that the first name is stored in element 0 of the array. The 3rd name is in element 2, the 6th name is in element 5, etc. Since arrays are zero-based in C#, the nth array item will be in the (n-1)th element.

What if you wanted to write each of these names to the Console? You could type out a total of fourteen Console.WriteLine() statements, but that is laborious. Instead, it would be better to traverse the elements of the array one at a time using a loop. For arrays, we have a special loop called a foreach loop. You can think of it like this: "For each element in the array, do the following..."

The format for a foreach loop is like this:



foreach(type iteration-variable in array_name){
//code that acts on elements of the array goes here 
}

So, for our string array names, we'd use something like the following:



foreach(string name in names){
Console.WriteLine("\t{0}",name); 
}

As far as the compiler is concerned, it doesn't matter what you name the variable that will reference each element of the array as we traverse the array elements using the foreach loop, but it does matter what array name you specify. Your foreach loop must reference an actual array that has been declared and initialized. So, for instance, we could also write:



foreach(string foo in names){
Console.WriteLine("\t{0}",foo); 
}

But we could not do this:



foreach(string foo in foobar){
Console.WriteLine("\t{0}",foo); 
}

That wouldn't compile. It would generate a syntax error because we haven't declared a string array named foobar.

Although you can use any name for the iteration variable, it's a best practice to only name it something meaningful. In the loop shown above, I named my iterator variable name. This makes sense because the array itself is named names. So, in effect foreach(string name in names) is saying "For every name in the list of names..."

If you want to create a fixed-size array without initially assigning any values to it, you can. For example, let's say that I wanted to create an integer array with twenty elements to hold the grades of a classroom of students for a midterm exam. I could create such an array like this:

integer[] MidtermGrades = new int[20];

Another way to do it is in two separate lines of code, like this:


int[] MidtermGrades;
MidtermGrades = new int[20];
Programming Assignment: create a C# console application that initializes a string array to hold the fourteen names used in the field trip example above. After initializing the array, the program should write each array element's value to the console using a foreach loop. Once you've made an honest attempt to do it yourself, you can look here if you need some hints on how to write this program.

Sample output:

In C#, an array is an object, and as you learned in a previous tutorial in this series, to use objects we have to instantiate a particular instance of the object in question. This is what is going on whenever you see the new keyword used in this fashion:

string[] strArray = new string[5] 

In the line of code above, we are instantiating an instance of a string array of fixed length that will have five elements. We could also choose to initialize the array, like so:

string[] strArray = new string[5] { "str1", "str2", "str3", "str4", "str5" };

When initializing an array on the same line as it is declared, you can omit the new keyword and the array type and brackets. This shortened form is equivalent to the line of code shown above:

string[] strArray = {"str1", "str2", "str3", "str4", "str5" };

Here, the C# compiler understands via context that we intend to instantiate a string array instance named strArray. Our assignment of values to the array's elements is what gives the compiler the necessary context for understanding our intent, and makes this shortcut possible. We assigned five strings, so obviously we intended to make this a fixed-length array of five elements.

And speaking of the length of an array, there is an easy way to tell exactly how many elements an array contains. The Array class contains a read-only property named Length. We can examine it anytime we want to know the total number of elements in an array. The GetLowerBound and GetUpperBound methods allow us to determine the index value of the very first array element and the very last array element, respectively. To demonstrate:

This code...


using System;

class Program {
    
    static void Main(string[] args) {

        string[] strArray = { "str1", "str2", "str3", "str4", "str5" };
        int lower = strArray.GetLowerBound(0);
        int upper = strArray.GetUpperBound(0);
        int length = strArray.Length;

        Console.WriteLine("\n\tstring[] strArray = {\"str1\",\"str2\",\"str3\",\"str4\",\"str5\"};\n");

        Console.WriteLine("\tLowerBound = {0}   //strArray[{1}] holds the value \"{2}\"\n",lower,lower,strArray[lower]);
        
        Console.WriteLine("\tUpperBound = {0}   //strArray[{1}] holds the value \"{2}\"\n", upper, upper, strArray[upper]);
        
        Console.WriteLine("\tArray length = {0}    // i.e., there are five total elements (elements 0,1,2,3, and 4)\n", length);

        Console.Write("\tTo exit program, press the Enter key... ");
        Console.ReadLine();
    }

}

produces this output...

 


 


 



 


 


 


Multidimensional (a.k.a. Rectangular) Arrays

Up until now, we've been talking about single dimensional arrays, simple arrays that are useful for things like lists of numbers or strings. Single-dimensional arrays are the essence of simplicity, like a grocery list. Now, however, we're going to turn our attention to multidimensional arrays, sometimes called rectangular arrays.

A multi dimension array is declared as following:

string[,] strArray;
After declaring an array, you can specify the size of array dimensions if you want a fixed size array or dynamic arrays. For example, the following code two examples create two multi dimension arrays with a matrix of 3x2 and 2x2. The next array can store 6 items in groups of two each.


int[,] numbers = new int[3, 2] { {1, 2}, {3, 4}, {5, 6} };

If you don't want to specify the size of arrays, just don't define a number when you call new operator. For example,


int[,] numbers = new int[,] { {1, 2}, {3, 4}, {5, 6} };

You can also omit the new operator as we did in single dimension arrays. You can assign these values directly without using the new operator. For example:


int[,] numbers = { {1, 2}, {3, 4}, {5, 6} };

The most basic multi-dimensional array is an array of an array, also referred to as two-dimensional. To create a two-dimensional array, declare the array variable as we did earlier but add a comma in the square brackets. The formula you would use is:

DataType[,] VariableName; The pair of brackets is empty but must contain a comma. There are two ways you can use a two-dimensional array. If you are declaring the array variable but are not ready to initialize it, use the following formula:

DataType[,] VariableName = new DataType[Number1,Number2]; Based on this, type two integers separated by a comma in the right square brackets. Here is an example:


using System;

namespace CSharpLessons
{
    class Exercise
    {
    static void Main()
    {
        string[,] Members = new string[2,4];
	}
}
In this declaration, the members array variable contains two lists. Each of the two lists contains 4 items. This means that the first list contains 4 items, the second list contains 4 items also. Therefore, the whole list is made of 8 items (2*4=8). Because the variable is declared as a string, each of the 8 items is a string.

You can initialize an array variable when declaring it. To do this, on the right side of the declaration, before the closing semi-colon, type an opening and a closing curly brackets. Inside of the brackets, include a pair of an opening and a closing curly brackets for each internal list of the array. Then, inside of a pair of curly brackets, provide a list of the values of the internal array, just as you would do for a one-dimensional array. Here is an example:


using System;

namespace CSharpLessons
{
    class Exercise
    {
    static void Main()
    {
        string[,] members = new string[2,4]{
	 {"Celeste", "Mathurin", "Alex", "Germain"},
	    {"Jeremy", "Mathew", "Anselme", "Frederique"}
                 };

		     Console.WriteLine();
		     }
}
If you use this technique to initialize an array, you can omit specifying the dimension of the array. Therefore, the array declaration shown above could also be written like this, leaving out "new string [2,4]":


string[,] members = {
  {"Celeste", "Mathurin", "Alex", "Germain"},
     {"Jeremy", "Mathew", "Anselme", "Frederique"}
  };

With two-dimensional arrays, we often need to use nested loops to access all elements. I've covered for loops in the past, but not nested for loops. Let's code a simple example of nested loops in action. The source code shown here will produce the following output, which indicates that the key to nested for loops is that for each iteration of the outer loop, the inner (or nested) loop iterates several times:

Now let's see if we can code a simple example of using nested loops with a rectangular array. Assume that there are three job candidates, and that each candidate has a name, resume, and a personal reference. Create a two-dimensional array to store the following values, and then display those values on the console using a nested for loop:


Mr. Johnson
  - resume #1
  - personal reference #1
Ms. Burton
  - resume #2
  - personal reference #2
Ms. Smith
  - resume #3
  - personal reference #3
Here is the source code that will produce the following output:

Programming Assignment: create a C# console application that creates three separate two-dimensional arrays. Using these three arrays, create data for three womens' clothing articles, and data for three mens' or childrens' clothing items. Use a nested for loop to iterate across every element, printing information from each array to the console. Once you've made an honest attempt to do it yourself, you can look here if you need some hints on how to write this program.

To use the members of a two-dimensional array, you can access each item individually. For example, to initialize a two-dimensional array, you can access each member of the array and assign it a value. The external list is zero-based. In other words, the first list has an index of 0, the second list has an index of 1. Internally, each list is zero-based and behaves exactly like a one-dimensional array. To access a member of the list, type the name of the variable followed by its square brackets. In the brackets, type the index of the list, a comma, and the internal index of the member whose access you need. Here is an example:



using System;

namespace CSharpLessons
{
    class Exercise
    {
    static void Main()
    {
        String[,] members = new String[2,4];

             members[0,0] = "Celeste";
             members[0,1] = "Mathurin";
	          members[0,2] = "Alex";
		       members[0,3] = "Germain";
		            members[1,0] = "Jeremy";
			         members[1,1] = "Mathew";
             members[1,2] = "Anselme";
             members[1,3] = "Frederique";

             Console.WriteLine();
	     }
}

Here's an example of a three-dimensional array.

Note to reader: you may have noticed that I use a lot of tab and newline escape characters in my Console.WriteLine() invocations. This is merely a personal preference. I do it to offset the console output away from the top and left edges of the console window. It's not necessary to do this.  


 


 



 


 


 


Jagged and Mixed Arrays

With a rectangular array, i.e., a multidimensional array, it's possible to calculate exactly how many elements the entire array contains. For example, the following two arrays contains 20 elements and 70 elements, respectively:



int[,] MyIntArray = new int[5, 4];            //this is a two-dimensional array

int[, ,] My3DArray = new int[2, 7, 5];        //this is a three-dimensional array

By contrast, a jagged array's total number of elements cannot be calculated as easily. A jagged array is an array of arrays. Unlike the two multidimensional arrays shown above, the following array, which is a jagged array, has only one dimension. However, this one-dimensional array has three elements, and each of those elements is itself a single-dimensional array of integers:

int[][] jaggedArray = new int[3][];

Before you can make use of a jagged array, you have to initialize its elements. This could be done like this:



jaggedArray[0] = new int[5];
jaggedArray[1] = new int[4];
jaggedArray[2] = new int[2];

Each of the elements is a single-dimensional array of integers. The first element is an array of 5 integers, the second is an array of 4 integers, and the third is an array of 2 integers. It is also possible to use initializers to fill the array elements with values, in which case you do not need the array size. For example:



jaggedArray[0] = new int[] { 1, 3, 5, 7, 9 };
jaggedArray[1] = new int[] { 0, 2, 4, 6 };
jaggedArray[2] = new int[] { 11, 22 };

And here is another way we could initialize this jagged array. Here, we perform the initialization in tandem with the array declaration:



int[][] jaggedArray = new int[][] 
{
    new int[] {1,3,5,7,9},
    new int[] {0,2,4,6},
    new int[] {11,22}
};

How would you make an assignment to replace the 11 in the third element above with the value 25?

Answer: well, 11 is the first element of the third array, so our code would be jaggedArrray[2][0];

Notice that, unlike with simple and multidimensional arrays, you cannot omit the new keyword from the elements' initialization in a jagged array, because there is no default initialization for the elements. Why, you ask? Well, recall that the elements of a jagged array are themselves arrays. In C#, arrays are a reference type, and we have to instantiate instances of objects using the new keyword.

It is possible to mix jagged and multidimensional arrays. The following is a declaration and initialization of a single-dimensional jagged array that contains two-dimensional array elements of different sizes:



int[][,] jaggedArray4 = new int[3][,] 
{
    new int[,] { {1,3}, {5,7} },
    new int[,] { {0,2}, {4,6}, {8,10} },
    new int[,] { {11,22}, {99,88}, {0,9} } 
};

To my mind, however, when your data structure is so complex as to require such a mixed array, it's time to refactor your code so that data can be handled by special hand-crafted classes, whose properties can be laid out in such a way that storing data in the properties of instances of those classes is more intuitive.

As a closing note, let me say that, for many people, arrays are mind-boggling. It can take repeated exposure to arrays, over a considerable period of time, before you begin to "get it". If you find yourself struggling to wrap your mind around two-dimensional (or even simple) arrays, don't force yourself to press onward and tackle jagged and mixed arrays. You have to have a foundation to build upon. Continue to seek out examples of simpler arrays, and practice manipulating them with for loops, or nested for loops.




Well, I hope that you've benefited, at least a little, from this tutorial. As ever, I welcome any feedback you may wish to impart.