Вопрос про цикл for

Общие вопросы программирования, алгоритмы и т.п.

Модератор: Модераторы

ZWolol
новенький
Сообщения: 21
Зарегистрирован: 06.01.2023 05:49:21

Вопрос про цикл for

Сообщение ZWolol »

Я всегда на С++ определял досрочный выход из цикла по 'break' проверкой значения i

for i := 0 to 8 do ...;
if i <= 8 then ... // был выход по break

Но здесь оказалось, что в конце цикла i=8 и не возможно определить был ли break на последнем элементе.
Это особенность Паскаля или Лазаруса?
Seenkao
энтузиаст
Сообщения: 568
Зарегистрирован: 01.04.2020 02:37:12
Контактная информация:

Сообщение Seenkao »

Паскаля.
Используй While. Только не понимаю смысла проверки.
ZWolol
новенький
Сообщения: 21
Зарегистрирован: 06.01.2023 05:49:21

Сообщение ZWolol »

Заменить 'for' на следующее не представляет проблемы:
i:=0;
while i < slGRUP.Count do
begin
i:=i+1;

Только i:=0 и i+1 делает 'for', иначе зачем он тогда нужен...

А смысл в том, что я ищу в массиве элементы удовлетворяющий условиям.
Проверки различны в зависимости от типа элемента. Я делаю 'break' когда элемент соответствует.
Но 'break' на последнем элементе равнозначен не найденному.
Нужно либо перед брейком присваивать переменной поиска труе, либо использовать вайл...

Описание работы for для паскаля мягко говоря не соответствует действительности.
xchgeaxeax
постоялец
Сообщения: 198
Зарегистрирован: 11.05.2023 02:51:40

Сообщение xchgeaxeax »

ZWolol, действие цикла for i := 0 to 8 do соответствует работе цикла for (int i = 0; i <= 8; ++i). В данном случае счетчик цикла существует только в пределах цикла. Значение счетчика не имеет значения после цикла и не сохраняется.

В данном случае эти две программы будут работать идентично, но на Pascal это будет длиннее

Код: Выделить всё

#include <iostream>

int main(int argc, char *argv[]) {
    int i = 5;
    for (int i = 0; i <= 8; ++i) std::cout << i << " ";
    std::cout << std::endl << i << std::endl;
    for (int i = 0; i <= 8; ++i) {
      if (i == 8) break;
      std::cout << i << " ";
    }
    std::cout << std::endl << i << std::endl;
    return 0;
}

Код: Выделить всё

program test_prog;

uses
  SysUtils;

var
  i: LongInt;

procedure For1();
var
  i: LongInt;
begin
  for i := 0 to 8 do Write(i, ' ');
end;

procedure For2();
var
  i: LongInt;
begin
  for i := 0 to 8 do begin
    if i = 8 then break;
    Write(i, ' ');
  end;
end;

