Для проти в той час як в програмуванні на C?


78

Є три петлі в C: for, whileі do-while. Яка різниця між ними?

Наприклад, здається, майже всі whileтвердження можна замінити forтвердженнями, так? Тоді, в чому перевага while?


9
Ви забули умовний GOTOцикл. Хоча люди не сприймають це як цикл, я вважаю, що всі цикли по суті компілюються до циклів умовного GOTO.
Armstrongest

1
Хіба рекурсія також не розглядається як цикл?
Nyan

чи не було б простіше написати компілятор, який у x86 isa компілює простий цикл for в більш ефективну loopінструкцію (віднімання, порівняння та перехід в одній інструкції), ніж компілюючий whileв loopінструкцію? чи компілятори нинішнього часу компілюються forв loopінструкцію?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Відповіді:


166

У той час як петля завжди буде оцінювати стан першого.

Робити / в той час як цикл завжди буде виконувати код в do{}блоці першого , а потім оцінити стан.

Цикл дозволяє ініціювати змінний лічильник, умова перевірки, і спосіб , щоб збільшити ваш лічильник все в одному рядку.

Зрештою, вони все ще є петлями, але вони пропонують певну гнучкість щодо того, як вони виконуються.

Ось чудове пояснення міркувань щодо використання кожного іншого типу циклу, що може допомогти прояснити ситуацію. Спасибі clyfe

Основна різниця між for's і while' s полягає у питаннях прагматики: ми зазвичай використовуємо, forколи існує відома кількість ітерацій, і використовуємо whileконструкції, коли кількість ітерацій невідомо заздалегідь. Випуск whilevs do ... while також стосується прагматики, другий виконує інструкції один раз при запуску, а згодом він поводиться так само, як і простий час.


Бо петлі особливо приємні, оскільки вони лаконічні. Для цього для циклу for:

щоб записати як цикл while, вам доведеться зробити наступне:

У цьому випадку є просто більше речей, за якими слід встигати, і вони count++;можуть загубитися в логіці. Це може закінчитися проблемою залежно від того, де countзбільшується, і чи слід збільшувати його до або після логіки циклу. За допомогою forциклу ваша змінна лічильника завжди збільшується до наступної ітерації циклу, що додає деякій однорідності коду.


Заради повноти, ймовірно, є сенс поговорити про breakтаcontinue твердження, які стануть в нагоді при обробці циклу.

break миттєво припинить поточний цикл і більше ітерацій виконуватися не буде.

continue припинить поточну ітерацію та перейде до наступної.

Зверніть увагу, що у циклі for continueобчислює part3вираз for (part1; part2; part3); на відміну від цього, у циклі while він просто перескакує, щоб переоцінити стан циклу.


7
Чи варто обговорювати поведінку "продовжувати;" у циклі 'for' проти циклу 'while'? В іншому випадку хороша відповідь.
Джонатан Леффлер,

3
+1 за чудову відповідь. Варто зазначити: для циклів не потрібна змінна лічильника. У мовах стилю С вони фактично призначені для (<оператор запуску>; <продовження>; <виконання після кожної ітерації>). Буває так, що найпоширенішим використанням є змінна counter: for (int x = 0 [start]; x <100 [continue?]; ++ x [post-iteration])
Шон Едвардс

10
Основна різниця між for'sі while'sє питанням прагматики: ми зазвичай використовуємо, forколи існує відома кількість ітерацій , і використовуємо whileконструкції, коли кількість ітерацій невідомо заздалегідь . Випуск whilevs do ... whileтакож стосується прагматики, другий виконує інструкції один раз при запуску, а згодом він поводиться так само, як і простий while.
clyfe

2
+1 добре написана відповідь, і іноді перегляд "основ" корисний для всіх
JYelton

1
Мені подобається відповідь, особливо в тій частині, де ви говорите про рівномірність збільшення лічильника у випадку "за" проти потенційно в будь-якому місці ітерації у випадку "в той час". Чесно кажучи, я ніколи б не висловився так красномовно, хоча тут не так багато нового
Шраван,

16

Якщо існує серйозне занепокоєння щодо швидкості та продуктивності, найкращим підходом є перевірка коду, створеного компілятором, на рівні збірки.

Наприклад, наступний код показує, що "виконувати" трохи швидше. Це тому, що інструкція "jmp" не використовується циклом "do-while".

