Для против в то время как в программировании на C? - PullRequest
71 голосов
/ 01 июня 2010

В C есть три цикла: for, while и do-while. В чем разница между ними?

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

Ответы [ 19 ]

152 голосов
/ 01 июня 2010

A в то время как цикл всегда сначала оценивает состояние.

while (condition) {
  //gets executed after condition is checked
}

A цикл do / while всегда будет выполняться сначала код в блоке do{} а затем оцените состояние.

do {
  //gets executed at least once
} while (condition); 

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

for (int x = 0; x < 100; x++) {
   //executed until x >= 100
}

В конце концов, все они все еще циклы, но они предлагают некоторую гибкость в отношении того, как они выполняются.

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

Основное различие между for и while это вопрос прагматика: мы обычно используем for когда есть известное количество итераций, и использовать while конструкции, когда количество итераций не известно в авансовый. while против do ... while вопрос также прагматики, второй выполняет инструкции один раз в начале, а потом ведет себя так же, как простое время.

<ч />

Ведь петли особенно хороши, потому что они лаконичны. Для этого для цикла

for (int x = 0; x < 100; x++) {
   //executed until x >= 100
}

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

int count = 0;
while (count < 100) {
  //do stuff
  count++;
}

В этом случае есть просто еще кое-что, и count++; может потеряться в логике. Это может оказаться проблематичным в зависимости от того, где count увеличивается, и следует ли увеличивать его до или после логики цикла. В цикле for переменная вашего счетчика всегда увеличивается до следующей итерации цикла, что добавляет некоторый единообразие вашему коду.

<ч />

Для полноты картины, вероятно, имеет смысл поговорить об операторах break и continue, которые могут пригодиться при обработке цикла.

break немедленно прервет текущий цикл и больше итераций не будет выполнено.

//will only run "do stuff" twice
for (int x = 0; x < 100; x++) {
  if (x == 2) {
    break;
  }
  //do stuff
}

продолжить прервет текущую итерацию и перейдет к следующей.

//will run "do stuff" until x >= 100 except for when x = 2
for (int x = 0; x < 100; x++) {
  if (x == 2) {
    continue;
  }
  //do stuff
}

Обратите внимание, что в цикле for "continue" вычисляет выражение "part3" для for (part1; part2; part3) '; напротив, в цикле while он просто перепрыгивает, чтобы повторно оценить условие цикла.

15 голосов
/ 02 июня 2010

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

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

Кстати, в этом конкретном примере наихудший случай задается циклом for. :))

int main(int argc, char* argv[])
{
    int i;
    char x[100];

    // "FOR" LOOP:
    for (i=0; i<100; i++ )
    {
        x[i] = 0;
    }

    // "WHILE" LOOP:
    i = 0;
    while (i<100 )
    {
        x[i++] = 0;
    }

    // "DO-WHILE" LOOP:
    i = 0;
    do
    {
        x[i++] = 0;
    }
    while (i<100);

    return 0;
}

// "ДЛЯ" ПЕТЛИ:

    010013C8  mov         dword ptr [ebp-0Ch],0
    010013CF  jmp         wmain+3Ah (10013DAh)

  for (i=0; i<100; i++ )
  {
      x[i] = 0;
    010013D1  mov         eax,dword ptr [ebp-0Ch]  <<< UPDATE i
    010013D4  add         eax,1
    010013D7  mov         dword ptr [ebp-0Ch],eax
    010013DA  cmp         dword ptr [ebp-0Ch],64h  <<< TEST
    010013DE  jge         wmain+4Ah (10013EAh)     <<< COND JUMP
    010013E0  mov         eax,dword ptr [ebp-0Ch]  <<< DO THE JOB..
    010013E3  mov         byte ptr [ebp+eax-78h],0
    010013E8  jmp         wmain+31h (10013D1h)     <<< UNCOND JUMP
  }

