Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Программирование. Введение в разработку на C#. Учебное пособие
.pdf
4.2. Виды циклов
4.2.1. Безусловные циклы
Часто в программах применяются циклы, выход из которых не предусмотрен программной логикой. Такие циклы называются безусловными, или бесконечными. Специальных синтаксических конструкций
для создания бесконечных циклов, ввиду их узкой направленности,
языки программирования не предусматривают, поэтому такие циклы
создаются с помощью конструкций, определённых для создания классических (или условных) циклов. Для обеспечения бесконечного повторения проверку условия в таком цикле либо убирают, либо заменяют константным значением:
while(true)
Console.WriteLine("Меня не остановить!");
4.2.2. Цикл с предусловием
Цикл с предусловием – цикл, который выполняется, пока истинно
некоторое условие, указанное перед его началом. Это условие
проверяется до выполнения тела цикла, поэтому тело может быть не
выполнено ни разу (если условие с самого начала ложно). В
большинстве процедурных языков программирования цикл с
предусловием реализуется оператором while, отсюда его второе
название – while-цикл. Его пример показан выше. Если количество
операций превышает одну, то необходимы фигурные скобки.
4.2.3. Цикл с постусловием
Цикл с постусловием – цикл, в котором условие проверяется после
выполнения тела цикла. Отсюда следует, что тело всегда выполняется
хотя бы один раз:
int i = -2;
do {
i++;
41

}
while(i > 0);
4.2.4 Цикл с выходом из середины
Цикл с выходом из середины – наиболее общая форма условного
цикла. Синтаксически такой цикл создается с помощью трёх
конструкций: начала цикла, конца цикла и команды выхода из цикла.
Конструкция начала определяет точку программы, в которой начинается
тело цикла, конструкция конца – точку, где тело завершается. Внутри
тела должна находиться команда принудительного выхода из цикла, при
выполнении которой цикл завершается и управление передаётся на
оператор, следующий за конструкцией конца цикла. Естественно, чтобы
цикл выполнялся более одного раза, команда выхода должна вызываться
не безусловно, а только при выполнении условия выхода из цикла.
Принципиальным отличием такого вида цикла от рассмотренных
выше является то, что часть тела цикла, расположенная после начала
цикла и до команды выхода, выполняется всегда (даже если условие
выхода из цикла истинно при первой итерации), а часть тела цикла, находящаяся после команды выхода, не выполняется при последней итерации.
Легко заметить, что с помощью цикла с выходом из середины можно моделировать и цикл с предусловием (разместив команду выхода в
начале тела цикла), и цикл с постусловием (разместив команду выхода
в конце тела цикла):
int i = 0;
while(i < 10)
{
i++;
if (i == 5)
break;
}
42

4.2.5. Цикл со счётчиком
Цикл со счётчиком – цикл, в котором некая переменная меняет своё
значение от заданного начального до конечного значения с заданным
шагом, и для каждого значения этой переменной тело цикла
выполняется один раз. В большинстве Си-подобных языков
программирования реализуется оператором for, в котором указывается
счётчик (так называемая «переменная цикла»), требуемое количество
проходов (или граничное значение счётчика) и, возможно, шаг, с
которым изменяется счётчик:
for(int i = 0; i < 10; i++)
Console.WriteLine(i)
4.2.6. Совместный цикл
Ещё один вариант цикла – цикл, задающий выполнение некоторой
операции для объектов из заданного множества, без явного указания порядка перечисления этих объектов. Такие циклы называются совместными (а также циклами по коллекции, циклами просмотра) и представляют
собой формальную запись инструкции вида: «Выполнить операцию X для
всех элементов, входящих в множество M». Совместный цикл теоретически никак не определяет, в каком порядке операция будет совершаться по
отношению к элементам множества, хотя конкретные языки программирования, разумеется, могут задавать конкретный порядок перебора элементов. Произвольность даёт возможность оптимизировать исполнение
цикла за счёт организации доступа не в заданном программистом, а в
наиболее выгодном с точки зрения логики порядке. При наличии возможности параллельного выполнения нескольких операций возможно
даже распараллеливание выполнения совместного цикла, когда одна и та
же операция одновременно выполняется на разных вычислительных модулях для разных объектов, при том что логически программа остаётся
последовательной.
43

