2 простых вопроса по синтаксису

Вопросы программирования на Free Pascal, использования компилятора и утилит.

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

2 простых вопроса по синтаксису

Сообщение Kitayets » 06.05.2015 16:54:46

1. почему компилятор не дает использовать переменную как переменную цикла - если она была инициализирована при описании?

пример:
Код: Выделить всё
{...}
var
  i: integer = 0;
begin
  {используем, или не используем переменную i}
  for i:=0 to 100 do  // <- тут ошибка "Error: Illegal counter variable"
  begin
    {do something}
  end;
end;


2. для конструкции for in (foreach в других языках) - можно ли как-то изменять значения самого контейнера?

допустим:
Код: Выделить всё
{есть к примеру массив}
var
  arr: array of integer;
  value: integer;
{...}
begin
  {...}
  setlength(arr, 10);
  {тут какие-то значения попадают в массив}
  for value in arr do
  begin
    inc(value); // <- хочу тут изменять значения в массиве, а на самом деле value это копия а не ссылка на элемент массива
  end;
end;
Kitayets
постоялец
 
Сообщения: 171
Зарегистрирован: 05.05.2010 21:15:24

Re: 2 простых вопроса по синтаксису

Сообщение SSerge » 06.05.2015 17:36:39

2.
Like the for..to loop, it is not allowed to change (i.e. assign a value to) the value of a loop control variable inside the loop.

