"Сокрытие деталей реализации называется инкапсуляцией (от слова "капсула"). " Сколько можно объяснять?! ИНКАПСУЛЯЦИЯ НЕ РАВНА СОКРЫТИЮ!!! Инкапсуляция это парадигма ООП, которая ОБЕСПЕЧИВАЕТ СОКРЫТИЕ!!! НО СОКРЫТИЕМ НЕ ЯВЛЯЕТСЯ!!! Если буровая коронка обеспечивает разрушение породы, то является ли она сама разрушением породы? Конечно нет! |
Массивы, символы и строки
Прямоугольные массивы
Прямоугольный массив имеет более одного измерения. Чаще всего в программах используются двумерные массивы. Варианты описания двумерного массива:
тип[,] имя; тип[,] имя = new тип [ разм_1, разм_2 ]; тип[,] имя = { список_инициализаторов }; тип[,] имя = new тип [,] { список_инициализаторов }; тип[,] имя = new тип [ разм_1, разм_2 ] { список_инициализаторов };
Примеры описаний (один пример на каждый вариант описания):
int[,] a; // 1 элементов нет int[,] b = new int[2, 3]; // 2 элементы равны 0 int[,] c = {{1, 2, 3}, {4, 5, 6}}; // 3 new подразумевается int[,] c = new int[,] {{1, 2, 3}, {4, 5, 6}}; // 4 размерность вычисляется int[,] d = new int[2,3] {{1, 2, 3}, {4, 5, 6}};// 5 избыточное описание
К элементу двумерного массива обращаются, указывая номера строки и столбца, на пересечении которых он расположен, например:
a[1, 4] b[i, j] b[j, i]
Внимание
Необходимо помнить, что компилятор воспринимает как номер строки первый индекс, как бы он ни был обозначен в программе.
В качестве примера рассмотрим программу, которая для целочисленной матрицы размером 3 x 4 определяет среднее арифметическое ее элементов и количество положительных элементов в каждой строке.
Для нахождения среднего арифметического элементов массива требуется найти их общую сумму, после чего разделить ее на количество элементов. Порядок перебора элементов массива (по строкам или по столбцам) роли не играет. Нахождение количества положительных элементов каждой строки требует просмотра матрицы по строкам. Схема алгоритма приведена на рис. 6.3, программа — в листинге 6.2.
using System; namespace ConsoleApplication1 { class Class1 { static void Main() { const int m = 3, n = 4; int[,] a = new int[m, n] { { 2,-2, 8, 9 }, {-4,-5, 6,-2 }, { 7, 0, 1, 1 } }; Console.WriteLine( "Исходный массив:" ); for ( int i = 0; i < m; ++i ) { for ( int j = 0; j < n; ++j ) Console.Write( "\t" + a[i, j] ); Console.WriteLine(); } double sum = 0; int nPosEl; for ( int i = 0; i < m; ++i ) { nPosEl = 0; for ( int j = 0; j < n; ++j ) { sum += a[i, j]; if ( a[i, j] > 0 ) ++nPosEl; } Console.WriteLine( "В строке {0} {1} положит-х элементов", i, nPosEl ); } Console.WriteLine( "Среднее арифметическое всех элементов: " + sum / m / n ); } } }Листинг 6.2. Работа с двумерным массивом
Ступенчатые массивы
В ступенчатых массивах количество элементов в разных строках может различаться. В памяти ступенчатый массив хранится иначе, чем прямоугольный: в виде нескольких внутренних массивов, каждый из которых имеет свой размер. Кроме того, выделяется отдельная область памяти для хранения ссылок на каждый из внутренних массивов ( рис. 6.3).
Фрагмент программы, иллюстрирующий работу со ступенчатым массивом, приведен в листинге 6.5 (после рассмотрения оператора foreach ).
Класс System.Array
Все массивы в C# построены на основе базового класса Array, который содержит полезные для программиста свойства и методы, часть из которых перечислена в таблилце 6.1.
В листинге 6.3 продемонстрировано применение элементов класса Array при работе с одномерным массивом.
using System; namespace ConsoleApplication1 { class Class1 { static void Main() { int[] a = { 24, 50, 18, 3, 16, -7, 9, -1 }; PrintArray( "Исходный массив:", a ); Console.WriteLine( Array.IndexOf( a, 18 ) ); Array.Sort(a); PrintArray( "Упорядоченный массив:", a ); Console.WriteLine( Array.BinarySearch( a, 18) ); } public static void PrintArray( string header, int[] a ) { Console.WriteLine( header ); for ( int i = 0; i < a.Length; ++i ) Console.Write( "\t" + a[i] ); Console.WriteLine(); } } }Листинг 6.3. Использование методов класса Array с одномерным массивом
Методы Sort, IndexOf и BinarySearch являются статическими, поэтому к ним обращаются через имя класса, а не экземпляра, и передают в них имя массива. Двоичный поиск можно применять только для упорядоченных массивов. В классе Class1 описан вспомогательный статический метод PrintArray, предназначенный для вывода массива на экран.
Результат работы программы:
Исходный массив: 24 50 18 3 16 -7 9 -1 2 Упорядоченный массив: -7 -1 3 9 16 18 24 50 5
Оператор foreach
Оператор foreach применяется для перебора элементов в специальным образом организованной группе данных. Массив является именно такой группой. Удобство этого вида цикла заключается в том, что нам не требуется определять количество элементов в группе и выполнять их перебор по индексу: мы просто указываем на необходимость перебрать все элементы группы. Синтаксис оператора:
foreach ( тип имя in выражение ) тело_цикла
Имя задает локальную по отношению к циклу переменную, которая будет по очереди принимать все значения из массива выражение (в качестве выражения чаще всего применяется имя массива или другой группы данных). В простом или составном операторе, представляющем собой тело цикла, выполняются действия с переменной цикла. Тип переменной должен соответствовать типу элемента массива.
Например, пусть задан массив:
int[] a = { 24, 50, 18, 3, 16, -7, 9, -1 };
Вывод этого массива на экран с помощью оператора foreach выглядит следующим образом:
foreach ( int x in a ) Console.WriteLine( x );
Этот оператор выполняется так: на каждом проходе цикла очередной элемент массива присваивается переменной х и с ней производятся действия, записанные в теле цикла.
В листинге 6.4 решается та же задача, что и в листинге 6.1, но с использованием цикла foreach. Обратите внимание, насколько понятнее стала программа.
using System; namespace ConsoleApplication1 { class Class1 { static void Main() { int[] a = { 3, 12, 5, -9, 8, -4 }; Console.WriteLine( "Исходный массив:" ); foreach ( int elem in a ) Console.Write( "\t" + elem ); Console.WriteLine(); long sum = 0; // cумма отрицательных элементов int num = 0; // количество отрицательных элементов foreach ( int elem in a ) if ( elem < 0 ) { sum += elem; ++num; } Console.WriteLine( "sum = " + sum ); Console.WriteLine( "num = " + num ); int max = a[0]; // максимальный элемент foreach ( int elem in a ) if ( elem > max ) max = elem; Console.WriteLine( "max = " + max ); } } }Листинг 6.4. Работа с одномерным массивом с использованием цикла foreach
Внимание
Ограничением оператора foreach является то, что с его помощью можно только просматривать значения в группе данных, но не изменять их.
Еще один пример использования оператора для работы со ступенчатым массивом приведен в листинге 6.5.
... int[][] a = new int[3][]; a[0] = new int [5] { 24, 50, 18, 3, 16 }; a[1] = new int [3] { 7, 9, -1 }; a[2] = new int [4] { 6, 15, 3, 1 }; Console.WriteLine( "Исходный массив:" ); foreach ( int [] mas1 in a ) { foreach ( int x in mas1 ) Console.Write( "\t" + x ); Console.WriteLine(); } // поиск числа 18 в нулевой строке: Console.WriteLine( Array.IndexOf( a[0], 18 ) ); ...Листинг 6.5. Работа со ступенчатым массивом с использованием цикла foreach