Шаг 43.
Язык программирования C#. Начала
Управляющие инструкции. Инструкция безусловного перехода goto

    На этом шаге мы рассмотрим синтаксис и пример использования этой инструкции.

    Инструкция безусловного перехода goto позволяет выполнить переход к определенному месту программного кода, помеченному с помощью метки. Метка - это обычный идентификатор, размещаемый в программном коде. Метку не нужно объявлять. Она просто указывается, и после нее следует двоеточие. Если в программном коде воспользоваться инструкцией goto, указав после нее метку из программного кода, то выполнение такой команды приведет к тому, что следующей будет выполняться команда в строке, выделенной с помощью метки.

    Таким образом, инструкция goto позволяет "прыгать" из одного места программного кода к другому, и это не может не вызывать некоторых опасений. Стоит признать, что они небезосновательны. Существует устоявшееся мнение, что наличие в программном коде команд с инструкцией goto - признак дурного тона в программировании. Другими словами, использование инструкции goto - это не тот путь, которым следует идти. Но прежде чем отказаться от использования какого-либо механизма, интересно хотя бы поверхностно оценить его возможности.


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

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

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace pr43_1
{
    class Program
    {
        static void Main()
        {
            // Переменные: количество слагаемых, индексная 
            // переменная и значение суммы: 
            int n = 10, k = 1, s = 0;
            // Отображение сообщения:
            Console.Write("Сумма 1 + 3 + 5 +...+ {0} = ",2*n-1); 
            // Использование метки: 
            mylabel:
            // Добавляем слагаемое в сумму: 
            s += 2 * k - 1;
            // Изменение значения индексной переменной: 
            k++;
            // Использование инструкции goto:
            if(k<=n) goto mylabel; // Переход к помеченному коду
            // Отображение результата вычислений:
            Console.WriteLine(s);
            // Задержка:
            Console.ReadLine();
        }
    }
}
Архив проекта можно взять здесь.

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


Рис.1. Результат выполнения программы

   

    Как же выполняется этот программный код? В принципе, все достаточно просто. В программе использованы, как и ранее, три целочисленные переменные n, k и s, назначение которых не изменилось - это количество слагаемых, индексная переменная и значение суммы чисел. Переменные получают начальные значения при объявлении. В программе использована метка mylabel. Это простой идентификатор, который заканчивается двоеточием. Само по себе наличие метки в программном коде никаких ощутимых последствий не имеет. То есть факт наличия метки на логику выполнения программного кода не влияет. На выполнение программного кода влияет наличие инструкции goto. Более конкретно, код выполняется следующим образом. После объявления и инициализации переменных n, k и s и отображения сообщения о вычислении суммы (команда

Console.Write("Сумма 1 + 3 + 5 +...+ {0} = ", 2*n-1)
) выполняются команды s+=2*k-l (добавление слагаемого в сумму) и k++ (увеличение значения переменной на единицу). Вообще, поскольку данные команды не находятся в теле цикла, то они должны были бы выполняться только один раз. Интрига появляется, когда дело доходит до выполнения условной конструкции. В нем проверяется условие k<=n. Если условие истинно, то выполняется команда goto mylabel. Эта команда означает, что продолжать выполнение программы следует с того места, которое выделено меткой mylabel. Несложно заметить, что сразу после метки mylabel находится команда s+=2*k-l. Поэтому в результате перехода из-за команды goto mylabel снова будет выполняться команда s+=2*k-1,азатем и команда k++. После этого на сцену опять выходит условная конструкция, и при истинном условии k<=n выполнение программы будет продолжено с места, выделенного меткой mylabel. Поскольку каждый раз значение переменной k увеличивается на единицу, то в какой-то момент при проверке условия k<=n оно окажется ложным, и команда goto mylabel выполнена не будет. Тогда выполнится следующая команда после условной конструкции, в которой отображается вычисленное значение для суммы нечетных чисел. Таким образом, получается, что с помощью условной конструкции и инструкции goto мы организовали некое подобие цикла, хотя ни одна из циклических конструкций использована не была.


В плане алгоритма выполнения программы с инструкцией goto она аналогична программе для вычисления суммы нечетных чисел, реализованной с использованием конструкции цикла do-while (см. 40 шаг).

    На следующем шаге мы рассмотрим перехват исключений.




Предыдущий шаг Содержание Следующий шаг