Массивом называют упорядоченную совокупность элементов одного типа. Число индексов характеризует размерность массива. При объявлении массива границы задаются выражениями. Если все границы заданы константами, то такие массивы называются статическими. Если же выражения, задающие границы, зависят от переменных, то такие массивы называются динамическими, память им отводится в процессе выполнения программы.
В языке C# имеются одномерные массивы, массивы массивов и многомерные ступенчатые массивы.
Определение одномерных массивов:
int[] k; //k - одномерный массив
k=new int [3]; //Определяем массив из трех целых
k[0]=-5; k[1]=4; k[2]=55; //Задаем элементы массива
Элементы массива можно задавать сразу при объявлении: int[] k = {-5, 4, 55};
Создание динамического массива: Console.WriteLine("Введите число элементов массива "); int size = Int32.Parse(Console.ReadLine()); int[] A1 = new int[size]; //создание динамического массива
Определение многомерных массивов:
int[,] k - new int [2,3];
Обратите внимение, что пара квадратных скобок только одна. Аналогично можно задавать многомерные массивы. Вот пример трехмерного массива:
int[,,] k = new int [10,10,10];
Многомерные массивы можно сразу инициализировать: int[,] k = {{2,-2},{3,-22},{0,4}};
Определение ступенчатых массивов:
int[][] k = new int [2][]; //Объявляем второй ступенчатый массив
k[0]-new int[3]; //Определяем нулевой элемент
k[1]-new int[4]; //Определяем первый элемент
k[1][3]-22; //записываем 22 в последний элемент
Обратите внимание, что у ступенчатых массивов задается несколько пар квадратных скобок (столько, сколько размерностей у массива), табл. 5.1.
Массив имеет два уровня. Можно считать, что у него три элемента, каждый из которых является массивом. Для каждого внутреннего массива необходимо вызвать конструктор new.
Базовый класс System.Array
Все классы-массивы являются потомками класса Array из библиотеки FCL. Класс имеет большое число методов и свойств (табл. 5.2, 5,3). Благодаря такому родителю над массивами определены самые разнообразные операции - копирование, поиск, обращение, сортировка, получение различных характеристик. Массивы можно рассматривать как коллекции и устраивать циклы foreach для перебора всех элементов.
Т аб ли ца 5.2
Т аб ли ца 5.3
Статические методы класса Array
Метод | Описание |
BinarySearch() | Двоичный поиск |
Clear() | Выполняет начальную инициализацию элементов в зависимости от типа: 0 - для арифметического типа, false - для логического типа, null - для ссылок, "" - для строк |
CopyTo() | Копирование части или всего массива в другой массив. Описание и примеры даны в тексте |
GetLength() | Используется для определения количества элементов в указанном измерении массива |
IndexOf() | Индекс первого вхождения образца в массив. Описание и примеры даны в тексте |
LastIndexOf() | Индекс последнего вхождения образца в массив. Описание и примеры даны в тексте |
Reverse() | Обращение одномерного массива |
Программа 1. Применение методов класса Array public static int Main(string[] args) {
string[]firstNames={мСашам, "Маша", "Олег", "Света", "Игорь"}; Console.WriteLine("Here is the array:"); for(int i=0; i< firstNames.Length;
Console.WriteLine(firstNames[i]+"\t"); Console.WriteLine("\n"); Array.Reverse(firstNames); for(int i=0; i< firstNames.Length;
Console.WriteLine(firstNames[i]+"\t");
Console.WriteLine("\n");
Console.WriteLine("Cleared out all but one...");
Array.Clear(firstNames,1,4);
for(int i=0; i< firstNames.Length; i++)
Console.WriteLine(firstNames[i]+"\t\n"); return 0;
}
В процедуре PrintAr формальный аргумент класса Array, следовательно, можно передавать массив любого класса в качестве фактического аргумента
Программа 2. Примение методов класса Array public static void PrintAr(string name, Array A) { Console.WriteLine(name); switch (A.Rank) {
case 1:
for(int i = 0; i<A.GetLength(0);i++)
Console.Write("\t" + name + "[{0}]={1}", i, A.GetValue(i)); Console.WriteLine(); break;
case 2:
for(int i = 0; i<A.GetLength(0);i++) { for(int j = 0; j<A.GetLength(1);j++) Console.Write("\t" + name + "[{0},{1}]={2}", A.GetValue(i,j));
Console.WriteLine();
}
break; default: break;
}
}
Последовательность элементов – a1, a2, …. an – одна из любимых структур в математике. Последовательность можно рассматривать как функцию a(i), которая по заданному значению индекса элемента возвращает его значение. Эта функция задает отображение integer -> T, где T – это тип элементов последовательности.
В программировании последовательности называются массивами, но от этого они не перестают быть менее любимыми. Массив – это упорядоченная последовательность элементов одного типа. Порядок элементов задается с помощью индексов.
Для программистов важно то, как массивы хранятся в памяти. Массивы занимают непрерывную область памяти, поэтому, зная адрес начального элемента массива, зная, сколько байтов памяти требуется для хранения одного элемента, и, зная индекс (индексы) некоторого элемента, нетрудно вычислить его адрес, а значит и хранимое по этому адресу значение элемента. На этом основана адресная арифметика в языках C, C++, где адрес элемента a(i) задается адресным выражением a+i, в котором имя массива a воспринимается как адрес первого элемента. При вычислении адреса i-го элемента индекс i умножается на длину слова, требуемого для хранения элементов типа T. Адресная арифметика приводит к 0-базируемости элементов массива, когда индекс первого элемента равен нулю, поскольку первому элементу соответствует адресное выражение а+0.
Язык C# сохранил 0-базируемость массивов. Индексы элементов массива в языке C# изменяются в плотном интервале значений от нижней границы, всегда равной 0, до верхней границы, заданной динамически вычисляемым выражением, возможно зависящим от переменных. Массивы C# являются 0-базируемыми динамическими массивами. Это важно понимать с самого начала.
Не менее важно понимать и то, что массивы C# относятся к ссылочным типам. Рассмотрим следующий фрагмент программного кода:
int[] x, y = {1, 2, 3};
double[] z;
int[,] u, v = {{1,3,5},{2,4,6}};
Здесь объявлены пять переменных – x, y, z, u, v. Все они являются массивами, но разных типов. Переменные x и y принадлежат типу T = int[], задающему одномерные массивы с элементами целого типа int. Переменные u и v принадлежат другому типу T1 = int[,]- двумерных массивов с элементами целого типа. Переменная z принадлежит типу T3 –одномерных массивов с элементами вещественного типа double. Все три типа массивов – T1, T2, T3 являются наследниками общего родителя – типа (класса) Array, наследуя от родителя многие полезные свойства и методы. Все пять переменных являются типизированными ссылками. В момент объявления три переменные – x, z и u не инициализированы и потому являются «висячими» ссылками со значением null. Переменные y и v объявлены с инициализацией. При инициализации в динамической памяти создаются два объекта соответственно типов T1 и T3, фактически и задающие реальные массивы. У первого из этих объектов 3 элемента, у второго - 6. Ссылки y и v связываются с этими объектами. При связывании тип ссылки и тип объекта должны быть согласованными. Заметьте, число элементов в массиве является характеристикой объекта, а не типа. Ссылка может быть связана с объектами, содержащими различное число элементов, необходимо лишь выполнение условия согласования типов.
Дополним код следующими строчками:
x = new int[10];
z = new double[20];
u = new int[3, 5];
Здесь последовательно вызываются три конструктора типов T1, T2, T3, создающие новые три объекта в памяти и ссылки x, y, z связываются с этими объектами, так что у массива x теперь 10 элементов, z – 20, u -15.
Рассмотрим, что произойдет в результате присваивания:
x = y;
u = v;
Присваивание законно, поскольку переменные в левой и правой части имеют один и тот же (следовательно, согласованный) тип. В результате присваивания переменные порвут связь с теми объектами, с которыми они были связаны, и будут связаны с новыми объектами, так что x теперь имеет 3 элемента, u – 6.