Главная страница
Навигация по странице:

  • Вложенные if-инструкции

  • Вложенные инструкции switch

  • Вариации на тему цикла for

  • Использование инструкции break для выхода из цикла

  • Использование инструкции continue

  • Инструкция return Инструкция return обеспечивает возврат из метода. Ее можно использовать для возвращения методом значения. Подробнее см. главу 6. Инструкция goto

  • Справочник по C# Герберт Шилдт ббк 32. 973. 26018 75 Ш57 удк 681 07 Издательский дом "Вильямс" Зав редакцией


    Скачать 5.05 Mb.
    НазваниеСправочник по C# Герберт Шилдт ббк 32. 973. 26018 75 Ш57 удк 681 07 Издательский дом "Вильямс" Зав редакцией
    АнкорC #.pdf
    Дата08.12.2017
    Размер5.05 Mb.
    Формат файлаpdf
    Имя файлаC #.pdf
    ТипСправочник
    #10795
    страница7 из 52
    1   2   3   4   5   6   7   8   9   10   ...   52
    Глава 5
    Инструкции управления

    Глава 5. Инструкции управления
    103 этой главе рассматриваются инструкции управления ходом выполнения C#- программы. Существует три категории управляющих инструкций: инструкции
    выбора (
    if
    , switch
    ), итерационные инструкции (состоящие из for
    -, while
    -, do
    - while
    - и foreach
    -циклов) и инструкции перехода (
    break
    , continue
    , goto
    , return и throw
    ).
    За исключением инструкции throw
    , которая является частью C#-механизма обработки исключительных ситуаций (и рассматривается в главе 13), все остальные перечисленные выше инструкции описаны в этой главе.
    Инструкция if
    Инструкция if была представлена в главе 2, но здесь мы рассмотрим ее более детально. Полный формат ее записи такой: if(
    условие
    )
    инструкция
    ; else
    инструкция
    ;
    Здесь под элементом
    инструкция
    понимается одна инструкция языка C#. Часть else необязательна. Вместо элемента
    инструкция
    может быть использован блок инструкций. В этом случае формат записи if
    -инструкции принимает такой вид: if(
    условие
    ) {
    последовательность инструкций
    } else
    {
    последовательность инструкций
    }
    Если элемент
    условие
    , который представляет собой условное выражение, при вычислении даст значение ИСТИНА, будет выполнена if
    -инструкция; в противном случае
    — else
    -инструкция (если таковая существует). Обе инструкции никогда не выполняются.
    Условное выражение, управляющее выполнением if
    -инструкции, должно иметь тип bool
    Рассмотрим простую программу, в которой используется if-else
    -инструкция для определения того, является число положительным или отрицательным.
    // Программа определяет, является число положительным
    // или отрицательным. using System; class PosNeg { public static void Main() { int i; for(i=-5; i <= 5; i++) {
    Console.Write("Тестирование " + i + ": "); if(i < 0) Console.WriteLine("Число отрицательно"); else
    Console.WriteLine("Число положительно");
    }
    }
    }
    В

    104
    Часть I. Язык C#
    Результаты выполнения программы выглядят так:
    Тестирование -5: Число отрицательно
    Тестирование -4: Число отрицательно
    Тестирование -3: Число отрицательно
    Тестирование -2: Число отрицательно
    Тестирование -1: Число отрицательно
    Тестирование 0: Число положительно
    Тестирование 1: Число положительно
    Тестирование 2: Число положительно
    Тестирование 3: Число положительно
    Тестирование 4: Число положительно
    Тестирование 5: Число положительно
    Если оказывается, что в этом примере значение переменной i
    меньше нуля, выполняется if
    -инструкция (выводится “диагноз”:
    Число отрицательно
    ); в противном случае — else
    -инструкция (выводится “диагноз”:
    Число положительно
    ). Обе инструкции вместе ни при каких условиях выполнены не будут.
    Вложенные if-инструкции
    Вложенные if
    -инструкции образуются в том случае, если в качестве элемента
    инструкция
    (см. полный формат записи) используется другая if
    -инструкция. Вложенные if
    -инструкции очень популярны в программировании. Главное здесь — помнить, что else
    -инструкция всегда относится к ближайшей if
    -инструкции, которая находится внутри того же программного блока, но еще не связана ни с какой другой else
    -инструкцией. Вот пример: if(i == 10) { if(j < 20) a = b; if(k > 100) c = d; else a = c; // Эта else-инструкция
    // относится к if(k > 100).
    } else a = d; // Эта else-инструкция относится к if(i == 10).
    Как утверждается в комментариях, последняя else
    -инструкция не связана с инструкцией if(j < 20)
    , поскольку они не находятся в одном блоке (несмотря на то что эта if
    -инструкция — ближайшая, которая не имеет при себе “
    else
    -пары”). Внутренняя else
    -инструкция связана с инструкцией if(k > 100)
    , поскольку она — ближайшая и находится внутри того же блока.
    В предыдущей программе нулевое значение тестируемой переменной интерпретировалось как положительное. Однако в некоторых приложениях нуль рассматривается как значение без знака. Поэтому в следующей версии программы, которая демонстрирует использование вложенных else
    -инструкций, нулю дается именно такая характеристика: “без знака”.
    // Программа определяет, является число положительным,
    // отрицательным или нулем. using System; class PosNegZero { public static void Main() { int i; for(i=-5; i <= 5; i++) {

    Глава 5. Инструкции управления
    105
    Console.Write("Тестирование " + i + ": "); if(i < 0) Console.WriteLine("Число отрицательно"); else if(i == 0) Console.WriteLine("Число без знака"); else
    Console.WriteLine("Число положительно");
    }
    }
    }
    Вот какие получаем результаты:
    Тестирование -5: Число отрицательно
    Тестирование -4: Число отрицательно
    Тестирование -3: Число отрицательно
    Тестирование -2: Число отрицательно
    Тестирование -1: Число отрицательно
    Тестирование 0: Число без знака
    Тестирование 1: Число положительно
    Тестирование 2: Число положительно
    Тестирование 3: Число положительно
    Тестирование 4: Число положительно
    Тестирование 5: Число положительно
    Конструкция if-else-if
    Очень распространенной в программировании конструкцией, в основе которой лежит вложенная if
    -инструкция, является “лестница” if-else-if
    . Ее можно представить в следующем виде: if(
    условие
    )
    инструкция
    ; else if(
    условие
    )
    инструкция
    ; else if(
    условие
    )
    инструкция
    ; else
    инструкция
    ;
    Здесь под элементом
    условие
    понимается условное выражение. Условные выражения вычисляются сверху вниз. Как только в какой-нибудь ветви обнаружится истинный результат, будет выполнена инструкция, связанная с этой ветвью, а вся остальная
    “лестница” опускается. Если окажется, что ни одно из условий не является истинным, будет выполнена последняя else
    -инструкция (можно считать, что она выполняет роль условия, которое действует по умолчанию). Если последняя else
    -инструкция не задана, а все остальные оказались ложными, то вообще никакое действие не будет выполнено.
    Работа if-else-if
    -“лестницы” демонстрируется в следующей программе, которая находит для заданного значения наименьший множитель {отличный от единицы и состоящий из одной цифры).
    // Определение наименьшего множителя,
    // состоящего из одной цифры. using System;

    106
    Часть I. Язык C# class Ladder { public static void Main() { int num; for(num = 2; num < 12; num++) { if((num % 2) == 0)
    Console.WriteLine("Наименьший множитель числа " + num
    +
    " равен 2."); else if((num % 3) == 0)
    Console.WriteLine("Наименьший множитель числа " + num
    +
    " равен 3."); else if((num % 5) == 0)
    Console.WriteLine("Наименьший множитель числа " + num
    +
    " равен 5."); else if((num % 7) ==0)
    Console.WriteLine("Наименьший множитель числа " + num
    +
    " равен 7."); else
    Console.WriteLine(num
    +
    " не делится на 2, 3, 5 или 7.");
    }
    }
    }
    Результаты выполнения этой программы выглядят так:
    Наименьший множитель числа 2 равен 2.
    Наименьший множитель числа 3 равен 3.
    Наименьший множитель числа 4 равен 2.
    Наименьший множитель числа 5 равен 5.
    Наименьший множитель числа 6 равен 2.
    Наименьший множитель числа 7 равен 7.
    Наименьший множитель числа 8 равен 2.
    Наименьший множитель числа 9 равен 3.
    Наименьший множитель числа 10 равен 2.
    11 не делится на 2, 3, 5 или 7.
    Как видите, последняя else
    -инструкция выполняется только в том случае, если не выполнилась ни одна из предыдущих if
    -инструкций.
    Инструкция switch
    Второй инструкцией выбора является switch
    . Инструкция switch обеспечивает многонаправленное ветвление. Она позволяет делать выбор одной из множества альтернатив. Хотя многонаправленное тестирование можно реализовать с помощью последовательности вложенных if
    -инструкций, для многих ситуаций инструкция switch оказывается более эффективным решением. Она работает следующим образом. Значение выражения последовательно сравнивается с константами из заданного списка. При обнаружении совпадения для одного из условий сравнения выполняется последовательность инструкций, связанная с этим условием. Общий формат записи инструкции switch такой: switch{
    выражение
    ) { case
    константа1
    :
    последовательность инструкций
    break; case
    константа2
    :

    Глава 5. Инструкции управления
    107
    последовательность инструкций
    break; case
    константа3
    :
    последовательность инструкций
    break; default:
    последовательность инструкций
    break;
    }
    Элемент
    выражение
    инструкции switch должен иметь целочисленный тип
    (например, char
    , byte
    , short или int
    ) или тип string
    (о котором речь пойдет ниже в этой книге). Выражения, имеющие тип с плавающей точкой, не разрешены. Очень часто в качестве управляющего switch
    -выражения используется просто переменная; case- константы должны быть литералами, тип которых совместим с типом заданного выражения. При этом никакие две case
    -константы в одной switch
    -инструкции не могут иметь идентичных значений.
    Последовательность инструкций default
    -ветви выполняется в том случае, если ни одна из заданных case
    -констант не совпадет с результатом вычисления switch
    - выражения. Ветвь default необязательна. Если она отсутствует, то при несовпадении результата выражения ни с одной из case
    -констант никакое действие выполнено не будет.
    Если такое совпадение все-таки обнаружится, будут выполнены инструкции, соответствующие данной case
    -ветви до тех пор, пока не встретится инструкция break
    Использование switch
    -инструкции демонстрируется в следующей программе.
    // Демонстрация использования инструкции switch. using System; class SwitchDemo { public static void Main() { int i; for(i=0; i<10; i++) switch(i)
    { case
    0:
    Console.WriteLine("i равно нулю."); break; case
    1:
    Console.WriteLine("i равно единице."); break; case
    2:
    Console.WriteLine("i равно двум."); break; case
    3:
    Console.WriteLine("i равно трем."); break; case
    4:
    Console.WriteLine("i равно четырем."); break; default:
    Console.WriteLine("i равно или больше пяти."); break;

    108
    Часть I. Язык C#
    }
    }
    }
    Результаты выполнения этой программы: i равно нулю. i равно единице. i равно двум. i равно трем. i равно четырем. i равно или больше пяти. i равно или больше пяти. i равно или больше пяти. i равно или больше пяти. i равно или больше пяти.
    Как видите, на каждой итерации цикла выполняются инструкции, соответствующие case
    -константе, которая совпадает с текущим значением переменной x
    . При этом все остальные инструкции опускаются. Если i
    равно или больше пяти, выполняется default
    - инструкция.
    В предыдущем примере switch
    -инструкция управлялась переменной типа int
    . Но, как вы уже знаете, для управления в switch
    -инструкции можно использовать переменную любого целочисленного типа, в том числе и типа c h
    ar. Перед вами пример использования в case
    -ветвях char
    -выражения и char
    -констант.
    // Использование типа char для управления
    // switch-инструкцией. using System; class SwitchDemo2 { public static void Main() { char ch; for(ch='A'; ch<= 'E'; ch++) switch(ch)
    { case
    'A':
    Console.
    WriteLine("ch содержит А"); break; case
    'B':
    Console.WriteLine("ch содержит В"); break; case
    'C':
    Console.WriteLine("ch содержит С"); break; case
    'D':
    Console.WriteLine("ch содержит D"); break; case
    'E':
    Console.WriteLine("ch содержит Е"); break;
    }
    }
    }
    Результаты выполнения этой программы выглядят так: ch содержит A ch содержит B

    Глава 5. Инструкции управления
    109 ch содержит C ch содержит D ch содержит E
    Обратите внимание на то, что в этом примере программы default
    -инструкция отсутствует. Не забывайте, что она необязательна. Если в ней нет необходимости, ее можно опустить.
    В C# считается ошибкой, если последовательность инструкций, относящаяся к одной case
    -ветви, переходит в последовательность инструкций, связанную со следующей. Здесь должно действовать правило запрета на передачу управления вниз, на “провал”, как говорят программисты. Поэтому case
    -последовательности чаще всего оканчиваются инструкцией break
    . (“Провала” можно избежать и другими способами, например с помощью инструкции goto
    , которая будет рассмотрена ниже в этой главе, но break
    — это самое распространенное средство от “провалов”.) Инструкция break
    , завершающая последовательность case
    -инструкций, приводит к выходу из всей конструкции switch и передаче управления к следующей инструкции, находящейся вне конструкции switch
    Последовательность инструкций default
    -ветви также не должна “проваливаться” и обычно завершается инструкцией break
    Правило запрета на “провальную” передачу управления вниз — одно из отличий языка C# от С, C++ и Java. В этих трех упомянутых языках case
    -инструкции имеют право
    “плавно” переходить в инструкции, соответствующие следующей case
    -ветви, т.е.
    “проваливаться” вниз. Разработчики языка C# обосновали запрет на “провал” двумя следующими причинами. Во-первых, это позволяет компилятору в целях оптимизации свободно менять порядок следования case
    -ветвей, что было бы невозможно, если бы одна case
    -последовательность могла беспрепятственно перетекать в следующую. Во-вторых, требование явного завершения case
    -последовательности специальной инструкцией исключит возможность случайного “провала”, организованного программистом по недосмотру.
    Несмотря на запрет “провальной” передачи управления от одной case
    - последовательности к следующей, можно, как показано в следующем примере, организовать программный код так, чтобы две или больше инструкций case ссылались на одну и ту же кодовую последовательность.
    // "Пустые" case-инструкции могут "проваливаться". using System; class EmptyCasesCanFall { public static void Main() { int i; for(i=1; i < 5; i++) switch(i)
    { case
    1: case
    2: case
    3:
    Console.WriteLine("i равно 1, 2 или 3"); break; case
    4:
    Console.WriteLine("i равно 4"); break;
    }
    }
    }

    110
    Часть I. Язык C#
    Результаты работы этой программы вполне ожидаемы: i равно 1, 2 или 3 i равно 1, 2 или 3 i равно 1, 2 или 3 i равно 4
    В этом примере, если переменная i
    содержит значение 1, 2 или 3, то выполняется первая инструкция вызова метода
    WriteLine()
    , а если значение i
    равно 4, то — вторая.
    Показанное здесь пакетирование case
    -ветвей не нарушает правило запрета “провалов”, поскольку все эти case
    -инструкции используют одну и ту же кодовую последовательность.
    Такое case
    -пакетирование — распространенный способ совместного использования кода несколькими case
    -ветвями, позволяющий устранить ненужное дублирование кодовых последовательностей.
    Вложенные инструкции switch
    Инструкция switch может быть использована как часть case
    -последовательности внешней инструкции switch
    . В этом случае она называется вложенной инструкцией switch
    . Необходимо отметить, что case
    -константы внутренних и внешних инструкций switch могут иметь одинаковые значения, при этом никаких конфликтов не возникнет.
    Например, следующий фрагмент кода вполне допустим: switch(ch1) { case
    'A':
    Console.WriteLine(
    "Эта буква А - часть внешней инструкции switch."); switch(ch2) { case
    'A':
    Console.WriteLine(
    "Эта буква А - часть внутренней инструкции switch."); break; case
    'В': // ...
    }
    //
    Конец внутренней инструкции switch. break; case
    'В': // ...
    Цикл for
    Начиная с главы 2, мы уже использовали простую форму цикла for
    . В этой главе мы рассмотрим этот цикл более детально, и вы узнаете, насколько мощным и гибким средством программирования он является. Начнем с традиционных форм его использования. Итак, общий формат записи цикла for для повторного выполнения одной инструкции имеет следующий вид: for(
    инициализация
    ;
    условие
    ;
    итерация
    )
    инструкция
    ;
    Если цикл for предназначен для повторного выполнения программного блока, то его общий формат выглядит так: for(
    инициализация
    ;
    условие
    ;
    итерация
    ) {
    последовательность инструкций
    }
    Элемент
    инициализация
    обычно представляет собой инструкцию присваивания, которая устанавливает управляющую переменную цикла равной начальному значению.

    Глава 5. Инструкции управления
    111
    Эта переменная действует в качестве счетчика, который управляет работой цикла.
    Элемент
    условие
    представляет собой выражение типа bool
    , в котором тестируется значение управляющей переменной цикла. Результат этого тестирования определяет, выполнится цикл for еще раз или нет. Элемент
    итерация
    это выражение, которое определяет, как изменяется значение управляющей переменной цикла после каждой итерации. Обратите внимание на то, что все эти элементы цикла for должны отделяться точкой с запятой. Цикл for будет выполняться до тех пор, пока вычисление элемента
    условие
    дает истинный результат. Как только условие станет ложным, выполнение программы продолжится с инструкции, следующей за циклом for
    Управляющая переменная цикла for может изменяться как с положительным, так и с отрицательным приращением, причем величина этого приращения также может быть любой. Например, следующая программа выводит числа в диапазоне от 100 до -100 с декрементом, равным 5.
    // Цикл for с отрицательным приращением
    // управляющей переменной. using System; class DecrFor { public static void Main() { int x; for(x = 100; x > -100; x -= 5)
    Console.WriteLine(x);
    }
    }
    Важно понимать, что условное выражение всегда тестируется в начале выполнения цикла for
    . Это значит, что если первая же проверка условия даст значение ЛОЖЬ, код тела цикла не выполнится ни разу. Вот пример: for(count=10; count < 5; count++) x += count; // Эта инструкция не будет выполнена вовсе.
    Этот цикл никогда не выполнится, поскольку уже при входе в него значение его управляющей переменной count больше пяти. Это делает условное выражение
    (count
    < 5)
    ложным с самого начала. Поэтому даже одна итерация этого цикла не будет выполнена.
    Цикл for особенно полезен в тех случаях, когда известно количество его повторений. Например, следующая программа использует два цикла for для отыскания простых чисел в диапазоне от 2 до 20. Если число не простое, программа отобразит его самый большой множитель.
    /*
    Программа определения простых чисел. Если число не простое, программа отображает его самый большой множитель. */ using System; class FindPrimes { public static void Main() { int num; int i; int factor; bool isprime; for(num = 2; num < 20; num++) {

    112
    Часть I. Язык C# isprime = true; factor
    =
    0;
    //
    Узнаем, делится ли num на i без остатка. for(i=2; i <= num/2; i++) { if((num % i) == 0) {
    // Если num делится на i без остатка,
    // значит num — число не простое. isprime
    = false; factor
    = i;
    }
    } if(isprime)
    Console.WriteLine(num
    +
    "
    — простое число."); else
    Console.WriteLine("Максимальный множитель числа " + num
    +
    " равен " + factor);
    }
    }
    }
    Результаты выполнения этой программы имеют такой вид:
    2 — простое число.
    3 — простое число.
    Максимальный множитель числа 4 равен 2 5 — простое число.
    Максимальный множитель числа 6 равен 3 7 — простое число.
    Максимальный множитель числа 8 равен 4
    Максимальный множитель числа 9 равен 3
    Максимальный множитель числа 10 равен 5 11 — простое число.
    Максимальный множитель числа 12 равен 6 13 — простое число.
    Максимальный множитель числа 14 равен 7
    Максимальный множитель числа 15 равен 5
    Максимальный множитель числа 16 равен 8 17 — простое число.
    Максимальный множитель числа 18 равен 9 19 — простое число.
    Вариации на тему цикла for
    Цикл for
    — одна из наиболее гибких инструкций в C#, поскольку она позволяет получить широкий диапазон вариаций.
    Использование нескольких управляющих переменных цикла
    Для управления циклом for можно использовать две или больше переменных. В этом случае инструкции инициализации и итерации для каждой из этих переменных отделяются запятыми. Вот пример:
    // Использование запятых в цикле for. using System; class Comma {

    Глава 5. Инструкции управления
    113 public static void Main() { int i, j; for(i=0, j=10; i < j; i++, j--)
    Console.WriteLine("i и j: " + i + " " + j);
    }
    }
    Вот как выглядят результаты выполнения этой программы: i и j: 0 10 i и j: 1 9 i и j: 2 8 i и j: 3 7 i и j: 4 6
    Здесь запятыми отделяются две инструкции инициализации и два итерационных выражения. При входе в цикл инициализируются обе переменные — i
    и j
    . После выполнения каждой итерации цикла переменная i
    инкрементируется, а переменная j
    декрементируется. Использование нескольких управляющих переменных в цикле иногда позволяет упростить алгоритмы. В разделах инициализации и итерации цикла for можно использовать любое количество инструкций, но обычно их число не превышает двух.
    Приведем пример практического использования двух управляющих переменных в цикле for
    . Рассмотрим программу, которая находит наибольший и наименьший множители числа (в данном случае числа 100). Обратите особое внимание на условие завершения цикла: оно включает обе управляющих переменных.
    /*
    Использование запятых в цикле for для определения наибольшего и наименьшего множителей числа. */ using System; class Comma { public static void Main() { int i, j; int smallest, largest; int num; num = 100; smallest = largest = 1; for(i=2, j=num/2; (i <= num/2) & (j >= 2); i++, j--) { if((smallest == 1) & ((num % i) == 0)) smallest
    = i; if((largest == 1) & ((num % j) == 0)) largest
    = j;
    }
    Console.WriteLine("Наибольший множитель: " + largest);
    Console.WriteLine("Наименьший множитель: " + smallest);
    }
    }
    Результаты выполнения этой программы выглядят так:

    114
    Часть I. Язык C#
    Наибольший множитель: 50
    Наименьший множитель: 2
    Благодаря использованию сразу двух управляющих переменных в одном цикле for можно найти как наибольший, так и наименьший множитель числа. Для определения наименьшего множителя используется управляющая переменная i
    . Первоначально она устанавливается равной числу 2 и инкрементируется до тех пор, пока ее значение не превысит половину исследуемого числа (оно хранится в переменной num
    ). Для определения наибольшего множителя используется управляющая переменная j
    . Первоначально она устанавливается равной половине числа, хранимого в переменной num
    , и декрементируется до тех пор, пока ее значение не станет меньше двух. Цикл работает до тех пор, пока обе переменные — i
    и j
    — не достигнут своих конечных значений. По завершении цикла будут найдены оба множителя.
    Условное выражение
    Условным выражением, которое управляет циклом for
    , может быть любое допустимое выражение, генерирующее результат типа bool
    . Например, в следующей программе цикл управляется переменной done
    // Условием цикла может быть любое выражение типа bool. using System; class forDemo { public static void Main() { int i, j; bool done = false; for(i=0, j=100; !done; i++, j--) { if(i*i >= j) done = true;
    Console.WriteLine("i, j: " + i + " " + j);
    }
    }
    }
    А вот результаты выполнения этой программы: i, j: 0 100 i, j: 1 99 i, j: 2 98 i, j: 3 97 i, j: 4 96 i, j: 5 95 i, j: 6 94 i, j: 7 93 i, j: 8 92 i, j: 9 91 i, j: 10 90
    В этом примере цикл for повторяется до тех пор, пока bool
    -переменная done имеет значение true
    . Эта переменная устанавливается равной true внутри цикла, если квадрат значения переменной i
    больше значения переменной j
    или равен ему.

    Глава 5. Инструкции управления
    115
    Отсутствие элементов в определении цикла
    В C# разрешается опустить любой элемент заголовка цикла (инициализация, условие, итерация) или даже все сразу. Отсутствие некоторых элементов в определении цикла может дать интересный результат. Рассмотрим следующую программу:
    // Составляющие части цикла for могут быть пустыми. using System; class Empty { public static void Main() { int i; for(i = 0; i < 10; ) {
    Console.WriteLine("Проход №" + i); i++;
    //
    Инкрементируем управляющую переменную цикла.
    }
    }
    }
    Здесь отсутствует выражение итерации цикла for
    . Вместо него инкрементирование управляющей переменной i
    выполняет инструкция, находящаяся внутри цикла. Это значит, что перед каждым повторением тела цикла выполняется только одно действие: значение переменной i
    сравнивается с числом 10. Но поскольку значение i
    инкрементируется внутри цикла, он функционирует нормально, отображая следующие результаты:
    Проход №0
    Проход №1
    Проход №2
    Проход №3
    Проход №4
    Проход №5
    Проход №6
    Проход №7
    Проход №8
    Проход №9
    В следующем примере из определения цикла for удалена и часть инициализации управляющей переменной.
    // Определение цикла for состоит из одного условия. using System; class Empty2 { public static void Main() { int i; i = 0; // Убираем из цикла раздел инициализации. for(; i < 10; ) {
    Console.WriteLine("Проход №" + i); i++;
    //
    Инкрементируем управляющую переменную цикла.
    }
    }
    }
    В этой версии переменная i
    инициализируется до входа в цикл for
    , а не в его заголовке. Обычно программисты предпочитают инициализировать управляющую переменную цикла внутри цикла for
    . К размещению выражения инициализации за

    116
    Часть I. Язык C# пределами цикла, как правило, прибегают только в том случае, когда начальное значение генерируется сложным процессом, который неудобно поместить в определение цикла.
    Бесконечный цикл
    Оставив пустым условное выражение цикла for
    , можно создать бесконечный цикл
    (цикл, который никогда не заканчивается). Например, в следующем фрагменте программы показан способ, который используют многие C#-программисты для создания бесконечного цикла. for(;;) // Специально созданный бесконечный цикл.
    {
    // ...
    }
    Этот цикл будет работать без конца. Несмотря на существование некоторых задач программирования (например, командных процессоров операционных систем), которые требуют наличия бесконечного цикла, большинство “бесконечных циклов” — это просто циклы со специальными требованиями к завершению. Ближе к концу этой главы будет показано, как завершить цикл такого типа. (Подсказка: с помощью инструкции break
    .)
    Циклы без тела
    В C# тело, связанное с циклом for
    (или каким-нибудь другим циклом), может быть пустым. Дело в том, что пустая инструкция синтаксически допустима. “Бестелесные” циклы часто оказываются полезными. Например, следующая программа использует
    “бестелесный” цикл для получения суммы чисел от 1 до 5.
    // Тело цикла может быть пустым. using System; class Empty3 { public static void Main() { int i; int sum = 0;
    //
    Суммируем числа от 1 до 5. for(i =1; i <= 5; sum += i++);
    Console.WriteLine("Сумма равна " + sum);
    }
    }
    Результат работы этой программы весьма лаконичен: сумма равна 15
    Обратите внимание на то, что процесс суммирования полностью выполняется внутри инструкции for
    , поэтому и в теле цикла отпала необходимость. Особое внимание обратите на итерационное выражение: sum += i++
    Не стоит пугаться инструкций, подобных этой. Они весьма распространены в профессиональной среде и легко понимаются, если их разбить на части. Эта инструкция означает, что в переменную sum необходимо поместить результат сложения текущего значения переменной sum и значения переменной i
    , а затем инкрементировать

    Глава 5. Инструкции управления
    117 значение переменной i
    . Таким образом, предыдущая инструкция эквивалентна следующим: sum = sum + i;
    Объявление управляющей переменной в цикле for
    Часто переменная, которая управляет циклом for
    , необходима только для этого цикла и больше никак не используется. В этом случае можно объявить ее в разделе инициализации цикла. Например, следующая программа вычисляет как сумму, так и факториал чисел от 1 до 5. Управляющая переменная i
    здесь объявляется в цикле for
    // Объявление управляющей переменной в цикле for. using System; class ForVar { public static void Main() { int sum = 0; int fact = 1;
    //
    Вычисляем сумму и факториал чисел от 1 до 5. for(int i = 1; i <= 5; i++) { sum += i; // i известна только в пределах цикла. fact *= i;
    }
    //Но здесь переменная i неизвестна.
    Console.WriteLine("Сумма равна " + sum);
    Console.WriteLine("Факториал равен " + fact);
    }
    }
    При объявлении переменной внутри цикла for необходимо помнить следующее: ее область видимости завершается с завершением этого цикла. Другими словами, область видимости этой переменной ограничена циклом for
    . Вне цикла такая переменная прекращает свое существование. Таким образом, в предыдущем примере переменная i
    недоступна вне цикла for
    . Если нужно использовать управляющую переменную цикла еще где-то в программе, вы не должны объявлять ее внутри цикла for
    Прежде чем двигаться дальше, не помешало бы поэкспериментировать с собственными вариациями на тему цикла for
    Цикл while
    Общая форма цикла while имеет такой вид: while(
    условие
    )
    инструкция
    ;
    Здесь под элементом
    инструкция
    понимается либо одиночная инструкция, либо блок инструкций. Работой цикла управляет элемент
    условие
    , который представляет собой любое допустимое выражение типа bool
    . Элемент
    инструкция
    выполняется до тех пор, пока условное выражение возвращает значение ИСТИНА. Как только это
    условие
    становится ложным, управление передается инструкции, которая следует за этим циклом.

    118
    Часть I. Язык C#
    Перед вами простой пример, в котором цикл while используется для вычисления порядка заданного целого числа.
    // Вычисление порядка целого числа. using System; class WhileDemo { public static void Main() { int num; int mag; num = 435679; mag = 0;
    Console.WriteLine("Число: " + num); while(num > 0) { mag++; num = num / 10;
    };
    Console.WriteLine("Порядок: " + mag);
    }
    }
    А вот результаты выполнения этой программы:
    Число: 435679 Порядок: 6
    Цикл while работает следующим образом. Проверяется значение переменной num
    Если оно больше нуля, счетчик mag инкрементируется, а значение num делится на 10. Цикл повторяется до тех пор, пока num больше нуля. Когда num станет равным нулю, цикл завершится, а переменная mag будет содержать порядок исходного числа.
    Подобно циклу for
    , условное выражение проверяется при входе в цикл while
    , a это значит, что тело цикла может не выполниться ни разу. Это свойство цикла
    (иллюстрируемое следующей программой) устраняет необходимость отдельного тестирования до начала цикла.
    // Вычисление целых степеней числа 2. using System; class Power { public static void Main() { int e; int result; for(int i=0; i < 10; i++) { result = 1; e
    = i; while(e > 0) { result
    *=
    2; e--;
    }
    Console.WriteLine("2 в степени " + i +
    " равно " + result);

    Глава 5. Инструкции управления
    119
    }
    }
    }
    Результаты выполнения этой программы выглядят так:
    2 в степени 0 равно 1 2 в степени 1 равно 2 2 в степени 2 равно 3 2 в степени 3 равно 4 2 в степени 4 равно 16 2 в степени 5 равно 32 2 в степени 6 равно 64 2 в степени 7 равно 128 2 в степени 8 равно 256 2 в степени 9 равно 512
    Обратите внимание на то, что цикл while выполняется только в том случае, если значение переменной е
    больше нуля. Таким образом, когда е
    равно нулю, что имеет место в первой итерации цикла for
    , цикл while опускается.
    Цикл do-while
    Третьим циклом в C# является цикл do-while
    . В отличие от циклов for и while
    , в которых условие проверяется при входе, цикл do-while проверяет условие при выходе из цикла. Это значит, что цикл do-while всегда выполняется хотя бы один раз. Его общий формат имеет такой вид: do {
    инструкции
    ;
    } while(
    условие
    );
    Несмотря на то что фигурные скобки необязательны, если элемент
    инструкции
    состоит только из одной инструкции, они часто используются для улучшения читабельности конструкции do-while
    , не допуская тем самым путаницы с циклом while
    Цикл do-while выполняется до тех пор, пока остается истинным элемент
    условие
    ,
    который представляет собой условное выражение.
    В следующей программе цикл do-while используется для отображения в обратном порядке цифр, составляющих заданное целое число.
    // Отображение в обратном порядке цифр целого числа. using System; class DoWhileDemo { public static void Main() { int num; int nextdigit; num = 198;
    Console.WriteLine("Число: " + num);
    Console.Write("Число с обратным порядком цифр: "); do
    { nextdigit = num % 10;
    Console.Write(nextdigit);

    120
    Часть I. Язык C# num = num / 10;
    } while(num > 0);
    Console.WriteLine();
    }
    }
    Результат выполнения этой программы выглядит так:
    Число: 198 Число с обратным порядком цифр: 891
    Вот как работает этот цикл. На каждой итерации крайняя справа цифра определяется как остаток от целочисленного деления заданного числа на 10. Полученная цифра тут же отображается на экране. Затем результат этого деления запоминается в той же переменной num
    . Поскольку деление целочисленное, его результат равносилен отбрасыванию крайней правой цифры. Этот процесс повторяется до тех пор, пока число num не станет равным нулю.
    Цикл foreach
    Цикл foreach предназначен для опроса элементов коллекции. Коллекция — это группа объектов. В C# определено несколько типов коллекций, среди которых можно выделить массив. Цикл foreach рассматривается в главе 7, посвященной массивам.
    Использование инструкции break для выхода из
    цикла
    С помощью инструкции break можно организовать немедленный выход из цикла, опустив выполнение кода, оставшегося в его теле, и проверку условного выражения. При обнаружении внутри цикла инструкции break цикл завершается, а управление передается инструкции, следующей после цикла. Рассмотрим простой пример.
    // Использование инструкции break для выхода из цикла. using System; class BreakDemo { public static void Main() {
    //
    Используем break для выхода из цикла. for(int i=-10; i <= 10; i++) { if(i > 0) break; // Завершение цикла при i > 0.
    Console.Write(i + " ");
    }
    Console.WriteLine("Готово!");
    }
    }
    Эта программа генерирует следующие результаты:
    -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 Готово!

    Глава 5. Инструкции управления
    121
    Как видите, несмотря на то, что этот цикл for спроектирован для перебора значений i
    в диапазоне от —10 до 10, инструкция break
    “досрочно” прекращает его выполнение, когда значение переменной i
    становится положительным.
    Инструкцию break можно использовать с любым C#-циклом, включая
    “бесконечный”. Например, предыдущая программа, переделанная для использования do- while
    -цикла, имеет следующий вид:
    // Использование инструкции break для выхода
    // из цикла do-while. using System; class BreakDemo2 { public static void Main() { int i; i = -10; do
    { if(i > 0) break;
    Console.Write(i + " "); i++;
    } while(i <= 10);
    Console.WriteLine("Готово!");
    }
    }
    Теперь рассмотрим более реальный пример. Следующая программа находит наименьший множитель заданного числа.
    // Определение наименьшего множителя числа. using System; class FindSmallestFactor { public static void Main() { int factor = 1; int num = 1000; for(int i=2; i < num/2; i++) { if((num%i) == 0) { factor
    = i; break;
    //
    Цикл прекращается, когда найден множитель.
    }
    }
    Console.WriteLine(
    "Наименьший множитель равен " + factor);
    }
    }
    Результаты выполнения этой программы выглядят так:
    Наименьший множитель равен 2
    Здесь инструкция break останавливает выполнение цикла for
    , как только находит множитель числа. Тем самым предотвращается попытка опробовать любые другие значения
    — кандидаты на “звание” множителя.
    При использовании внутри множества вложенных циклов инструкция break прерывает только самый внутренний цикл.

    122
    Часть I. Язык C#
    // Использование инструкции break с вложенными циклами. using System; class BreakNested { public static void Main() { for(int i=0; i<3; i++) {
    Console.WriteLine(
    "Подсчет итераций внешнего цикла: " + i);
    Console.Write(
    " Подсчет итераций внутреннего цикла: "); int t = 0; while(t < 100) { if(t == 10) break; // Останов цикла, когда
    // t равно 10.
    Console.Write(t + " "); t++;
    }
    Console.WriteLine();
    }
    Console.WriteLine("Циклы завершены.");
    }
    }
    Результаты работы этой программы выглядят следующим образом:
    Подсчет итераций внешнего цикла: 0
    Подсчет итераций внутреннего цикла: 0123456789
    Подсчет итераций внешнего цикла: 1
    Подсчет итераций внутреннего цикла: 0123456789
    Подсчет итераций внешнего цикла: 2
    Подсчет итераций внутреннего цикла: 0123456789
    Циклы завершены.
    Как видите, инструкция break
    , находящаяся во внутреннем цикле, прекращает выполнение только этого цикла, а на внешний не оказывает никакого воздействия.
    Хотелось бы также обратить ваше внимание на то, что в одном цикле можно использовать не одну, а несколько инструкций break
    , однако слишком большое их количество способно нарушить структуру кода. И еще. Инструкция break
    , которая завершает выполнение инструкции switch
    , влияет только на инструкцию switch
    , а не на содержащий ее цикл.
    Использование инструкции continue
    Помимо средства “досрочного” выхода из цикла, существует средство “досрочного” выхода из текущей его итерации. Этим средством является инструкция continue
    . Она принудительно выполняет переход к следующей итерации, опуская выполнение оставшегося кода в текущей. Инструкцию continue можно расценивать как дополнение к более “радикальной” инструкции break
    . Например, в следующей программе используется инструкция continue для “ускоренного” поиска четных чисел в диапазоне от 0 до 100.
    // Использование инструкции continue. using System;

    Глава 5. Инструкции управления
    123 class ContDemo { public static void Main() {
    //
    Выводим четные числа между 0 и 100. for(int i = 0; i <= 100; i++) { if((i%2) != 0) continue;
    // переход на следующую
    // итерацию.
    Console.WriteLine(i);
    }
    }
    }
    Здесь выводятся только четные числа, поскольку при обнаружении нечетного числа происходит преждевременный переход к следующей итерации, а метод
    WriteLine()
    не вызывается.
    В циклах while и do-while инструкция continue передает управление непосредственно инструкции, проверяющей условное выражение, после чего циклический процесс продолжает “идти своим чередом”. А в цикле for после выполнения инструкции continue сначала вычисляется итерационное выражение, а затем — условное. И только после этого циклический процесс будет продолжен.
    Инструкция continue используется программистами не слишком часто, хотя в некоторых случаях он оказывается весьма кстати.
    Инструкция return
    Инструкция return обеспечивает возврат из метода. Ее можно использовать для возвращения методом значения. Подробнее см. главу 6.
    Инструкция goto
    Инструкция goto
    — это C#-инструкция безусловного перехода. При ее выполнении управление программой передается инструкции, указанной с помощью метки. Долгие годы эта инструкция находилась в немилости у программистов, поскольку способствовала, с их точки зрения, созданию “спагетти-кода”. Однако инструкция goto по-прежнему используется, и иногда даже очень эффективно. В этой книге не делается попытка
    “реабилитации” законных прав этой инструкции в качестве одной из форм управления программой. Более того, необходимо отметить, что в любой ситуации (в области программирования) можно обойтись без инструкции goto
    , поскольку она не является элементом, обеспечивающим полноту описания языка программирования. Вместе с тем в определенных ситуациях ее использование может быть очень полезным. В этой книге было решено ограничить использование инструкции goto рамками этого раздела, так как, по мнению большинства программистов, она вносит в программу лишь беспорядок и делает ее практически нечитабельной. Но поскольку использование инструкции goto в некоторых случаях может сделать намерение программиста яснее, ей стоит уделить некоторое внимание.
    Инструкция goto требует наличие в программе метки. Метка — это действительный в C# идентификатор, за которым поставлено двоеточие. Метка должна находиться в одном методе с инструкцией goto
    , которая ссылается на эту метку. Например, с помощью goto можно организовать следующий цикл на 100 итераций: x = 1; loop1: x++; if(x < 100) goto loop1;

    124
    Часть I. Язык C#
    Инструкцию goto можно также использовать для перехода к case
    - или default
    - ветви внутри инструкции switch
    . Ведь, по сути, case
    - и default
    -инструкции являются метками. Следовательно, они могут принимать “эстафету” управления, передаваемую инструкцией goto
    . Но в этом случае инструкция goto должна обязательно находиться в
    “рамках” той же инструкции switch
    . Это значит, что с помощью какой-либо “внешней” инструкции goto нельзя попасть в инструкцию switch
    . Рассмотрим пример, который иллюстрирует использование инструкций goto и switch
    // Использование инструкций goto и switch. using System; class SwitchGoto { public static void Main() { for(int i=1; i < 5; i++) { switch(i)
    { case
    1:
    Console.WriteLine("В ветви case 1"); goto case
    3; case
    2:
    Console.WriteLine("В ветви case 2"); goto case
    1; case
    3:
    Console.WriteLine("В ветви case 3"); goto default; default:
    Console.WriteLine("В ветви default"); break;
    }
    Console.WriteLine();
    }
    // goto case 1; // Ошибка! Нельзя впрыгнуть
    // в инструкцию switch.
    }
    }
    Результаты выполнения этой программы выглядят так:
    В ветви case 1
    В ветви case 3
    В ветви default
    В ветви case 2
    В ветви case 1
    В ветви case 3
    В ветви default
    В ветви case 3
    В ветви default
    В ветви default
    Обратите внимание на то, как используется инструкция goto для перехода к ветвям case и default инструкции switch
    . Обратите также внимание на то, что case
    - последовательность инструкций не завершается инструкцией break
    . Поскольку goto не позволяет case
    -последовательности
    “провалиться” в следующую case
    - последовательность,

    Глава 5. Инструкции управления
    125 то специальное средство от “провала” (
    break
    ) не требуется. Как разъяснялось выше, инструкцию goto нельзя использовать для проникновения извне в switch
    -конструкцию.
    Если удалить символы комментария в начале строки
    // goto case 1; // Ошибка!... то программа не скомпилируется. Использование инструкции goto совместно с инструкцией switch может быть полезно в особых случаях, но не рекомендуется как общий стиль программирования,
    Иногда инструкцию goto стоит использовать для выхода из глубоко вложенных инструкций. Вот простой пример:
    // Демонстрация использования инструкции goto. using System; class Use_goto { public static void Main() { int i=0, j=0, k=0; for(i=0; i < 10; i++) { for(j=0; j < 10; j++) { for(k=0; k < 10; k++) {
    Console.WriteLine("i, j, k: " + i + " " + j + " " + k); if(k == 3) goto stop;
    }
    }
    } stop:
    Console.WriteLine("Все, хватит! i, j, k: " + i +
    ", " + j + ", " + k);
    }
    }
    Результаты выполнения этой программы выглядят так: i, j, k: 0 0 0 i, j, k; 0 0 1 i, j, k: 0 0 2 i, j, k: 0 0 3
    Все, хватит! i, j, k: 0, 0, 3
    Для того чтобы получить такие же результаты, но без инструкции goto
    , пришлось бы использовать три пары инструкций if и break
    . В данном случае инструкция goto существенно упрощает программный код. Несмотря на то что этот пример — совершенно искусственный, вы, вероятно, смогли представить ситуации, в которых применение инструкции goto может иметь преимущества перед другими вариантами.

    Полный справочник по
    1   2   3   4   5   6   7   8   9   10   ...   52


    написать администратору сайта