Дайте відповіді на питання:
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;
}
Добавить комментарий