// ПЕТЛЯ "WHILE":

  i = 0;
  010013EA  mov         dword ptr [ebp-0Ch],0
  while (i<100 )
  {
      x[i++] = 0;
    010013F1  cmp         dword ptr [ebp-0Ch],64h   <<< TEST
    010013F5  jge         wmain+6Ah (100140Ah)      <<< COND JUMP
    010013F7  mov         eax,dword ptr [ebp-0Ch]   <<< DO THE JOB..
    010013FA  mov         byte ptr [ebp+eax-78h],0
    010013FF  mov         ecx,dword ptr [ebp-0Ch]   <<< UPDATE i
    01001402  add         ecx,1
    01001405  mov         dword ptr [ebp-0Ch],ecx
    01001408  jmp         wmain+51h (10013F1h)      <<< UNCOND JUMP
  }

// ЦИКЛ "DO-WHILE":

i = 0;
.  0100140A  mov         dword ptr [ebp-0Ch],0
  do
  {
      x[i++] = 0;
    01001411  mov         eax,dword ptr [ebp-0Ch]   <<< DO THE JOB..
    01001414  mov         byte ptr [ebp+eax-78h],0
    01001419  mov         ecx,dword ptr [ebp-0Ch]   <<< UPDATE i
    0100141C  add         ecx,1
    0100141F  mov         dword ptr [ebp-0Ch],ecx
    01001422  cmp         dword ptr [ebp-0Ch],64h   <<< TEST
    01001426  jl          wmain+71h (1001411h)      <<< COND JUMP
  }
  while (i<100);
10 голосов
/ 01 июня 2010

Они все взаимозаменяемы; Вы можете выбрать один тип и использовать его только навсегда, но обычно он более удобен для выполнения определенной задачи. Это все равно что сказать «зачем иметь переключатель, вы можете просто использовать кучу операторов if» - правда, но если это обычный шаблон для проверки переменной на набор значений, это удобно и намного легче читать, если есть языковая функция сделать это

10 голосов
/ 01 июня 2010

Ради удобочитаемости

8 голосов
/ 01 июня 2010

Если вы хотите, чтобы цикл выполнялся, пока условие выполняется, а не для определенного числа итераций, кому-то еще будет легче понять:

while (cond_true)

чем то так:

for (; cond_true ; )
5 голосов
/ 01 июня 2010

Помните, цикл for - это, по сути, необычный цикл while. Это одно и то же.

while <some condition is true> {
   // do some stuff
   // possibly do something to change the condition
}


for ( some var, <some condition is true>; increment var ) {

}

Преимущество цикла for состоит в том, что сложнее случайно выполнить бесконечный цикл. Или, скорее, это более очевидно, когда вы делаете один, потому что вы обычно помещаете цикл var в первоначальный оператор.

Цикл while более понятен, если вы не выполняете стандартную схему приращения. Например:

int x = 1;
while( x != 10 ) {
  if ( some condition )
     x = 10;
  else 
     x += 5;
}
4 голосов
/ 01 июня 2010

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

For циклы являются просто синтаксически подслащенными while циклами и ускоряют написание итерационного кода.

Когда компилятор берет ваш код и компилирует его, он переводит его в форму, которую компьютеру легче понять и выполнить на более низком уровне (сборка). Во время этого перевода тонкие различия между синтаксисами while и for теряются, и они становятся точно такими же.

4 голосов
/ 01 июня 2010

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

for(int i = 0; i < 10; i++)
{
    print(i);
}

//or

int i = 0;
while(i < 10)
{
    print(i);
    i++;
}

Очевидно, что в такой ситуации «for» выглядит лучше, чем «while». И "do while" должно использоваться, когда некоторые операции должны быть выполнены уже до того момента, когда будет проверено состояние вашего цикла.

Извините за мой плохой английский).

3 голосов
/ 01 июня 2010

A for предлагает фиксированную итерацию с использованием индекса или вариантов этой схемы.

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

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

3 голосов
/ 06 июля 2014

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

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

static int intStartWith = 100;

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...