'сделайте … в то время как' по сравнению с 'в то время как'

Возможные дубликаты:
В то время как по сравнению с делают в то время как
Когда должен я использовать сделать - в то время как вместо циклов с условием продолжения?

Я программировал некоторое время теперь (работа 2 лет + градус 4,5 лет + предварительный колледж 1 года), и я никогда не использовал цикл с условием продолжения за исключением того, чтобы быть вызванным к во Введении в Программирование курса. У меня есть рост, чувствуя, что я делаю программирование неправильно, если я никогда не сталкиваюсь с чем-то настолько фундаментальным.

Могло случиться так, что я просто не столкнулся с корректными обстоятельствами?

Каковы некоторые примеры, где было бы необходимо использовать - в то время как вместо некоторое время?

(Мое обучение было почти всем в C/C++, и моя работа находится в C#, поэтому если существует другой язык, где это абсолютно имеет смысл, потому что делают - whiles работа по-другому, затем эти вопросы действительно не применяются.)

Разъясниться... Я знаю различие между a while и a do-while. В то время как проверки условие выхода и затем выполняют задачи. do-while выполняет задачи и затем проверяет условие выхода.

75
задан Peter Mortensen 24 June 2017 в 16:46
поделиться

24 ответа

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

do
{
   try to access resource...
   put up message box with retry option

} while (user says retry);
100
ответ дан 24 November 2019 в 11:28
поделиться

Любой вид консольного ввода хорошо работает с do-while, потому что вы запрашиваете в первый раз и повторно запрашиваете каждый раз, когда проверка ввода терпит неудачу.

0
ответ дан 24 November 2019 в 11:28
поделиться

Я использовал его в функции, которая возвращала следующую позицию символа в строке utf-8:

char *next_utf8_character(const char *txt)
{
    if (!txt || *txt == '\0')
        return txt;

    do {
        txt++;
    } while (((signed char) *txt) < 0 && (((unsigned char) *txt) & 0xc0) == 0xc0)

    return (char *)txt;
}

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

0
ответ дан 24 November 2019 в 11:28
поделиться

Самый распространенный сценарий, в котором я использую цикл do/while - это небольшая консольная программа, которая запускается на основе некоторых входных данных и повторяется столько раз, сколько захочет пользователь. Очевидно, что для консольной программы нет смысла запускаться ни разу; но после первого раза все зависит от пользователя - отсюда do/while вместо просто while.

Это позволяет пользователю при желании опробовать множество различных входов.

do
{
   int input = GetInt("Enter any integer");
   // Do something with input.
}
while (GetBool("Go again?"));

Я подозреваю, что разработчики программного обеспечения используют do/while все меньше и меньше в наши дни, теперь, когда практически каждая программа под солнцем имеет графический интерфейс. Это имеет больше смысла в консольных приложениях, так как там необходимо постоянно обновлять вывод, чтобы предоставить инструкции или подсказать пользователю новую информацию. В графическом интерфейсе, напротив, текст, предоставляющий эту информацию пользователю, может просто находиться на форме и никогда не повторяться программно.

0
ответ дан 24 November 2019 в 11:28
поделиться

Я использовал do while , когда читаю контрольное значение в начале файла, но кроме этого, я не думаю, что это ненормально что эта структура не слишком часто используется - do-while действительно ситуативны.

-- file --
5
Joe
Bob
Jake
Sarah
Sue

-- code --
int MAX;
int count = 0;
do {
MAX = a.readLine();
k[count] = a.readLine();
count++;
} while(count <= MAX)
0
ответ дан 24 November 2019 в 11:28
поделиться

Вот моя теория, почему большинство людей (включая меня) предпочитают циклы while(){} циклам do{}while(): Цикл while(){} может быть легко адаптирован для выполнения как цикл do..while(), в то время как обратное не верно. Цикл while является в некотором смысле "более общим". Кроме того, программистам нравятся легко воспринимаемые шаблоны. В цикле while в самом начале говорится о том, что является его инвариантом, и это очень приятно.

Вот что я имею в виду, говоря о "более общем". Возьмем этот цикл do...while:

do {
 A;
 if (condition) INV=false; 
 B;
} while(INV);

Преобразовать его в цикл while очень просто:

INV=true;
while(INV) {
 A;
 if (condition) INV=false; 
 B;
}

Теперь возьмем модельный цикл while:

while(INV) {
     A;
     if (condition) INV=false; 
     B;
}

И преобразуем его в цикл do..while, получается вот такое чудовище:

if (INV) {
 do
 {
         A;
         if (condition) INV=false; 
         B;

 } while(INV)
}

Теперь у нас есть две проверки на противоположных концах, и если инвариант меняется, вам приходится обновлять его в двух местах. В определенном смысле do...while подобен специализированным отверткам в ящике с инструментами, которые вы никогда не используете, потому что стандартная отвертка делает все, что вам нужно.

1
ответ дан 24 November 2019 в 11:28
поделиться

Я использовал это в функции TryDeleteDirectory. Это было что-то вроде этого

do
{
    try
    {
        DisableReadOnly(directory);
        directory.Delete(true);
    }
    catch (Exception)
    {
        retryDeleteDirectoryCount++;
    }
} while (Directory.Exists(fullPath) && retryDeleteDirectoryCount < 4);
11
ответ дан 24 November 2019 в 11:28
поделиться

Do while полезен, когда вы хотите выполнить что-то хотя бы один раз. Что касается хорошего примера использования do while против while, допустим, вы хотите сделать следующее: Калькулятор.

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

do
{
    //do calculator logic here
    //prompt user for continue here
} while(cont==true);//cont is short for continue
11
ответ дан 24 November 2019 в 11:28
поделиться

Ситуация, когда вам всегда нужно выполнить кусок кода один раз, и в зависимости от его результата, возможно, несколько раз. То же самое можно получить и с помощью обычного цикла while.

rc = get_something();
while (rc == wrong_stuff)
{
    rc = get_something();
}

do
{
    rc = get_something();
}
while (rc == wrong_stuff);
6
ответ дан 24 November 2019 в 11:28
поделиться

Я довольно часто ими пользовался, когда учился в школе, но не так часто с тех пор.

Теоретически они полезны, когда вы хотите, чтобы тело цикла выполнялось один раз перед проверкой условия выхода. Проблема в том, что для тех немногих случаев, когда я не хочу сначала проверять, обычно мне нужна проверка выхода в середине тела цикла, а не в самом конце. В этом случае я предпочитаю использовать хорошо известный for (;;) с if (condition) exit; где-нибудь в теле.

На самом деле, если меня немного не устраивает условие выхода из цикла, иногда я считаю полезным начать писать цикл как for (;;) {} с оператором выхода, где это необходимо. , а затем, когда я закончу, я могу посмотреть, можно ли "очистить", переместив инициализации, условия выхода и / или увеличив код внутри скобок для .

7
ответ дан 24 November 2019 в 11:28
поделиться

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

using(IDataReader reader = connection.ExecuteReader())
{
    do
    {
        while(reader.Read())
        {
            //Read record
        }
    } while(reader.NextResult());
}
2
ответ дан 24 November 2019 в 11:28
поделиться

Ответы на данный момент суммируют общее использование do-while. Но OP попросил пример, так что вот один: получить ввод пользователя. Но ввод пользователя может быть недействительным - поэтому вы запрашиваете ввод, проверяете его, продолжаете, если он действителен, в противном случае повторяете.

С помощью do-while вы получаете ввод, в то время как ввод недействителен. В обычном цикле while вы получаете ввод один раз, но если он недействителен, вы получаете его снова и снова, пока он не станет действительным. Нетрудно заметить, что первый будет короче, элегантнее и проще в обслуживании, если тело цикла станет более сложным.

2
ответ дан 24 November 2019 в 11:28
поделиться

делать, а - если вы хотите запустить блок кода хотя бы один раз. , а , с другой стороны, не всегда будет выполняться в зависимости от указанных критериев.

6
ответ дан 24 November 2019 в 11:28
поделиться

Одно из приложений, которые я видел, это Oracle, когда мы смотрим на наборы результатов.

После того, как у вас есть набор результатов, вы сначала извлекаете из него (do) и с этого момента ... проверяете, возвращает ли выборка элемент или нет (пока элемент найден ..). То же самое может быть применимо для любые другие реализации, подобные выборке.

0
ответ дан 24 November 2019 в 11:28
поделиться

do-while лучше, если компилятор некомпетентен в оптимизации. do-while имеет только один условный переход, в отличие от for и while, у которых есть условный переход и безусловный переход. Для ЦП, которые являются конвейерными и не прогнозируют ветвление, это может иметь большое значение в производительности жесткого цикла.

Кроме того, поскольку большинство компиляторов достаточно умны, чтобы выполнить эту оптимизацию, все циклы, обнаруженные в декомпилированном коде, обычно будут выполняться в режиме выполнения (если декомпилятор вообще потрудится восстановить циклы из обратных локальных gotos).

61
ответ дан 24 November 2019 в 11:28
поделиться

Я все время использую циклы do-while при чтении файлов. Я работаю с большим количеством текстовых файлов, которые включают комментарии в заголовке:

# some comments
# some more comments
column1 column2
  1.234   5.678
  9.012   3.456
    ...     ...

я буду использовать цикл do-while для чтения до строки «column1 column2», чтобы я мог искать интересующий столбец. Вот псевдокод:

do {
    line = read_line();
} while ( line[0] == '#');
/* parse line */

Затем я выполню цикл while, чтобы прочитать остальную часть файла.

0
ответ дан 24 November 2019 в 11:28
поделиться
Циклы

while проверяют условие до цикла, циклы do...while проверяют условие после цикла. Это полезно, если вы хотите основывать условие на побочных эффектах от выполнения цикла или, как говорили другие авторы, если вы хотите, чтобы цикл выполнялся хотя бы один раз.

Я понимаю, к чему вы клоните, но do-while - это то, что большинство используют редко, а я сам никогда не использовал. Вы не делаете это неправильно.

Вы не делаете это неправильно. Это все равно, что сказать, что кто-то делает неправильно, потому что никогда не использовал примитив byte. Он просто не так часто используется.

0
ответ дан 24 November 2019 в 11:28
поделиться

Это так просто:

предусловие против постусловия

  • while (cond) {...} - предусловие, оно выполняет код только после проверки.
  • do {...} while (cond) - постусловие, код выполняется хотя бы один раз.

Теперь, когда вы знаете секрет ... используйте их с умом :)

