Тверской государственный университет
Опубликован: 02.12.2009 | Доступ: свободный | Студентов: 3450 / 677 | Оценка: 4.41 / 4.23 | Длительность: 09:18:00
ISBN: 978-5-9963-0259-8
Лекция 4:

Операторы языка C#

Операторы перехода

Операторов перехода, позволяющих прервать естественный порядок выполнения операторов блока, в языке C# несколько.

Оператор goto

Оператор goto имеет простой синтаксис и семантику:

goto [метка|case константное_выражение|default];

Все операторы языка C# могут иметь метку - уникальный идентификатор, предшествующий оператору и отделенный от него символом двоеточия. Передача управления помеченному оператору - это классическое применение оператора goto. Оператор goto может использоваться в операторе switch, о чем шла речь выше.

"О вреде оператора goto" и о том, как можно обойтись без него, писал еще Эдсгар Дейкстра при обосновании принципов структурного программирования.

Я уже многие годы не применяю этот оператор и считаю, что хороший стиль программирования не предполагает использования этого оператора в C# ни в каком из вариантов - ни в операторе switch, ни для организации безусловных переходов.

Операторы break и continue

В структурном программировании признаются полезными "переходы вперед" (но не назад), позволяющие при выполнении некоторого условия выйти из цикла, из оператора выбора, из блока. Операторы break и continue специально предназначены для этих целей.

Оператор break может стоять в теле цикла или завершать case-ветвь в операторе switch. Пример его использования в операторе switch уже демонстрировался. При выполнении оператора break в теле цикла завершается выполнение самого внутреннего цикла. В теле цикла чаще всего оператор break помещается в одну из ветвей оператора if, проверяющего условие преждевременного завершения цикла. Классическим примером является "поиск по образцу", когда в массиве отыскивается элемент, соответствующий образцу. Понятно, что когда такой элемент найден, поиск можно прекратить. Вот пример метода, реализующего данную стратегию поиска:

/// <summary>
  /// Поиск образца в массиве
  /// </summary>
  /// <param name="ar">массив для поиска</param>
  /// <param name="pat">образец поиска</param>
  /// <param name="patIndex">индекс найденного элемента</param>
  /// <returns>
  /// true, если найден элемент, совпадающий с образцом
  /// false - в противном случае
  /// </returns>
  public bool SearchPattern(int[] ar, int pat, out int patIndex)
  {
      int n = ar.Length;
      patIndex = -1;
      bool found = false;
      for (int i = 0; i < n; i++)
         if (ar[i] == pat)
    {
        found = true;
        patIndex = i;
        break;
    }
      return found;
  }

Оператор continue используется только в теле цикла. В отличие от оператора break, завершающего внутренний цикл, continue осуществляет переход к следующей итерации этого цикла.

Оператор return

Еще одним оператором, относящимся к группе операторов перехода, является оператор return, позволяющий завершить выполнение процедуры или функции. Его синтаксис:

return [выражение];

Для функций его присутствие и аргумент обязательны, поскольку выражение в операторе return задает значение, возвращаемое функцией.

Операторы цикла

Без циклов жить нельзя в программах, нет.

Оператор for

Наследованный от С++ весьма удобный оператор цикла for обобщает известную конструкцию цикла типа арифметической прогрессии. Его синтаксис:

for(инициализаторы; условие; список_выражений) оператор

Оператор, стоящий после закрывающей скобки, задает тело цикла. В большинстве случаев телом цикла является блок. Сколько раз будет выполняться тело цикла, зависит от трех управляющих элементов, заданных в скобках. Инициализаторы задают начальное значение одной или нескольких переменных, часто называемых счетчиками или просто переменными цикла. В большинстве случаев цикл for имеет один счетчик, но часто полезно иметь несколько счетчиков, что и будет продемонстрировано в следующем примере. Условие задает условие окончания цикла, соответствующее выражение при вычислении должно получать значение true или false. Список выражений, записанный через запятую, показывает, как меняются счетчики цикла на каждом шаге выполнения. Если условие цикла истинно, то выполняется тело цикла, затем изменяются значения счетчиков и снова проверяется условие. Как только условие становится ложным, цикл завершает свою работу. В цикле for тело цикла может ни разу не выполняться, если условие цикла ложно после инициализации, а может происходить зацикливание, если условие всегда остается истинным. В нормальной ситуации тело цикла выполняется конечное число раз.

Счетчики цикла зачастую объявляются непосредственно в инициализаторе и соответственно являются переменными, локализованными в цикле, так что после завершения цикла они перестают существовать. В тех случаях, когда предусматривается возможность преждевременного завершения цикла с помощью одного из операторов перехода, счетчики объявляются до цикла, что позволяет анализировать их значения при выходе из цикла.

В качестве примера рассмотрим еще одну классическую задачу: является ли строка текста палиндромом. Напомню, палиндромом называется симметричная строка текста, читающаяся одинаково слева направо и справа налево. Для ее решения цикл for подходит наилучшим образом: здесь используются два счетчика - один возрастающий, другой убывающий. Вот текст соответствующей процедуры:

