Разница между циклами Foreach и For?

#c #for-loop #foreach

#c #цикл for #foreach

Вопрос:

В чем реальная разница между циклом foreach и for, если любой из них может выполнить ту же работу? Я изучаю C и, по-видимому, для его массивов нет цикла foreach : (

Комментарии:

1. cplusplus.com/reference/algorithm/for_each — используйте контейнеры STL вместо массивов, и у вас это есть .

2. @BrianRoach На самом деле, вам даже не нужно использовать контейнер STL в последнем стандарте. Вы можете использовать std::begin() и std::end() в std::for_each функции.

3. Qt (популярный кроссплатформенный инструментарий C ) предоставляет foreach конструкцию .

4. @MichaelPrice — Да… Я немного сомневаюсь, начинать ли отвечать на вопросы C с ответов на C 11. То же самое с Java 7. Я полагаю, что предложение этого в качестве дополнительной альтернативы является ответственным.

5. @BrianRoach Хотя это скорее мета , я бы предпочел отказаться от тега C 11 в пользу добавления тега C 98/03, который зарезервирован для вопросов, специфичных для этой версии. То же самое касается ответов. Если бы только эти чертовы компиляторы реализовали полный стандарт.

Ответ №1:

В C нет языковой конструкции «foreach», по крайней мере, не буквально. Однако C 11 вводит нечто, «столь же хорошее», как цикл foreach.

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

Цикл «foreach», с другой стороны, явно предназначен для перебора элементов контейнера.

Пример:

 int arr[5] = { 1, 3, 5, 2, 4 };

for (int amp; n : arr) { n *= 2; } // "for-each" loop, new in C  11

for (size_t i = 0; i != 5;   i) { arr[i] *= 2; } // "classic" for loop
  

Во втором for мы используем традиционный for цикл для увеличения вспомогательной переменной i , чтобы получить доступ к контейнеру arr . Первый цикл, основанный на диапазоне, не раскрывает никаких подробностей итерации, а просто говорит «сделайте то-то и то-то для каждого элемента в коллекции».

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

 std::vector<std::string> all_lines;
for (std::string line; std::cin >> line; all_lines.push_back(line))
{
  std::cout << "On line " << (all_lines.size()   1) << " you said: " << line << std::endl;
}
  

Вы можете тривиально переписать for(A; B; C) как цикл while:

 {  // scope!
  A;
  while (true amp;amp; B)
  {
    {  // more scope!
      /* for loop body */
    }
    C;
  }
}
  

Редактировать: вероятно, было бы упущением не упомянуть шаблон библиотечной функции std::for_each из <algorithm> , который в сочетании с лямбдами является очень приятным и самоописывающимся способом перебора произвольных диапазонов (а не только целых контейнеров). Он существует с первого дня, но до появления лямбд его использование приводило к остановке показа.


Обновление: я подумал о чем-то еще, что может быть уместно здесь: цикл «foreach» обычно предполагает, что вы не изменяете контейнер. Распространенный тип цикла, который изменяет контейнер, требует традиционного for цикла; как, например, в этом типичном erase шаблоне:

 for(Container::const_iterator it = v.begin(); it != v.end() /* not hoisted! */; /* no increment */ )
{
  // do something
  if (suitable_condition)
  {
    v.erase(it  );   // or it = v.erase(it), depending on container type
  }
  else
  {
      it;
  }
}
  

Комментарии:

1. Так что, действительно, я могу использовать их взаимозаменяемо, но, возможно, могу сделать больше с for циклом?

2. @Howdy_McGee: Да. Я добавил необычный for пример. Стандартный for цикл на самом деле просто сокращен от «a) инициализировать некоторый материал; b) если выполняется некоторое условие, выполнить некоторый материал; c) выполнить некоторую операцию; d) перейти к b)».

3. @Howdy_McGee: Это может помочь вам думать о for цикле как об удобном while цикле. Я добавил это объяснение.

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

5. @Howdy_McGee: Все дело в выражении намерения. Если у вас есть контейнер, цикл for-each (или ranged-for, в C ) позволяет выразить, что вы хотите получить доступ к элементам контейнера, не больше и не меньше. Обратите внимание, что цикл на основе диапазона имеет гораздо более простое тело, поскольку не отображается ненужная информация. Программирование — это выражение ментальной модели, и наличие доступной идиоматической конструкции помогает сделать ваш код более понятным.

Ответ №2:

foreach обычно имеет 1 параметр, for имеет 3. Все, что foreach можно сделать for , тоже может. Одна из причин, по которой foreach этого не существует в C , заключается в том, что количество итераций не всегда может быть выведено из типа.

Я полагаю, что в библиотеке boost есть способ заставить foreach работать, а C 11 имеет диапазон, основанный на for :

 int my_array[5] = {1, 2, 3, 4, 5};
for (int amp;x : my_array) {
    x *= 2;
}
  

Ответ №3:

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

Ответ №4:

Синтаксис «Для каждого» используется для перебора коллекции объектов, в то время как цикл for — это цикл, который будет выполняться для заданного диапазона. C имеет for_each в своем STL и может использоваться для перебора контейнеров линейных объектов, таких как вектор.

Комментарии:

1. for Цикл не имеет ничего общего с «диапазонами». Речь идет о проверке условных выражений и выполнении инструкций.

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

Ответ №5:

В других языках с конструкцией foreach они обычно удобны тем, что не нужно индексировать коллекцию, по которой вы выполняете цикл. То есть вам предоставляется следующий объект в коллекции без доступа к самому индексу (или необходимости в нем). Если вам по какой-то причине нужен индекс, вам обычно понадобится цикл for, хотя на некоторых языках у вас есть доступ к счетчику в их ‘foreach’.

Ответ №6:

как показывает опыт, FOR работает быстрее, чем FOREACH