Совместные циклы имеются во многих современных языках
программирования (C#, Eiffel, Java, JavaScript, Perl, Python, PHP, LISP,
Tcl и др.) – они позволяют выполнять цикл по всем элементам заданной
коллекции объектов. В определении такого цикла требуется указать
только коллекцию объектов и переменную, которой в теле цикла будет
итерационно присвоено значение обрабатываемого в данный момент
объекта (или ссылка на него). В различных языках программирования
синтаксис оператора различается. В C# это :
foreach(int i in Enumerable.Range(1, 10)) Console.WriteLine(i);
4.3. Вопросы для самопроверки
1. Каково определение понятия «алгоритм»?
2. Какие требования следуют из определения алгоритма?
3. Поясните любые 3 требования к алгоритму на выбор, приведите
по одному примеру на каждое пояснение.
4. Какие виды циклов бывают? Приведите пример кода на языке C#,
описывающего каждый из видов циклов.
5. Для какого типа цикла не предусматриваются специальные
синтаксические средства в языках программирования?
6. Какие, по вашему мнению, преимущества дает использование
совместного цикла в сравнении с циклом со счетчиком?
4.4. Задания для самопроверки
1. При помощи цикла while переделать задание с инверсией
введённой строки таким образом, чтобы программа не завершалась
после выполнения операции. Программа должна завершаться, если
пользователь ввёл строку "exit".
2. Дан цикл, надо в нём добавить в трех местах постфиксный или
префиксный инкремент/декремент так, чтобы программа вывела 0.
44

Например:
int j = 0;
for (int i = 0; i < 2; ?i?)
{
j = ?i?;
}
Console.Write(?j?);
3. Проверить введенное число на простоту. Число считается
простым, если оно делится только на 1 и на себя без остатка.
4. Выведите нечетные числа в диапазоне от 100 до 200.
5. Выведите двоичное представление десятичного числа.
45

5. РАБОТА С МАССИВАМИ
5.1. Одномерные и многомерные числовые массивы
Массивом называют упорядоченную совокупность элементов одного типа. Каждый элемент массива имеет индексы, определяющие порядок элементов. Индексы задаются целочисленным типом. Число индексов характеризует размерность массива. Если конечное значение задано
константным выражением, то число элементов массива известно в момент его объявления и ему может быть выделена память ещё на этапе
трансляции. Такие массивы называются статическими. Если же конечное значение зависят от переменной, то такой массив называют динамическим, поскольку память ему может быть отведена только динамически в процессе выполнения программы, когда становятся известными
значения соответствующих переменных. Массиву, как правило, выделяется непрерывная область памяти.
В языке C# каждый индекс изменяется в диапазоне от 0 до
некоторого конечного значения. Массивы в языке C# являются
настоящими динамическими массивами. Как следствие этого, массивы
относятся к ссылочным типам, память им отводится динамически в
«куче». Массивы могут быть одномерными и многомерными.
Объявление одномерного массива выглядит следующим образом:
<тип>[] <объявители>;
Как и в случае объявления простых переменных, каждый
объявитель может быть именем или именем с инициализацией. В
первом случае речь идёт об отложенной инициализации. Нужно
понимать, что при объявлении с отложенной инициализацией сам
массив не формируется, а создаётся только ссылка на массив, имеющая
неопределённое значение Null. Поэтому пока массив не будет реально
создан и его элементы не будут инициализированы, использовать его в
вычислениях нельзя. Вот пример объявления трёх массивов с
отложенной инициализацией:
46

int[] a, b, c;
Чаще всего при объявлении массива используется имя с
инициализацией. И, как и в случае простых переменных, могут быть
два варианта инициализации. В первом случае инициализация является
явной и задаётся константным массивом. Например:
double[] x = {5.5, 6.6, 7.7};
Следуя синтаксису, элементы константного массива необходимо заключать в фигурные скобки. Если массив инициализируется константным
массивом, то в динамической памяти создаётся константный массив с заданными значениями, с которым и связывается ссылка.
Во втором случае создание массива выполняется с помощью
операции new. Например:
int[] d = new int[5];
Здесь объявлен динамический целочисленный массив, в котором
будут храниться 5 целых чисел. Массив создаётся в динамической
памяти, его элементы получают начальные нулевые значения, и ссылка
связывается с этим массивом.
Примеры:
// объявляются три одномерных массива A,B,C
int[] A = new int[5], B= new int[5], C= new int[5];
// заполняется данными с клавиатуры массив A
for(int i = 0; i < 5; i++)
A[i] = int.Parse(Console.ReadLine());
// вычисляются элементы массива C
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];
47