/// <summary>
  /// Определение палиндромов.
  /// Демонстрация цикла for
  /// </summary>
  /// <param name="str">текст</param>
  /// <returns>true - если текст является палиндромом</returns>
  public bool IsPalindrom(string str)
  {
      for (int i = 0, j = str.Length - 1; i < j; i++, j--)
          if (str[i] != str[j]) return (false);
      return (true);
  }//IsPalindrom

В цикле for разрешается опускать некоторые части заголовка цикла. Конструкция этого оператора, в которой все части заголовка опущены, задает бесконечный цикл:

for(;;) {…}

Эта конструкция позволяет организовать цикл с проверкой выхода в теле цикла. Ярые почитатели оператора for, к которым чаще всего относятся любители стиля языка С++, часто пользуются такой конструкцией. Я отношу это к нарушению хорошего стиля программирования. В таких ситуациях лучше использовать цикл типа while.

Циклы While

Цикл while (выражение) является универсальным видом цикла, включаемым во все языки программирования. Тело цикла выполняется до тех пор, пока остается истинным выражение while. В языке C# у этого вида цикла две модификации - с проверкой условия в начале и в конце цикла. Первая модификация имеет следующий синтаксис:

while(выражение) оператор

Эта модификация соответствует стратегии: "сначала проверь, а потом делай". В результате проверки может оказаться, что и делать ничего не нужно. Тело такого цикла может ни разу не выполняться. Конечно же, возможно и зацикливание. В нормальной ситуации каждое выполнение тела цикла - это очередной шаг к завершению цикла.

Цикл, проверяющий условие завершения в конце, соответствует стратегии: "сначала делай, а потом проверь". Тело такого цикла выполняется, по меньшей мере, один раз. Вот синтаксис этой модификации:

do
	оператор
while(выражение);

Приведу пример, в котором участвуют обе модификации цикла while. Во внешнем цикле проверка выполняется в конце, во внутреннем - в начале. Внешний цикл представляет собой типичный образец организации учебных программ, когда в диалоге с пользователем многократно решается некоторая задача. На каждом шаге пользователь вводит новые данные, решает задачу и анализирует полученные данные. В его власти продолжить вычисления или нет, но хотя бы один раз решить задачу ему приходится. Внутренний цикл do while используется для решения уже известной задачи с палиндромами. Вот текст соответствующей процедуры:

/// <summary>
    /// Два цикла: с проверкой в конце и в начале.
    /// Внешний цикл - образец многократно решаемой задачи.
    /// Завершение цикла определяется в диалоге с пользователем.
    /// </summary>
    public void Loop()
    {
    	string answer, text;
    	do
    	{
        Console.WriteLine("Введите текст");
        text = Console.ReadLine();
        int i =0, j = text.Length-1;
        while ((i < j) && (text[i] == text[j]))
        	{i++; j--;}
        if (text[i] == text[j])
        	Console.WriteLine(text +" - это палиндром!");
        else
        	Console.WriteLine(text +" - это не палиндром!");
        Console.WriteLine("Продолжим? (yes/no)");
        answer = Console.ReadLine();
    	}
    	while(answer =="yes");
    }//Loop

Цикл foreach

Новым видом цикла, не унаследованным от С++, является цикл foreach, удобный при работе с массивами, коллекциями и другими подобными контейнерами данных. Его синтаксис:

foreach(тип идентификатор in контейнер) оператор

Цикл работает в полном соответствии со своим названием - тело цикла выполняется для каждого элемента в контейнере. Тип идентификатора должен быть согласован с типом элементов, хранящихся в контейнере данных. Предполагается также, что элементы контейнера (массива, коллекции) упорядочены. На каждом шаге цикла идентификатор, задающий текущий элемент контейнера, получает значение очередного элемента в соответствии с порядком, установленном на элементах контейнера. С этим текущим элементом и выполняется тело цикла - выполняется столько раз, сколько элементов находится в контейнере. Цикл заканчивается, когда полностью перебраны все элементы контейнера.

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

В приведенном ниже примере показана работа с трехмерным массивом. Массив создается с использованием циклов типа for, а при нахождении суммы его элементов, минимального и максимального значения используется цикл foreach:

/// <summary>
/// Демонстрация цикла foreach.
/// Вычисление суммы, максимального и минимального
/// элементов трехмерного массива,
/// заполненного случайными числами.
/// </summary>
public void SumMinMax()
{
	int [,,] arr3d = new int[10,10,10];
	Random rnd = new Random();
	for (int i = 0; i < 10; i++)
    for (int j = 0; j < 10; j++)
    	for (int k = 0; k < 10; k++)
        arr3d[i, j, k]= rnd.Next(100);

	long sum = 0; int min = arr3d[0,0,0], max = min;
	foreach(int item in arr3d)
	{
    sum +=item;
    if (item > max) max = item;
    else if (item < min) min = item;
	}
	Console.WriteLine("sum = {0}, min = {1}, max = {2}",
    sum, min, max);
}//SumMinMax
Федор Антонов
Федор Антонов

Здравствуйте!

Записался на ваш курс, но не понимаю как произвести оплату.

Надо ли писать заявление и, если да, то куда отправлять?

как я получу диплом о профессиональной переподготовке?

Илья Ардов
Илья Ардов

Добрый день!

Я записан на программу. Куда высылать договор и диплом?