5
ответ дан 24 November 2019 в 11:28
поделиться

Это довольно распространенная структура на сервере / потребителе:

DOWHILE (no shutdown requested)
   determine timeout
   wait for work(timeout)
   IF (there is work)
      REPEAT
          process
      UNTIL(wait for work(0 timeout) indicates no work)
      do what is supposed to be done at end of busy period.
   ENDIF
ENDDO

REPEAT UNTIL (cond) является do {... } while (! cond)

Иногда ожидание работы (0) может быть дешевле с точки зрения ЦП (даже исключение вычисления тайм-аута может быть улучшением при очень высокой скорости поступления). Более того, существует множество результатов теории массового обслуживания, которые делают количество обслуживаемых в период занятости важной статистической информацией. (См., Например, Kleinrock - Vol 1.)

Аналогично:

DOWHILE (no shutdown requested)
   determine timeout
   wait for work(timeout)
   IF (there is work)
      set throttle
      REPEAT
          process
      UNTIL(--throttle<0 **OR** wait for work(0 timeout) indicates no work)
   ENDIF
   check for and do other (perhaps polled) work.
ENDDO

где проверять и выполнять другую работу может быть непомерно дорогостоящим для включения в основной цикл или, возможно, ядро, которое не поддерживает эффективная операция типа waitany (waitcontrol *, n) или, возможно, ситуация, когда приоритетная очередь может ограничивать выполнение другой работы, а дросселирование используется в качестве контроля голодания.

