Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛР №3.doc
Скачиваний:
2
Добавлен:
28.09.2019
Размер:
312.32 Кб
Скачать

Лабораторная работа № 3 массиВы

1. Цель и задачи работы

Целью работы является изучение студентами приемов работы с массивами, а также особенностей их использования.

Задачами работы являются:

  • изучение приведенных примеров использования массивов;

  • разработка блок-схем алгоритмов обработки массивов с последующей их программной реализацией.

2. Теоретические сведения

При разработке программ часто используются массивы – упорядоченные наборы однотипных значений. Для массивов характерно следующее:

  • все элементы массива имеют общий тип и индекс – порядковый номер элемента в массиве, начиная с 0;

  • обращение к элементам массива происходит по общему имени (имени массива) с указанием индекса элемента массива;

  • в массиве поддерживается произвольный доступ к любому элементу.

Массивы представляют собой удобное средство группирования связанных переменных, они организованы таким способом, который позволяет легко ими манипулировать, например, сортировать в нужном направлении.

Хотя массивы в С# можно использовать по аналогии с тем, как они используются в других языках программирования, однако С#-массивы реализованы как объекты.

Примечание: Понятие “объект” рассматривается в рамках объектно-ориентированного программирования.

Различают одномерные массивы и многомерные. Для доступа к одномерному массиву используется один индекс, а для многомерного – два и более. Для объявления одномерного массива используется следующая конструкция:

тип[] имя_массива = new тип [размер];

Здесь с помощью элемента тип объявляется базовый тип массива. Базовый тип определяет тип данных каждого элемента, составляющего массив. Обратите внимание на одну пару квадратных скобок за элементом записи тип. Это означает, что определяется одномерный массив. Количество элементов, которые будут храниться в массиве, определяется элементом размер. Поскольку массивы реализуются как объекты, их создание представляет собой двухступенчатый процесс. Сначала объявляется ссылочная переменная на массив, а затем для него выделяется память, и переменной массива присваивается ссылка на эту область памяти. Таким образом, в С# массивы динамически размещаются в памяти с помощью оператора new.

В следующем примере показано объявление одномерного массива и его заполнение (фактически инициализация его элементов) в цикле for.

//Объявление одномерного массива

//типа int с 10 элементами

int[] sample=new int [10];

//Заполнение массива в цикле от 0 до 9

//значениями счетчика цикла i

for (int i = 0; i < 10; i++) sample[i] = i;

Этот же массив может быть заполнен иначе:

//Заполнение массива с помощью

//10 инструкций присванивания

sample[0] = 0;

sample[1] = 1;

sample[2] = 2;

sample[3] = 3;

sample[4] = 4;

sample[5] = 5;

sample[6] = 6;

sample[7] = 7;

sample[8] = 8;

sample[9] = 9;

Существует более простой путь достижения той же цели: массивы можно инициализировать в момент их создания. Формат инициализации одномерного массива имеет следующий вид:

тип[] имя_массива = {значение1, значение2, ... , значениеN};

Здесь начальные значения, присваиваемые элементам массива, задаются с помощью последовательности значение1, значение2, ... , значениеN. Значения присваиваются слева направо, в порядке возрастания индекса элементов массива. С# автоматически выделяет для массива область памяти достаточно большого размера, чтобы хранить заданные значения инициализации (инициализаторы). В этом случае нет необходимости использовать в явном виде оператор new. Например:

int[] sample ={0,1,2,3,4,5,6,7,8,9};

При использовании массивов необходимо соблюдать “граничный режим” – индексы массива не могут быть меньше 0 и больше количества элементов массива – 1.

Рассмотрим теперь многомерные массивы. Простейший многомерный массив – двумерный, в котором позиция любого элемента определяется двумя индексами. Если представить двумерный массив в виде таблицы, то один индекс означает строку, а второй – столбец.

Для объявления двумерного массива используется следующая конструкция:

тип[,] имя_массива = new тип [размер1, размер2];

В следующем примере показано объявление двумерного массива и его заполнение.

//Объявление двумерного массива

//типа int с 10 строками и 10 столбцами

int[,] sample_2dem =new int[10,10];

//Заполнение массива в цикле от 0 до 9

//c вложенным циклом от 0 до 9

//значениями суммы счетчиков внешнего цикла i и внутреннего цикла j

for (int i = 0; i < 10; i++)

{

for (int j = 0; j < 10; j++) sample_2dem[i, j] = i + j;

}

В этом примере мы создали двумерный массив, который в С# называется прямоугольным. Если двумерный массив можно представить в виде таблицы, то прямоугольный массив можно определить как массив, строки которого имеют одинаковую длину. Однако С# позволяет создавать двумерный массив специального типа, именуемый рваным, или с рваными краями. У такого массива строки могут иметь различную длину. Следовательно, рваный массив можно использовать для создания таблицы со строками разной длины.

Рваные массивы объявляются с помощью наборов квадратных скобок, обозначающих размерности массива. Например, чтобы объявить двумерный рваный массив, используется следующий формат записи:

тип[][] имя = new тип[размер][];

Здесь элемент размер означает количество строк в массиве. Для самих строк память выделяется индивидуально, что позволяет строкам иметь разную длину. Например, следующий фрагмент программы при объявлении массива выделяет память для его первой размерности, а память для его второй размерности выделяется “вручную”.