for(int i = 0; i < 3; i++) u[i] = i + 1;
// v = {1,2,3}; // присваивание константного массива
недопустимо!
v = new int[4];
v = u; // допустимое присваивание – массивы одного
класса
int [,] w = new int[3,5];
// v = w; // недопустимое присваивание: объекты разных
классов
В вышеприведённых примерах объявлялись статические массивы,
поскольку нижняя граница равна нулю по определению, а верхняя
всегда задавалась в этих примерах константой. Вспомним, что в C# все
массивы, независимо от того, каким выражением описывается граница,
рассматриваются как динамические, и память для них распределяется в
«куче». Чисто синтаксически нет существенной разницы в объявлении
статических и динамических массивов. Выражение, задающее границу
изменения индексов, в динамическом случае содержит переменные.
Единственное требование – значения переменных должны быть
определены в момент объявления. Это ограничение в C# выполняется
автоматически, поскольку хорошо известно, насколько требовательно
C# контролирует инициализацию переменных. Рассмотрим пример:
// объявление динамического массива A1
Console.WriteLine("Введите число элементов массива A1");
int size = int.Parse(Console.ReadLine());
int[] A1 = new int[size];
5.2. Класс Array
Нельзя понять многие детали работы с массивами в C#, если не
знать устройство класса Array из библиотеки FCL, потомками которого
48

по определению являются все классы-массивы. Рассмотрим следующие
объявления:
int[] ar1 = new int[5];
double[] ar2 = {5.5, 6.6, 7.7};
int[,] ar3 = new Int32[3,4];
Зададимся естественным вопросом: к какому типу или к каким
классам принадлежат объекты ar1, ar2 и ar3? Ответ прост: все они
принадлежат к разным классам. Переменная ar1 принадлежит к классу
int[] – одномерному массиву значений типа int, ar2 – к double[] –
одномерному массиву значений типа double, ar3 – к двумерному
массиву значений типа int. Следующий закономерный вопрос: что
общего есть у этих трёх объектов? Прежде всего, все три класса этих
объектов, как и другие классы, являются потомками класса Object, а
потому имеют общие методы, наследованные от класса Object и
доступные объектам этих классов.
У всех классов, являющихся массивами, много общего, поскольку
все они являются потомками класса System.Array. Класс System.Array
наследует ряд интерфейсов: ICloneable, IList, ICollection, IEnumerable, а
следовательно обязан реализовать все их методы и свойства. Помимо
наследования свойств и методов класса Object и вышеперечисленных
интерфейсов, класс Array имеет довольно большое число собственных
методов и свойств. Благодаря такому мощному родителю, над
массивами определены самые разнообразные операции: копирование,
поиск, обращение, сортировка, получение различных характеристик.
Статические методы класса Array позволяют решать самые
разнообразные задачи:
1) Copy – позволяет копировать весь массив или его часть в другой
массив;
2) IndexOf, LastIndexOf – определяют индексы первого и последнего
вхождения образца в массив, возвращая значение -1, если такового
вхождения не обнаружено;
49

3) Reverse – выполняет обращение массива, переставляя элементы в
обратном порядке;
4) Sort – осуществляет сортировку массива;
5) BinarySearch – определяет индекс первого вхождения образца в
отсортированный массив, используя алгоритм двоичного поиска.
5.3. Пример работы с массивами
Существует несколько часто повторяющихся в различных задачах
операций работы с массивами. К таким шаблонным операциям можно
отнести:
1) прохождение одномерного массива от начала до конца:
int[] Arr = {1,2,3,4,5};
for (int i = 0; i < Arr.Length; i++)
{
Console.WriteLine(Arr[i]);//Чтение i-того элемента
массива
Arr[i] = 0; // Присвоение значения i-тому элементу
массива
}
2) прохождение многомерно массива от начала до конца по
строкам-столбцам:
int[,] Arr =
{{1,2,3},
{4,5,6},
{7,8,9}};
for (int i = 0; i < Arr.GetLength(0); i++)
{
for (int j = 0; j < Arr.GetLength(1); j++)
Console.Write(Arr[i, j] + " ");
Console.WriteLine();
}
50
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