Этот тип балансировки может показаться хитростью, но он может быть необходим.Слепое использование пулов потоков полностью сведет на нет преимущества в производительности от использования вспомогательного потока с частной очередью для сложной структуры данных с высокой частотой обновления, поскольку использование пула потоков, а не вспомогательного потока потребует поточно-ориентированной реализации.

Я действительно не хочу вдаваться в дебаты о псевдокоде (например, следует ли проверять запрошенное завершение работы в UNTIL) или потоках-смотрителях в сравнении с пулами потоков - это просто призвано дать представление о конкретном вариант использования структуры потока управления.

0
ответ дан 24 November 2019 в 11:28
поделиться

Я не могу представить, как вы продержались так долго без использования цикла do ... while .

Сейчас есть один на другом мониторе, и в этой программе есть несколько таких циклов. Все они имеют форму:

do
{
    GetProspectiveResult();
}
while (!ProspectIsGood());
1
ответ дан 24 November 2019 в 11:28
поделиться

Будучи чудаковатым программистом, во многих моих школьных проектах по программированию использовалось взаимодействие, управляемое текстовым меню. Практически все использовали что-то вроде следующей логики для основной процедуры:

do
    display options
    get choice
    perform action appropriate to choice
while choice is something other than exit

Еще со школьных времен я обнаружил, что чаще использую цикл while.