До речі, у цьому конкретному прикладі найгірший випадок дається циклом "for". :))

// "ЗА" ЦИКЛ:

// "ПОКА" ЛОП:

// "ЗАКРІПЛЕННЯ":


11

Заради читабельності


3
Щодо цього, ви також можете використовувати goto як цикл.
WhirlWind

Інша справа - рекурсія. І ви можете замінити будь-який стиль циклу будь-яким іншим стилем.
WhirlWind

10
Насправді ... всі цикли насправді є просто фантазійними гілками GOTO.
Armstrongest

@WhirlWind За винятком того, що в мовах без рекурсії у вас, ймовірно, закінчиться переповнення стека. (І ви можете опинитися тут і запитати про переповнення стеку, що змусить мене трохи посміхнутися.)
Шон Едвардс

@Sean yeah, я думав про це, і якщо є спосіб обійти переповнення стека. Звичайно, якщо є рекурсія хвоста ...
WhirlWind

10

Всі вони взаємозамінні; ви можете вибрати один тип і не використовувати нічого, крім цього назавжди, але зазвичай один зручніший для даного завдання. Це все одно, що сказати "навіщо комутатор, ви можете просто використати купу операторів if" - правда, але якщо це звичайний шаблон перевірки змінної на набір значень, це зручно і набагато легше читати, якщо є мовна функція для цього


4
Не зовсім. І на час, і на час може виконувати тіло нуль разів - виконувати не можна.

4
@ Ніл do {if(!cond) break; /* do stuff */ } while(cond);. Некрасиво і повторюється, але це свого роду міркування про те, чому існують варіації :)
Michael Mrozek

@Neil: Ви можете використовувати додатковий прапор, щоб пропустити перше виконання. Взаємозамінні нічого не говорять про те, наскільки це просто або корисно. ;)
Захищений

3
Тіло циклу все ще введено - це не так поки що і для.

2
@Neil Ну, для певних визначень поняття "тіло циклу". Це спричиняє однакову поведінку в будь-якому випадку - вона не запускає /* do stuff */частину, якщо condвона хибна
Michael Mrozek

8

Якщо ви хочете, щоб цикл виконувався, якщо умова є істинним, а не для певної кількості ітерацій, комусь іншому набагато легше зрозуміти:

ніж щось подібне:


Я не знаю про набагато легше. Я ризикнув би здогадатися, що якби C не мав першої форми, ми всі вже звикли бачити другу.
кафе

Досить справедливо, але я гарантую, що я б подумав "WTF", якби побачив другу версію в будь-якому коді, який я підтримував ...
Джастін Етьє

2
Кодекс слід читати як прозу, перший набагато ближче до природної мови. Можливо, не "набагато простіше", але, швидше за все, набагато швидше розпізнати і зрозуміти.
FredCooke,

5

Пам'ятайте, forцикл - це, по суті, вигаданий whileцикл. Вони одне і те ж.

Перевага циклу for полягає в тому, що важче випадково виконати нескінченний цикл. Вірніше, це стає більш очевидним, коли ви це робите, оскільки зазвичай ви вводите цикл var у початковий оператор.

whileЦикл більш ясно , коли ви не робите стандартний шаблон инкрементирование. Наприклад:


6
Однак є одна тонка різниця між for () та виписуванням його як деякий час (): ви змінюєте поведінку continue. У випадку for () continue виконує крок приросту перед перевіркою умови, тоді як у while () continue перейде прямо назад до умови.
Rup

Так, дуже хороший момент. Крім того, я думаю, що люди забувають, це те, що, коли справа доходить до цього, всі цикли компілюються в оператори GOTO.
Armstrongest

Я думаю, саме тому, хоча цикли частіше призводять до нескінченних помилок циклу - крок приросту можна пропустити десь продовженням.
Michael Mathews

@ Майкл: Так, дуже правда. forпетлі, ймовірно, були введені як зручність та продуктивні методи.
Armstrongest

@Rup Дуже хороший момент. Я завжди вважав синтаксичним цукром певний час, але продовження поведінки означає, що це неправда.
JeremyP

4

Ви повинні використовувати такий цикл, який найбільш повно відповідає вашим потребам. Наприклад:

Очевидно, що в такій ситуації "for" виглядає краще, ніж "while". І "робити поки" слід використовувати, коли деякі операції повинні бути зроблені вже до того моменту, коли стан вашого циклу буде перевірено.

