|
An
array is a collection of similar data types stored in adjacent
memory locations. Though the syntax of declaring and using
a C# array is more or less similar to that of C/C++, they
are actually created as objects of the System.Array class.
Hence arrays in C# fall in the category of reference types.
Like any other reference type, an array object refers to a
memory space allocated on the heap. Following code fragment
shows how to declare and initialise an array.
int[ ] a, b ;
a = new int [ 10 ] ;
b = new int [ ] { 0, 1, 2, 3, 4 } ;
foreach ( int i in b )
Console.WriteLine ( i ) ;
The first statement merely sets aside space for references
to arrays. The second and third statement allocates memory
for ten and five integers respectively. The references of
arrays created in the heap are stored in a and b. Note that
though the array gets allocated on the heap, the references
a and b are created on the stack.
The foreach loop iterates through the array and extracts one
element at a time from the array. We can also use the subscript
notation to access the array elements. Like C/C++, C# too
uses zero-based index to access array elements. All the array
elements are set to a default value 0 unless we initialise
them. However, if we create an array of reference types, the
array elements are set to null. Here is an example that creates
an array of objects of a class sample.
sample[ ] s = new sample [ 5 ] ;
Here s is a reference to an array. Each element of the array
in itself is a reference to the sample object.
Array Bounds Checking
In C# checking the array bounds is not the programmer's responsibility.
If the array bounds are exceeded, the .NET runtime informs
the application about it by throwing an exception. An exception
is a runtime error caused by fatal errors like array bounds
out of range, using an invalid reference, etc. Thus, following
code would never work in C#.
int[ ] a = { 1, 2, 3, 4 } ;
a [ 4 ] = 10 ;
Although compiler would not report any error .NET runtime
would throw an exception.
Passing an array to a method
As said earlier, an array is implemented as an object. Hence,
when we pass an array to a method, only its reference gets
passed to the method. Here is the program that shows how to
pass an array to a method.
using System ;
namespace arraytofunc
{
class Class1
{
static void Main ( string[ ] args )
{
int[ ] a = { 1, 2, 3, 4, 5 } ;
print ( a ) ;
Console.WriteLine ( Elements of a ) ;
for ( int i = 0 ; i < a.Length ; i++ )
Console.Write ( a [ i ] ) ;
}
static void change ( int[ ] b )
{
for ( int i = 0 ; i < b.Length ; i++ )
b [ i ] = b [ i ] + 5 ;
}
}
}
In Main( ), we have created a 1-D array referred to by a and
passed a to the change( ) method. In change( ) method we have
collected it in another reference b. Now, both a and b are
referring to the same memory. Next, we have incremented the
values of array by 5. Since b refers to the same array which
a is referring to, changes made to array elements in change(
) get reflected in Main( ) as well. If we display the elements
of array using the reference a it displays the modified elements,
6 7 8 9 10
Apart from single dimension array, C# provides multidimensional
arrays, also called rectangular arrays and jagged arrays.
This is how we can declare a 2D array.
int [ , ] arr1 = new int [ 4, 4 ] ;
arr1 = new int [ 4, 4 ] ;
int [ , ] arr2 = { { 3, 5, 7, 9 }, { 11, 13, 15, 17 } } ;
We can access elements of arr1 as arr1[0, 0].
A jagged array is an array of arrays. When we declare a jagged
array, we specify number of rows. Each row holds an array,
which can be of different length. Following statements show
how to declare and initialise a jagged array.
int [ ] [ ] arr1 = new int [ 2 ] [ ] ; // array of 2 arrays
arr1 [ 0 ] = new int [ 3 ] ; // first array has 3 elements
arr1 [ 1 ] = new int [ 2 ] ; // second array has 2 elements
We can access elements of arr1 as arr1[0][0], arr1[0][1],
etc.
The System.Array class provides number of methods for array
manipulation. A few of them are used below.
int[ ] arr1 = new int [ 5 ] { 1, 4, 7, 8, 9 } ;
int[ ] arr2 = new int [ 10 ] ;
arr2.SetValue ( 5, 0 ) ;
Console.WriteLine ( "Number of elements in arr1:" + arr1.Length ) ;
Array.Copy ( arr1, 2, arr2, 6, 2 ) ;
Array.Reverse ( arr2 ) ;
Array.Sort ( arr2 ) ;
The SetValue( ) method sets the value 5 at 0th location in
arr2. Length is a property of Array class that returns number
of elements in the array. The Copy( ), Reverse( ) and Sort(
) methods copy, reverse and sort the array elements.
Strings
C# has provided a built-in data type string to hold the sequence
of Unicode characters. The string data type is mapped to the
System.String class. So, a string is represented as an object
rather than an array of characters. When we create a string
through the statement,
string s = Hello;
a reference s gets created on the stack. An object of type
String gets created on heap with memory required to hold the
string Hello. The object gets initialised with
the string Hello. The reference s then starts
referring to this object.
Strings in C# are more sophisticated, powerful and easy to
use. The following statements would prove this.
string s1 = True Rural Ruler;
s1 += Is A Truly Rural Ruler;
for ( int i = 0 ; i < s1.Length ; i++ )
Console.Write ( s1 [ i ] ) ;
To concatenate two strings we are no longer required to use
standard library functions like strcat( ). We can do this
by using a more familiar and convenient syntax. At the same
time, we can continue using the native syntax like s1[i] to
access the individual character in the string.
Strings are immutable. What this means is that once initialised,
strings cannot be changed. So, when we try to change the string,
changes do not take place in the same object but a new object
of type String gets created with the new, changed string.
The string reference then starts referring to this new object.
For example, in the above code, when we concatenate strings,
a new object that is capable of holding the concatenated string
gets created.
The reference s1 then starts referring to this object. The
memory allocated for the first object becomes unreferenced,
which then gets collected by the Garbage Collector.
Suppose we create two strings having exactly same literal
as shown below.
string s1 = hi there! ;
string s2 = hi there! ;
Here, two different objects would not get created. Only one
object with string hi there! would get created
and both the references s1 and s2 would refer to that object.
As soon as we assign a different string constant to any of
the references it will start referring to different object.
The StringBuilder Class
Creating a new object every time we change the string sounds
reasonable if our program deals with strings having moderate
length. But if the program extensively performs text processing,
then this may affect the performance of the program as there
may be a number of unreferenced objects on the heap waiting
to be collected by the Garbage Collector. Hence .NET has provided
another class named StringBuilder to cope with this problem.
Although StringBuilder does not provide as much functionality
as the String class, it certainly provides methods for the
most common operations. To be able to use StringBuilder class
we must import classes of System.Text namespace.
 |
Yashavant
Kanetkar, one of the first Express Computer columnists,
is an established software expert, speaker and author
with several best-sellers to his credit, including titles
like “Let Us C” and the “Fundas” series. Contact him at
kanet@nagpur.dot.net.in |
|