Оператор goto в C: синтаксис, практическое применение и лучшие практики
Оператор goto в C
В этом руководстве вы узнаете, как работает оператор goto в C, его правильный синтаксис, когда он может быть полезен и почему его обычно избегают в современном коде.
Синтаксис оператора goto
goto label;
...
label: statement;
label — это идентификатор, за которым следует двоеточие. При выполнении goto управление безусловно переходит к строке с этой меткой.

Пример: Использование goto для раннего выхода из цикла
#include <stdio.h>
int main() {
const int maxInput = 100;
int i;
double number, average, sum = 0.0;
for (i = 1; i <= maxInput; ++i) {
printf("%d. Enter a number: ", i);
scanf("%lf", &number);
/* Если пользователь ввёл отрицательное число, пропускаем остаток цикла */
if (number < 0.0) {
goto exit_loop;
}
sum += number;
}
exit_loop:
average = sum / (i - 1);
printf("Sum = %.2f\n", sum);
printf("Average = %.2f", average);
return 0;
}
Вывод
1. Enter a number: 3 2. Enter a number: 4.3 3. Enter a number: 9.3 4. Enter a number: -2.9 Sum = 16.60 Average = 5.53
Почему большинство разработчиков избегают goto
Оператор goto может создавать «спагетти-код», трудный для чтения, тестирования и поддержки. Например:
one:
for (i = 0; i < number; ++i) {
test += i;
goto two;
}
two:
if (test > 5) {
goto three;
}
// ...
Прыжки из вложенных областей видимости или через сложные управляющие структуры часто скрывают поток программы, приводя к багам, которые сложно диагностировать.
Когда goto всё ещё может быть уместен
Хотя редко нужен, goto может упростить специфические сценарии, такие как:
- Выход из глубоко вложенных циклов без множественных флагов.
- Централизация кода очистки перед выходом из функции.
Используйте его экономно и всегда документируйте намерение, чтобы будущие сопровождающие понимали цель перехода.
Стоит ли использовать goto?
В большинстве современных программ на C структурные конструкции управления потоком — циклы, функции, switch — покрывают варианты использования goto. Стандарт C и лучшие практики рекомендуют избегать его, если нет веской причины. Как отметил Бьярн Страуструп, создатель C++: "Тот факт, что 'goto' может делать что угодно, — именно почему мы его не используем."
В конечном счёте, если можно достичь той же логики с чистым, структурированным кодом — выбирайте этот путь. Резервируйте goto для редких, хорошо обоснованных ситуаций и тщательно документируйте его.
Идиоматический паттерн: goto для очистки ошибок
Один из уместных случаев — централизованная очистка ресурсов при ошибках:
int func() {
int* p = malloc(sizeof(int));
if (!p) goto error;
FILE* f = fopen("data.txt", "r");
if (!f) goto error_free_p;
// работа с ресурсами...
fclose(f);
free(p);
return 0;
error_free_p:
free(p);
error:
return -1;
}
Этот паттерн распространён в системном коде (ядро Linux, драйверы), где исключений нет, а RAII недоступен.
Язык C
- Бипер (пейджер): от ранних инноваций к двусторонней связи завтрашнего дня
- Условная логика в C#: if, if-else, if-else-if и вложенные if
- Освоение оператора switch в C#: синтаксис, примеры и лучшие практики
- Оператор break в C#: как и когда использовать
- Оператор continue в C#: как эффективно пропускать итерации циклов
- Освоение условных операторов C++: if, if...else и вложенные if...else
- Оператор pass в Python: практическое руководство
- Базовый синтаксис C: токены, идентификаторы, ключевые слова и пробелы
- Числа в Python: Неизменяемые числовые типы данных
- Артикул (парт-номбер): роль в инвентаризации и продажах