Вибачте за мою погану англійську).


4

Одне з поширених непорозумінь із while/ forциклами, яке я бачив, полягає в тому, що їх ефективність відрізняється. Whileпетлі та forпетлі однаково ефективні . Пам’ятаю, мій учитель комп’ютера з середньої школи сказав мені, що цикли ефективніші для ітерації, коли доводиться збільшувати число. Це не так.

Forцикли - це просто синтаксично зацукровані while цикли і роблять код ітерації швидшим для запису.

Коли компілятор бере ваш код і компілює його, він переводить його у форму, яку комп'ютеру легше зрозуміти та виконати на нижчому рівні (збірка). Під час цього перекладу тонкі відмінності між синтаксисами whileта та forвтрачаються, і вони стають абсолютно однаковими.


"Адже цикли просто синтаксично цукруються, тоді як цикли": як уже зазначалося в одному з коментарів вище, це не є суворо правильним. Продовження всередині for не обходить вираз циклу (наприклад, i ++ in for (i = 0 i < limit ; i++).
JeremyP,

3

A forПередбачає фіксовані ітерації з використанням індексу або варіантами за цією схемою.

А whileіdo... while є конструкції використовується , коли є умова , яка повинна бути перевірено кожен раз ( за винятком деякого індексу Двійник конструкції, см . Вище) Вони відрізняються тим, коли виконується перше виконання перевірки стану.

Ви можете використовувати будь-яку конструкцію, але вони мають свої переваги та недоліки залежно від вашого випадку використання.


3

Я помітив деякий час тому, що цикл For зазвичай генерує на кілька машинних інструкцій більше, ніж цикл while. Однак, якщо ви уважно придивитеся до прикладів, які відображають мої спостереження, різниця полягає в двох-трьох машинних інструкціях, навряд чи варта великого розгляду.

Також зауважте, що ініціалізатор циклу WHILE можна усунути, вписавши його в код, наприклад:

Статичний модифікатор виписує початкове значення в коді, зберігаючи (удар барабана) одну інструкцію MOV. Більше значення має позначення змінної як статичної, що переміщує її за рамки стека. Дозволяє вирівнювання за змінним, він також може виробляти дещо менший код, оскільки інструкція MOV та її операнди займають більше місця, ніж, наприклад, ціле число, булеве значення або значення символу (або ANSI, або Unicode).

Однак, якщо змінні вирівняні за межами 8 байтів, загальний параметр за замовчуванням, int, bool або TCHAR, запечений у коді, коштує таку ж кількість байт, як інструкція MOV.


2

Вони однакові в роботі, яку виконують. Ви можете робити ті самі речі, використовуючи будь-яку з них. Але щодо читабельності, зручності використання, зручності тощо вони відрізняються.


2

Різниця між while і do-while полягає в тому, що while перевіряє стан циклу, і якщо це відповідає дійсності, тіло виконується і умова перевіряється знову. Do-while перевіряє стан після виконання тіла, тому з do-while тіло виконується принаймні один раз.

Звичайно, ви можете написати цикл while як do-while та vv, але це зазвичай вимагає певного копіювання коду.


2

Однією особливістю do whileє те, що вам потрібно через деякий час ставити двокрапку для завершення. Він часто використовується у визначеннях макросів для виконання декількох операторів лише один раз, обмежуючи вплив макросу. Якщо макроси визначені як блоки, можуть виникнути помилки аналізу.

Одне з пояснень серед інших


1
Це жахливо хак , хоча, це не велика причина do-whileіснує
Майкл Mrozek

Ні, я ніколи цього не говорив, але це одне з дійсно специфічних методів роботи, який є досить поширеним.
LB40,

@Michael, так, це хак, але це справді загальновживаний, який змушує макрос, що містить декілька тверджень, поводитися повністю, як очікувалось, у всіх синтаксичних контекстах.
JeremyP

@JeremyP Я знаю, я теж його використовую, але це не справжній випадок використання do-while, він просто використовується, тому що трапляється, щоб створити блок і все одно вимагає крапки з комою в кінці
Майкл Мрозек

я просто хотів вказати саме на це використання do-while. Частково питання полягало в тому, які відмінності ... і це одна різниця. (але я погоджуюсь, це хакерство)
LB40,

2

Для циклів (принаймні, враховуючи C99) перевершують цикли while, оскільки вони обмежують область збільшених змінних.

Цикли do while корисні, коли умова залежить від деяких входів. Вони найчастіше використовуються з трьох типів циклів.


2

Між тим і на час: while не потребує ініціалізації та оператора оновлення, тому може виглядати краще, елегантніше; forможе мати відсутні оператори, один два або всі, тому це найбільш гнучке і очевидне, якщо вам потрібна ініціалізація, умова циклу та "оновлення" перед циклічним виконанням. Якщо вам потрібні лише умови циклу (перевірено на початку циклу), то whileце більш елегантно.

Між for / while та do-while : in do-whileобчислюється в кінці циклу. Більш зручним, якщо цикл потрібно виконати хоча б один раз.


2

В той час, як є більш гнучким. FOR є більш стислим у тих випадках, коли він застосовується.

FOR чудово підходить для петель, які мають якийсь лічильник, наприклад

Ви можете виконати те ж саме за допомогою WHILE, звичайно, як вказували інші, але зараз ініціалізація, тест і збільшення розбиті на три рядки. Можливо три широко розділені лінії, якщо тіло петлі велике. Це ускладнює читачеві розуміння того, що ви робите. Зрештою, хоча "++ n" є дуже поширеним третім фрагментом FOR, це, звичайно, не єдина можливість. Я написав багато циклів, де пишу "n + = приріст" або якийсь більш складний вираз.

Звичайно, FOR також може добре працювати з іншими речами, окрім лічильника. Подібно до

І т.д.

Але FOR руйнується, коли логіка "наступного разу через цикл" ускладнюється. Розглянемо:

Тобто, якщо процес просування може відрізнятися залежно від умов, що виникають під час обробки, твердження FOR недоцільно. Так, іноді ви можете зробити так, щоб він працював із досить складними виразами, використанням тернарного оператора?: Та ін., Але це зазвичай робить код менш читабельним, а не більш читабельним.

На практиці більшість моїх циклів або переходять через масив або якусь структуру, і в цьому випадку я використовую цикл FOR; або читають файл або набір результатів з бази даних, і в цьому випадку я використовую цикл WHILE ("while (! eof ())" або щось подібне).


Якщо заголовок for стає довгим, просто розділіть рядок після крапки з комою. Це не аргумент для while замість for.
klutt

@klutt Проблема з довгим і залученим виразом із залученням вкладених тернарних операторів та шістьма рівнями дужок або деякою порівнянною складністю не полягає в тому, що рядок занадто довгий, щоб поміститися у вікно редактора, а в тому, що стає важко читати та розуміти.
Джей

Правда, але це не має нічого спільного з тим, яку петлю ви вибрали.
klutt

@klutt Звичайно. Якщо операція "наступний" включає складну логіку з багатьма умовами, її не можна легко помістити в цикл FOR. Вам доведеться або мати складний вираз із вкладеними тернарами, або який-небудь подібний, або вам доведеться витягнути наступний з оператора FOR і помістити його в тіло циклу. У цей момент ви також можете написати цикл WHILE.
Джей

2

Вони майже однакові, за винятком do-whileциклу. forПетля хороша , коли у вас є counterтакі змінний. Це робить це очевидним. whileцикл має сенс у випадках, коли перевіряється прапор, як показано нижче:


0

whileі forоператори можуть бути використані для циклічного програмування. Це буде залежати від програміста щодо того, чи використовується whileцикл чи forцикл. Комусь зручно користуватися whileциклом, а хтось із forциклом.

Використовуйте будь-яку вподобану петлю. Однак do...whileцикл може бути дещо складним у програмуванні на Сі .


1
Існують послідовні відмінності між while, do whileі forпетлі. Погляньте на верхню відповідь, і ви їх знайдете.
Avio

0

/ * while циклу

5 баксів

1 шоколад = 1 бакс

приходьте додому і не можете ходити, поки ходите по магазинах, бо мої гроші = 0 баксів * /

нескінченні гроші

відвідайте це відео для кращого розуміння https://www.youtube.com/watch?v=eqDv2wxDMJ8&t=25s

/ * для циклу

5 баксів

* /

Для кращого розуміння відвідайте https://www.youtube.com/watch?v=_vdvyzzp-R4&t=25s

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.