begin
  i := 5;
  For1;
  WriteLn(#13, #10, i);
  For2;
  WriteLn(#13, #10, i);
end.
ZWolol писал(а):Описание работы for для паскаля мягко говоря не соответствует действительности.
Смотря где вы читаете.
Seenkao
энтузиаст
Сообщения: 568
Зарегистрирован: 01.04.2020 02:37:12
Контактная информация:

Сообщение Seenkao »

ZWolol, используй цикл по последний элемент включительно и тебе без разницы будет был break или нет.
xchgeaxeax писал(а):Значение счетчика не имеет значения после цикла и не сохраняется.
значение счётчика после выхода из цикла определено. И, если пользователь/программист не менял сам это значение, то всегда можно сказать какое это будет значение по выходу из цикла.

Если хочешь то можешь привести пример, когда значение не определено для значения счётчика по выходу из цикла.
ZWolol
новенький
Сообщения: 21
Зарегистрирован: 06.01.2023 05:49:21

Сообщение ZWolol »

int i = 5;
for (int i = 0; i <= 8; ++i) ...;

Это объявление локальной переменной в пределах цикла.
К ней не может быть обращение вне цикла.
После цикла, по моему, даже i сохранит 5.

int i = 5;
for (i = 0; i <= 8; ++i) ...;
А здесь используется объявленная переменная и i станет равно 9.
В паскале то же используется объявленная переменная, только значение будет 8.
Я могу ошибаться, 10 лет уже не писал...

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

>ZWolol, используй цикл по последний элемент включительно и тебе без разницы будет был break или нет.
Перебирать 50 тыс элементов, если найден десятым, я не вижу смысла.
И мне нужно определить в конце цикла, найден элемент или нет.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
Сообщения: 1409
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Sergei I. Gorelkin »

Компилятор может оптимизировать цикл for. Например, если значение управляющей переменной не используется внутри тела цикла, то задача компилятора - сгенерировать код, повторяющий тело цикла заданное количество раз, а как именно - это его проблемы. Т.е. компилятор имеет право превратить "for i:=0 to 7 do" в "for i:=1000 to 1007 do" или "for i:=7 downto 0 do", и переменная после цикла действительно не определена.

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

Код: Выделить всё

for i:=0 to 7 do arr[i] := arr[i]+25;
превратится в что-то такое (если считать, что arr - массив элементов типа integer)

Код: Выделить всё

var tmp: PInteger;
tmp := @arr[0];
for i:=0 to 7 do
begin
  tmp^ := tmp^+25;
  inc(tmp);
end;
И здесь значение управляющей переменной тоже перестает использоваться.
xchgeaxeax
постоялец
Сообщения: 198
Зарегистрирован: 11.05.2023 02:51:40

Сообщение xchgeaxeax »

ZWolol писал(а):Перебирать 50 тыс элементов, если найден десятым, я не вижу смысла.
И мне нужно определить в конце цикла, найден элемент или нет.

Код: Выделить всё

var
  i, k: LongInt;
begin
  k := -1;
  for i := 0 to 50000 do if i = 10 then begin k := i; break end;
  if k < 0 then WriteLn('не найден') else WriteLn(k);
  WriteLn(i);
end;
Хотя в таком простом цикле i останется равным 10.
Seenkao
энтузиаст
Сообщения: 568
Зарегистрирован: 01.04.2020 02:37:12
Контактная информация:

Сообщение Seenkao »

Sergei I. Gorelkin, да, тут моя вина, но если пользователь/программист будет использовать счётчик цикла вне цикла, то значение цикла будет учтено.


ZWolol писал(а):int i = 5;
for (int i = 0; i <= 8; ++i) ...;
по сути там не должно сохраняться i = 5, по простой причине, что данная переменная задействована. Какова правильная реализация в Си, не знаю. В Паскале не сохранится.
ZWolol писал(а):Перебирать 50 тыс элементов, если найден десятым, я не вижу смысла.
Первое, при использовании Break, не надо будет перебирать все элементы.
Второе можно задать конкретный цикл от 48000 до 50000.
Последний раз редактировалось Seenkao 22.01.2024 13:34:06, всего редактировалось 1 раз.
Alex2013
долгожитель
Сообщения: 3211
Зарегистрирован: 03.04.2013 11:59:44

Сообщение Alex2013 »

Seenkao писал(а):по сути там не должно сохраняться i = 5, по простой причине, что данная переменная задействована. Какова правильная реализация в Си, не знаю. В Паскале не сохранится.
Разумеется ... Другое дело что после "честного завершения" цикла (без break ) ИНОГДА может быть i = 9 ... ( что вроде и странно но по своему логично )
Seenkao
энтузиаст
Сообщения: 568
Зарегистрирован: 01.04.2020 02:37:12
Контактная информация:

Сообщение Seenkao »

Alex2013 писал(а):ИНОГДА может быть i = 9
может, надо знать какой компилятор используется. Старые компиляторы зачастую следующее значение выдавали.
Аватара пользователя
Sharfik
энтузиаст
Сообщения: 836
Зарегистрирован: 20.07.2013 01:04:30

Сообщение Sharfik »

ZWolol писал(а):Я всегда на С++ определял досрочный выход из цикла по 'break' проверкой значения i

for i := 0 to 8 do ...;
if i <= 8 then ... // был выход по break

Но здесь оказалось, что в конце цикла i=8 и не возможно определить был ли break на последнем элементе.
Это особенность Паскаля или Лазаруса?
дичь какая то.... простейшее условие с флагом. Зачем еще что то искать.

Код: Выделить всё

var
  bCorrect:Boolean;
  i:integer;
begin
 bCorrect:=False;
 for i:=0 to 100 do
 begin
  if i=44 then
  begin
     bCorrect:=True;
    break;
  end;
 end;

 if  bCorrect then ....
end;
Seenkao
энтузиаст
Сообщения: 568
Зарегистрирован: 01.04.2020 02:37:12
Контактная информация:

Сообщение Seenkao »

Sharfik, зачастую нужен поиск не по элементу, а нужен элемент, на котором поиск был остановлен.
ZWolol
новенький
Сообщения: 21
Зарегистрирован: 06.01.2023 05:49:21

Сообщение ZWolol »

>по сути там не должно сохраняться i = 5, по простой причине, что данная переменная задействована. Какова правильная реализация в Си, не знаю. В Паскале не сохранится.

Видимость для переменных: ты можешь многократно объявлять переменную i.
Локальная i не изменит приватную и глобальную.
Локальная i цикла не должна менять переменную вне ее.
А в паскале используется объявленная переменная. Она меняется, но результат использовать нельзя. :(

>Sharfik, зачастую нужен поиск не по элементу, а нужен элемент, на котором поиск был остановлен.
Собственно я так и делал.

Но в данном случае мне каждую строку в массиве нужно разобрать на составляющие и по комбинации этих значений определить соответствие.
А если я уже разобрал строку и сохранил их в переменных, то зачем мне по ее номеру опять делать разбор, достаточно указать что найдена.
Я сразу сказал, что переменная True/False решает эту проблему.
Нужно только ко всем break добавить ей True (аналогично можно ей присваивать номер в массиве).

Вопрос стоял в том: почему результат i нельзя использовать, а на С не было проблем.
Seenkao
энтузиаст
Сообщения: 568
Зарегистрирован: 01.04.2020 02:37:12
Контактная информация:

Сообщение Seenkao »

ZWolol писал(а):Она меняется, но результат использовать нельзя.
что? :shock:
Я постоянно использую результат именно счётчика цикла. Потому что при использовании Break мы получим последнее значение когда был прерван цикл. А если цикл завершился, то использую значение для задание новых данных.

Что за сказки тут рассказывают? :)

Добавлено спустя 2 минуты 57 секунд:
ZWolol писал(а):Вопрос стоял в том: почему результат i нельзя использовать, а на С не было проблем.
ещё раз пишу, что надо использовать те переменные, которые будут входить в условие, тогда ты получишь необходимое значение.

Если ты используешь значения больше/меньше в счётчике цикла, то должен это обставить в нужном варианте. В Си будет так же.
Нужен обход кода, делай вызов функции или используй оператор GoTo.
Последний раз редактировалось Seenkao 22.01.2024 15:03:00, всего редактировалось 1 раз.
Ответить