Завдання 6 Дедлайн 23 листопада

Дайте відповіді на питання:

1. Чи є відмінність в роботі конструкцій while(true) та for(;;)?

2. Наступний цикл для зворотного відліку нескінченний. Чому?

for (unsigned i = 10; i >= 0; --i) {
          // ...
}

3. Щоб завершити роботу циклу є ключове слово break, проте воно завершує лише поточний цикл. Продемонструйте хоча б один спосіб завершити роботу всіх циклів у випадку, якщо вони вкладені (можна використовувати будь-які засоби):

while (true) { // Цикл 1.
    while (true) { // Цикл 2.
        if (/* Виявлена певна умова. Потрібно вийти з обох циклів */) {
            // ...
        }
    }
    // ...
}
// ...

4. Дано цикл який виводить введене число, якщо воно не 0. Якщо 0, то цикл завершує роботу.

  • Знайдіть і виправте помилку в коді програми.
  • Запропонуйте, як можна оптимізувати подвійну перевірку на нуль в тілі циклу.
#include <iostream>

int main() {
    unsigned i;
    while (i != 0) {
        std::cin >> i;
        if (i != 0) {
            std::cout << "i is " << i << std::endl;
        }
    }
    return 0;
}

Відповідь

1. Вони ідентичні, обидві означають нескінченний цикл.

2. При зворотній індексації важливо звертати увагу на тип індекса. Параметр циклу i не може набувати від’ємних значень. Якщо в кінці від 0 відняти 1, то відбудеться переповнення, і замість -1 індекс i матиме максимально можливе значення типу unsigned (232 — 1), яке звісно більше за 0. Після цього цикл зробить 232 ітерацій, і ситуація повториться знову.

3. Перший варіант — використати додаткову змінну:

while (true) { // Цикл 1.
    bool breakthrough = false;
    while (true) { // Цикл 2.
        if (/* Виявлена певна умова. Потрібно вийти з обох циклів */) {
            breakthrough = true;
            break;
        }
    }
    if (breakthrough) {
        break;
    }
}

Цей спосіб є прийнятним в C++, і не повинен викликати дискусій при код рев’ю.Другий варіант — використання ключового слова goto, яке є “стрибком” до наперед позначеного рядка коду:





while (true) { // Цикл 1.
        while (true) { // Цикл 2.
            if (/* Виявлена певна умова. Потрібно вийти з обох циклів */) {
                goto breakthrough;
            }
        }
    }
// Синтаксис мітки (label). Це рядок коду, до якого потрібно зробити "стрибок".
// Відступ зазвичай на рівень нижче, щоб візуально виділити.
breakthrough:
    // ...

Рекомендація: краще не використовувати goto. Це візуально більш компактний спосіб, але навіть в простих випадках він є джерелом проблем в C++:

  • Не ініціалізовані змінні.
  • Не звільнені ресурси.
  • Доступ до вже звільнених ресурсів.

4. Помилкою є те, що змінна i не проініціалізована, тому її значення невизначене, і цикл може завершитись негайно, якщо значення 0. Це можна виправити просто проініціалізувавши змінну значенням, відмінним від 0.

Подвійну перевірку можна оптимізувати, забравши її з while і переформулювавши її: завершити цикл, якщо i рівне 0. Це одночасно вирішує проблему з неініціалізованою змінною i, бо тепер вона буде зчитана з консолі до того, як її значення перевіряється:

#include <iostream>

int main() {
   unsigned i;
   while (true) {
       std::cin >> i;
       if (i == 0) {
           break;
       }
       std::cout << "i is " << i << std::endl;
   }
   return 0;
}

Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Максимальный размер загружаемого файла: 1 ГБ. Вы можете загрузить: изображение, аудио, видео, документ, таблица, интерактив, текст, архив, код, другое. Ссылки на YouTube, Facebook, Twitter и другие сервисы, вставленные в текст комментария, будут автоматически встроены. Перетащите файл сюда