(http://www.freepascal.org/docs-html/ref/refsu55.html)
Подстановочную переменную в таких операторах нельзя менять и в других языках, кстати.

1. Потому что переменная счетчик не должна использоваться для других целей. По описанию языка, ее значение вне тела оператора цикла не определено, а здесь вы пытаетесь ее еще и инициализировать на уровне компиляции.
SSerge
энтузиаст
 
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Re: 2 простых вопроса по синтаксису

Сообщение Kitayets » 06.05.2015 20:46:36

спасибо за ответ.

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


вот тут например http://en.wikipedia.org/wiki/Foreach_loop
для Perl есть такой пример:
Код: Выделить всё
#Direct modification of collection members:

@arr = ( 'remove-foo', 'remove-bar' );
foreach $x (@arr){
    $x =~ s/remove-//;
}
# Now @arr = ('foo', 'bar');

так же как минимум для PHP есть возможность такая...
очевидно и в некоторых других тоже есть, т.е. говорить, что нигде нет - не верно ИМХО.

Для с++ есть такой вариант:
Код: Выделить всё
#include <vector>
#include <algorithm>
#include <iostream>

struct Sum {
    Sum() { sum = 0; }
    void operator()(int n) { sum += n; }

    int sum;
};

int main()
{
    std::vector<int> nums{3, 4, 2, 9, 15, 267};

    std::cout << "before: ";
    for (auto n : nums) {
        std::cout << n << " ";
    }
    std::cout << '\n';

    std::for_each(nums.begin(), nums.end(), [](int &n){ n++; });

    // Calls Sum::operator() for each number
    Sum s = std::for_each(nums.begin(), nums.end(), Sum());

    std::cout << "after:  ";
    for (auto n : nums) {
        std::cout << n << " ";
    }
    std::cout << '\n';
    std::cout << "sum: " << s.sum << '\n';
}


output:
Код: Выделить всё
before: 3 4 2 9 15 267
after:  4 5 3 10 16 268
sum: 306


хотя тут конечно for_each это не оператор, а просто функция. Но я к тому, что не хочу что-то странное, а вообще такое бывает востребовано.
Kitayets
постоялец
 
Сообщения: 171
Зарегистрирован: 05.05.2010 21:15:24

Re: 2 простых вопроса по синтаксису

Сообщение скалогрыз » 06.05.2015 21:08:53

SSerge писал(а):1. Потому что переменная счетчик не должна использоваться для других целей. По описанию языка, ее значение вне тела оператора цикла не определено, а здесь вы пытаетесь ее еще и инициализировать на уровне компиляции.

FPC 2.6.4 - копилирует без проблем:
Код: Выделить всё
procedure Test;
var
  i: integer = 0;
begin
  for i:=0 to 100 do
  begin
   write(i);
    {do something}
  end;
end;

begin
  Test;
end.


есть мнение, что Kitayets, имел в виду.
Код: Выделить всё
var
  i: integer = 0;
begin
  for i:=0 to 100 do
  begin
   write(i);
    {do something}
  end;
end.

Обращаю внимание на последний end с точкою, где i становится глобальной инициалириованной переменной.
Такие перменные загружаются в память при запуске программы. И там же остаются на время исполнения. (см asm с .data секцией)
Хотя цикл for работает с переменной расположенной в регистре. (Что кстати, технически гарантирует что никто другой кроме самого цикла for не сможет поменять значение переменной).

Если есть острая необходимость использовать глобальную инициализированную перменную в цикле, то стоит изменить цикл на while (repeat), либо чётко обозначить место присваивания (чтения?) значения глобальной переменной.
Примерно так:
Код: Выделить всё
var
  i: integer = 0;
  j: integer;
begin
  for j:=0 to 100 do
  begin
   write(i);
   i:=j;
    {do something}
  end;
end.


Добавлено спустя 9 минут 54 секунды:
Хотя я нихрена не прав насчёт любви цика-for к регистровым переменным, и можно добиться забавный результатов, если писать такой вот, сомнительной ценности, код:
Код: Выделить всё
program main;
uses withglobalvar;

var
  i: integer;

procedure AssingVal;
begin
  i := 5;
end;

begin
  AssingVal;
  for ki:=0 to 100 do
  begin
    write(ki);
    Modify;
    {do something}
  end;
end.
---
unit withglobalvar;

interface

var
  ki : integer;

procedure Modify;

implementation

procedure Modify;
begin
  ki:=4;
end;

initialization
  ki:=6;

end.

Надеюсь, за 70 лет сущствования информатика научит программистов не эксплуатировать глобальные переменные для низменных нужд, вроде циклов.
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: 2 простых вопроса по синтаксису

Сообщение SSerge » 07.05.2015 06:36:35

Kitayets писал(а):для Perl есть такой пример:

[
Код: Выделить всё
$x =~ s/remove-//;


Пример-то есть, только это вообще-то не операция присваивания. Алсо, если и в паскале перебирается массив указателей, ничто не препятствует менять данные, на которые указывает подстановочная переменная; вписать новый адрес в саму подстановочную переменную - вот этот номер не пройдет.

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

скалогрыз писал(а):есть мнение, что Kitayets, имел в виду.


Не, он именно имел ввиду то, что имел. Если с переменной цикла до ее использования в теле оператора цикла происходят какие-то действия по присваиванию ей, компилятор выдает специфическое сообщение. Это было еще на RT-11 pascal, на турбе, на дельфях. Парадигма формальная озвучена: по правилам языка переменная цикла for вне тела цикла не определена. Возможно, на этот счет еще и какое-то RFC существует.

то есть, если сделать:

Код: Выделить всё
procedure Test;
var
  i: integer = 0;
  j: integer;
begin
  j:=i*i+200;
  i:=j-1;
  for i:=0 to 100 do
  begin
   write(i);
    {do something}
  end;
end;

begin
  Test;
end.


...то компилятор imho выдаст ошибку.
И то же самое скорее всего будет, если i не объявлять типизированной константой. {{проверять лениво, етц}}
SSerge
энтузиаст
 
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Re: 2 простых вопроса по синтаксису

Сообщение sign » 07.05.2015 07:22:30

Что я делаю не так?
Может, не пользую древнюю версию или руки с иного места растут?
Это
Код: Выделить всё
var
  i: integer = 0;
begin
  {используем, или не используем переменную i}
  for i:=0 to 100 do  // <- тут ошибка "Error: Illegal counter variable"
  begin
    {do something}
  end;
end;

у меня работает.
Никаких ошибок не выдаёт.

И вот это работает.
Код: Выделить всё
program Project1;

procedure Test;
var
  i: integer = 0;
  j: integer;
begin
  j:=i*i+200;
  i:=j-1;
  for i:=0 to 100 do
  begin
   write(i);
    {do something}
  end;
end;
begin
  Test;
end.       


1.jpg


Лазарус 1.4
Win XP
У вас нет необходимых прав для просмотра вложений в этом сообщении.
sign
энтузиаст
 
Сообщения: 1131
Зарегистрирован: 30.08.2009 09:20:53

Re: 2 простых вопроса по синтаксису

Сообщение скалогрыз » 07.05.2015 07:39:07

SSerge писал(а):Не, он именно имел ввиду то, что имел. Если с переменной цикла до ее использования в теле оператора цикла происходят какие-то действия по присваиванию ей, компилятор выдает специфическое сообщение. Это было еще на RT-11 pascal, на турбе, на дельфях. Парадигма формальная озвучена: по правилам языка переменная цикла for вне тела цикла не определена. Возможно, на этот счет еще и какое-то RFC существует


Переменная цикла for - после цикла не определена. До цикла, переменная следует правилами переменной в соответствии со своей областью видимости.
И ты прав, говоря о том, что борланд компиляторы ругаются на такой вот код
Код: Выделить всё
for i:=0 to 100 do write(i);
writeln(i);

А вот FPC нет.

Добавлено спустя 5 минут 17 секунд:
sign писал(а):Что я делаю не так?
Может, не пользую древнюю версию или руки с иного места растут?

а как у тебя первый пример кода работает? если его просто скопипастить в файл и скомпилировать то компилятор выдаёт ошибку.
Код: Выделить всё
test2.pas(5,7) Error: Illegal counter variable
test2.pas(9,4) Fatal: Syntax error, "." expected but ";" found
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: 2 простых вопроса по синтаксису

Сообщение SSerge » 07.05.2015 09:20:49

sign писал(а):Что я делаю не так?


Не компилируется, если i:integer = 200 - глобальная переменная.
Если такое объявление под заголовком процедуры - компилируется. работает. FPC 3.1.
В-общем то поведение понятное - инициализированная константа, размещенная не в стеке, никак не должна быть пригодна для переменной, зона действия которой заканчивается [пусть] за циклом.
SSerge
энтузиаст
 
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Re: 2 простых вопроса по синтаксису

Сообщение Devel0 » 07.05.2015 12:46:00

SSerge писал(а):В C++ foreach нету вообще

<offtopic>Уже есть (по крайней мере на уровне синтаксиса), в Википедии по той ссылке есть пример. И поскольку подстановочная переменная объявлена как int &i, её можно менять</offtopic>
Devel0
новенький
 
Сообщения: 66
Зарегистрирован: 24.07.2011 10:43:13

Re: 2 простых вопроса по синтаксису

Сообщение sign » 08.05.2015 07:35:30

скалогрыз писал(а):
sign писал(а):Что я делаю не так?
Может, не пользую древнюю версию или руки с иного места растут?

а как у тебя первый пример кода работает? если его просто скопипастить в файл и скомпилировать то компилятор выдаёт ошибку.
Код: Выделить всё
test2.pas(5,7) Error: Illegal counter variable
test2.pas(9,4) Fatal: Syntax error, "." expected but ";" found


1.jpg


Добавлено спустя 2 минуты 7 секунд:
SSerge писал(а):
sign писал(а):Что я делаю не так?


Не компилируется, если i:integer = 200 - глобальная переменная.
Если такое объявление под заголовком процедуры - компилируется. работает. FPC 3.1.
В-общем то поведение понятное - инициализированная константа, размещенная не в стеке, никак не должна быть пригодна для переменной, зона действия которой заканчивается [пусть] за циклом.

В примере автора темы, переменная не глобальная.
Иначе бы и вопроса не стояло.
У вас нет необходимых прав для просмотра вложений в этом сообщении.
sign
энтузиаст
 
Сообщения: 1131
Зарегистрирован: 30.08.2009 09:20:53

Re: 2 простых вопроса по синтаксису

Сообщение Kitayets » 08.05.2015 10:42:45

sign именно глобальная, т.к. подпрограмм небыло.

ситуация - короткая программа из нескольких циклов, причем один был repeat..until и в нем тоже нужен был счетчик, чтобы не городить несколько переменных сделал 1-у и так-как repeat был первым нужно было инициализировать счетчик начальным значением.
Kitayets
постоялец
 
Сообщения: 171
Зарегистрирован: 05.05.2010 21:15:24


Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1

Рейтинг@Mail.ru
cron