int[][] sample3 = new int[3][];

sample3[0] = new int[3];

sample3[1] = new int[4];

sample3[2] = new int[5];

После создания рваного массива доступ к элементу осуществляется посредством задания индекса внутри собственного набора квадратных скобок. Например, чтобы присвоить число 10 элементу массива sample3 с индексами 2 и 1, используется такая инструкция:

sample3[2][1] = 10;

Обратите внимание на то, что этот синтаксис отличается от того, который используется для доступа к элементам прямоугольного массива.

Поскольку рваные массивы – это по сути массивы массивов, то совсем не обязательно, чтобы “внутренние” массивы имели одинаковый тип. Например, эта инструкция создает массив двумерных массивов:

int[][,] sample4 = new int[3][,];

А эта инструкция присваивает элементу sample4[0] ссылку на массив размером 4x2:

sample4[0] = new int[4, 2];

Следующая инструкция присваивает значение переменной i элементу sample4[0][1,0]:

sample4[0][1,0] = i;

С каждым массивом в C# связано свойство Length, содержащее количество элементов, которое может хранить массив. Использование этого свойства демонстрируется в следующей программе.

//Объявление массива типа int

int[] sample5 =new int[10];

//Заполнение массива в цикле от 0 до sample5.Length-1

for (int i = 0; i < sample5.Length; i++) sample5[i] = i*2;

Обратите внимание на то, как цикл for использует свойство sample5.Length для управления количеством итераций. Поскольку каждый массив сопровождается информацией о собственной длине, можно использовать эту информацию, а не вручную отслеживать размер массива. При этом следует иметь в виду, что свойство Length никак не связано с реально используемым количеством элементов массива. Оно содержит количество элементов, которое массив способен хранить.

При получении длины многомерного массива возвращается общее количество элементов, обусловленное “врожденной” способностью массива хранить данные.

При работе с рваными массивами использование свойства Length приобретает особое значение, поскольку позволяет получить длину каждого отдельного (“строчного”) массива.

Рассмотрим, например, следующую программу, которая имитирует работу центрального процессора (ЦП) в сети с четырьмя узлами.

int[][] network_nodes = new int[4][];

network_nodes[0] = new int[3];

network_nodes [1] = new int [7];

network_nodes [2] = new int[2];

network_nodes[3] = new int[5];

int i,j;

// Создаем фиктивные данные по использованию ЦП

for (i = 0; i < network_nodes.Length; i++)

for (j = 0; j < network_nodes[i].Length; j++)

network_nodes[i][j] = i * j + 70;

Console.WriteLine("Общее количество сетевых узлов: " +

network_nodes.Length + "\n");

for (i = 0; i < network_nodes.Length; i++)

for (j = 0; j < network_nodes[i].Length; j++)

{

Console.Write("Использование ЦП на узле " + i +

" для ЦП " + j + ":");

Console.Write(network_nodes[i][j] + "% ");

Console.WriteLine();

}

Console.WriteLine();

Console.ReadLine();

Результаты выполнения этой программы выглядят так:

Рисунок 1  Результаты выполнения программы, имитирующей работу ЦП

Обратите внимание на то, как свойство Length используется для рваного массива network_nodes: выражение network_nodes.Length возвращает количество массивов, хранимых в массиве network_nodes (в данном случае это значение равно 4), а чтобы получить длину отдельного массива во “внешнем” рваном массиве, используется выражение network_nodes[i].Length.

Как демонстрировалось в примерах, при работе с массивами часто используется цикл for. Между тем, весьма полезным может быть цикл foreach, который используется для опроса элементов коллекции  группы объектов. С# определяет несколько типов коллекций, и одним из них является массив. Формат записи цикла f oreach имеет такой вид:

foreach (тип имя_переменной in коллекция) инструкция;

Здесь элементы тип и имя_переменной задают тип и имя итерационной переменной, которая при функционировании цикла fоreach будет получать значения элементов из коллекции. Элемент коллекция служит для указания опрашиваемой коллекции (в данном случае в качестве коллекции мы рассматриваем массив). Таким образом, элемент тип должен совпадать (или быть совместимым) с базовым типом массива. Здесь важно запомнить, что итерационную переменную применительно к массиву можно использовать только для чтения. Следовательно, невозможно изменить содержимое массива, присвоив итерационной переменной новое значение.

Рассмотрим простой пример использования цикла foreach. Приведенная ниже программа создает массив для хранения целых чисел и присваивает его элементам начальные значения. Затем она отображает элементы массива.

Random ran = new Random();

int[] arr = new int[10];

for (int i = 0; i < arr.Length; i++)

//Массив заполняется случайными числами

arr[i] = ran.Next(1,10);

//Цикл foreach используется для отображения

//элементов массива

foreach (int i in arr)

Console.Write(i + " ");

Как видно из примера, цикл foreach последовательно опрашивает элементы массива в направлении от наименьшего индекса к наибольшему. Несмотря на то что цикл foreach работает до тех пор, пока не будут опрошены все элементы массива, существует возможность досрочного его останова с помощью инструкции break.

Цикл foreach работает и с многомерными массивами. В этом случае он возвращает элементы в порядке следования строк: от первой до последней.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]