#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