Рассмотрим, как объявляются одномерные массивы, массивы массивов и многомерные массивы.
Напомню общую структуру объявления:
[<атрибуты>] [<модификаторы>] <тип> <объявители>;
Забудем пока об атрибутах и модификаторах. Объявление одномерного массива выглядит следующим образом:
<тип>[] <объявители>;
Заметьте, в отличие от языка C++ квадратные скобки приписаны не к имени переменной, а к типу. Они являются неотъемлемой частью определения типа, так что запись T[] следует понимать как тип, задающий одномерный массив с элементами типа T.
Что же касается границ изменения индексов, то эта характеристика не является принадлежностью типа, она является характеристикой переменных данного типа - экземпляров, каждый из которых является одномерным массивом со своим числом элементов, задаваемых в объявителе переменной.
Как и в случае объявления простых переменных, каждый объявитель может быть именем или именем с инициализацией. В первом случае речь идет об отложенной инициализации. Нужно понимать, что при объявлении с отложенной инициализацией сам массив не формируется, а создается только ссылка на массив, имеющая неопределенное значение. Поэтому пока массив не будет реально создан и его элементы инициализированы, использовать его в вычислениях нельзя. Вот пример объявления трех массивов с отложенной инициализацией:
int[] a, b, c;
Чаще всего при объявлении массива используется имя с инициализацией. И опять-таки, как и в случае простых переменных, могут быть два варианта инициализации. В первом случае инициализация является явной и задается константным массивом. Вот пример:
double[] x= {5.5, 6.6, 7.7};
Следуя синтаксису, элементы константного массива необходимо заключать в фигурные скобки.
Во втором случае создание и инициализация массива выполняется в объектном стиле с вызовом конструктора массива. И это наиболее распространенная практика объявления массивов. Приведу пример:
int[] d= new int[5];
Итак, если массив объявляется без инициализации, то создается только висячая ссылка со значением void. Если инициализация выполняется конструктором, то в динамической памяти создается сам массив, элементы которого инициализируются константами соответствующего типа (ноль для арифметики, пустая строка для строковых массивов), и ссылка связывается с этим массивом. Если массив инициализируется константным массивом, то в памяти создается константный массив, с которым и связывается ссылка.
Как обычно задаются элементы массива, если они не заданы при инициализации? Они либо вычисляются, либо вводятся пользователем. Давайте рассмотрим первый пример работы с массивами из проекта с именем Arrays, поддерживающего эту лекцию:
public void TestDeclaration() { //объявляются три одномерных массива A,B,C int[] A = new int[5], B= new int[5], C= new int[5]; Arrs.CreateOneDimAr(A); Arrs.CreateOneDimAr(B); for(int i = 0; i<5; i++) C[i] = A[i] + B[i]; //объявление массива с явной инициализацией int[] x ={5,5,6,6,7,7}; //объявление массивов с отложенной инициализацией int[] u,v; u = new int[3]; for(int i=0; i<3; i++) u[i] =i+1; // v = {1,2,3}; //присваивание константного массива недопустимо v = new int[4]; v = u; //допустимое присваивание Arrs.PrintAr1("A", A); Arrs.PrintAr1("B", B); Arrs.PrintAr1("C", C); Arrs.PrintAr1("X", x); Arrs.PrintAr1("U", u); Arrs.PrintAr1("V", v); }
На что следует обратить внимание, анализируя этот текст?
В процедуре показаны разные способы объявления массивов. Вначале объявляются одномерные массивы A, B и C, создаваемые конструктором. Значения элементов этих трех массивов имеют один и тот же тип int. То, что они имеют одинаковое число элементов, произошло по воле программиста, а не диктовалось требованиями языка. Заметьте, что после такого объявления с инициализацией конструктором все элементы имеют значение, в данном случае - ноль, и могут участвовать в вычислениях.
Массив x объявлен с явной инициализацией. Число и значения его элементов определяется константным массивом.
Массивы u и v объявлены с отложенной инициализацией. В последующих операторах массив u инициализируется в объектном стиле, его элементы получают в цикле значения.
Обратите внимание на закомментированный оператор присваивания. В отличие от инициализации использовать константный массив в правой части оператора присваивания недопустимо. Эта попытка приводит к ошибке, поскольку v - это ссылка, которой можно присвоить ссылку, но нельзя присвоить константный массив. Ссылку присвоить можно. Что происходит в операторе присваивания v = u.? Это корректное ссылочное присваивание: хотя u и v имеют разное число элементов, но они являются объектами одного класса. В результате присваивания память, отведенная массиву v, освободится, ей займется теперь сборщик мусора. Обе ссылки u и v будут теперь указывать на один и тот же массив, так что изменение элемента одного массива немедленно отражается на другом массиве.
Для поддержки работы с массивами создан специальный класс Arrs, статические методы которого выполняют различные операции над массивами. В частности, в примере использованы два метода этого класса, один из которых заполняет массив случайными числами, второй - выводит массив на печать.
Вот текст первого из этих методов:
public static void CreateOneDimAr(int[] A) { for(int i = 0; i<A.GetLength(0);i++) A[i] = rnd.Next(1,100); }//CreateOneDimAr
Здесь rnd - это статическое поле класса Arrs, объявленное следующим образом:
private static Random rnd = new Random();
Процедура печати массива с именем name выглядит так:
public static void PrintAr1(string name,int[] A) { Console.WriteLine(name); for(int i = 0; i<A.GetLength(0);i++) Console.Write("\t" + name + "[{0}]={1}", i, A[i]); Console.WriteLine(); }//PrintAr1
На рис. 6.1 показан консольный вывод результатов работы процедуры TestDeclarations:
Рис. 6.1. Результаты объявления и создания массивов
Особое внимание обратите на вывод, связанный с массивами u и v.