0
ответ дан 24 November 2019 в 11:28
поделиться

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

Как уже говорили все, вы используете цикл do ... while , если хотите выполнить тело хотя бы один раз. Но при каких обстоятельствах вы бы хотели это сделать?

Что ж, наиболее очевидный класс ситуаций, которые я могу придумать, это когда начальное («незаштрихованное») значение условия проверки такое же, как когда вы хотите выйти . Это означает, что вам нужно выполнить тело цикла один раз, чтобы заполнить условие несуществующим значением, а затем выполнить фактическое повторение на основе этого условия. Из-за того, что программисты были такими ленивыми, кто-то решил обернуть это в структуру управления.

Так, например, чтение символов из последовательного порта с тайм-аутом может принимать форму (в Python):

response_buffer = []
char_read = port.read(1)

while char_read:
    response_buffer.append(char_read)
    char_read = port.read(1)

# When there's nothing to read after 1s, there is no more data

response = ''.join(response_buffer)

Обратите внимание на дублирование кода: char_read = port.read (1) . Если бы у Python был цикл do ... while , я мог бы использовать:

do:
    char_read = port.read(1)
    response_buffer.append(char_read)
while char_read

Дополнительное преимущество для языков, которые создают новую область видимости для циклов: char_read не загрязняет функцию пространство имен. Но обратите внимание, что есть лучший способ сделать это - использовать значение Python None :

response_buffer = []
char_read = None

while char_read != '':
    char_read = port.read(1)
    response_buffer.append(char_read)

response = ''.join(response_buffer)

Итак, вот суть моей мысли: в языках с типами, допускающими значение NULL, ситуация initial_value == exit_value возникает гораздо реже, и , что может быть причиной того, что вы не сталкиваетесь с ним. Я не говорю, что этого никогда не произойдет, потому что бывают случаи, когда функция возвращает None для обозначения допустимого условия.Но, по моему поспешному и кратко обдуманному мнению, это могло бы произойти гораздо больше, если бы используемые вами языки не допускали значения, которое означает: эта переменная еще не инициализирована.

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

10
ответ дан 24 November 2019 в 11:28
поделиться

Я занимаюсь программированием около 12 лет, и всего 3 месяца назад я столкнулся с ситуацией, когда было действительно удобно использовать do-while, поскольку перед проверкой условия всегда требовалась одна итерация. Так что угадайте, ваше большое время впереди :).

1
ответ дан 24 November 2019 в 11:28
поделиться

Я вижу, что на этот вопрос был дан адекватный ответ, но хотел бы добавить очень специфический сценарий использования. Возможно, вы начнете чаще использовать do...while.

do
{
   ...
} while (0)

часто используется для многострочных #defines. Например:

#define compute_values     \
   area = pi * r * r;      \
   volume = area * h

Это работает нормально для:

r = 4;
h = 3;
compute_values;

- но есть проблема для:

if (shape == circle)  compute_values;

поскольку это расширяется до:

if (shape == circle) area = pi *r * r;
volume = area * h;

Если вы обернете это в цикл do ... while(0) цикл, он правильно расширяется до одного блока:

if (shape == circle)
  do
  {
    area = pi * r * r;
    volume = area * h;
  } while (0);
4
ответ дан 24 November 2019 в 11:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: