Recent

Author Topic: Неправильно исполняется код  (Read 605 times)

devisa_san

  • New member
  • *
  • Posts: 12
Неправильно исполняется код
« on: August 12, 2019, 11:51:37 am »
Добрый день!
Ситуация следующая - имеется вот такой простейший код, где мы вводим значение переменных и вводим операцию, необходимую для выполнения над переменными. Lazarus при компиляции выдаёт какую то дичь - уже на стадии ввода операции он выводит сообщение, которое должно выводиться при невыполнении всех условий. Код рабочий, проверен в мобильном Pascal N-IDE  и там всё работает как надо. Вопрос - что происходит и как сделать так, чтобы код работал? Пробовал версии лазаруса 2.0.4 и 1.8.4. Лазарусы из коробки, никаких настроек не было произведено. Скрин с окном выполнения прикладываю.
P.S. Такое поведение лазаруса вызывает шок - это очень мягко говоря.   :o 

program Project1;
var a,b:double;
    c:string;
begin
write ('a=');
read (a);
write ('b=');
read (b);
write ('Enter operation (+ - * /) : ');
read (c);

if c='+' then write (a+b) else
 if c='-' then write (a-b) else
  if c='*' then write (a*b) else
   if c='/' then write (a/b) else write ('Wrong');
readln;
readln;
readln;
end.

julkas

  • Sr. Member
  • ****
  • Posts: 306
  • KISS principle / Lazarus 2.0.0 / FPC 3.0.4
Re: Неправильно исполняется код
« Reply #1 on: August 12, 2019, 11:59:30 am »
Try following -
Code: Pascal  [Select]
  1. write ('a=');
  2. readln (a);
  3. write ('b=');
  4. readln (b);
  5. write ('Enter operation (+ - * /) : ');
  6. readln (c);
  7.  
Замени read() на readln()
« Last Edit: August 12, 2019, 12:24:24 pm by julkas »
procedure mulu64(a, b: QWORD; out clo, chi: QWORD); assembler;
asm
  mov rax, a
  mov rdx, b
  mul rdx
  mov [clo], rax
  mov [chi], rdx
end;
(* Pointer game *) Inc(ptr, 1); (* vs *) ptr := ptr + 1;

devisa_san

  • New member
  • *
  • Posts: 12
Re: Неправильно исполняется код
« Reply #2 on: August 12, 2019, 01:36:39 pm »
Спасибо за быстрый ответ. Работает как задумано, благодарю. Но тогда почему код работал в Pascal N-IDE?

julkas

  • Sr. Member
  • ****
  • Posts: 306
  • KISS principle / Lazarus 2.0.0 / FPC 3.0.4
Re: Неправильно исполняется код
« Reply #3 on: August 12, 2019, 01:41:33 pm »
Спасибо за быстрый ответ. Работает как задумано, благодарю. Но тогда почему код работал в Pascal N-IDE?
Это для меня тоже загадка. Надо опробовать N-IDE. Давно хотел ...
procedure mulu64(a, b: QWORD; out clo, chi: QWORD); assembler;
asm
  mov rax, a
  mov rdx, b
  mul rdx
  mov [clo], rax
  mov [chi], rdx
end;
(* Pointer game *) Inc(ptr, 1); (* vs *) ptr := ptr + 1;

devisa_san

  • New member
  • *
  • Posts: 12
Re: Неправильно исполняется код
« Reply #4 on: August 12, 2019, 03:07:32 pm »
Ну, и соответственно вопрос почему с Read не работает в Lazarus? Комп в любом случае должен дождаться ввода переменной c, а он этого не делает... Хотелось бы разобраться, а то такое поведение для меня показалось странным. Да, и вообще не первый раз в lazarus наблюдаю такое явление, когда порядок выполнения программы нарушен, но там это было зачастую в программах с графическим интерфейсом и сложной структурой, но тут то простейшая программа с несколькими IF - школьнику паскаль объяснял и тут такое западло вылезло.

julkas

  • Sr. Member
  • ****
  • Posts: 306
  • KISS principle / Lazarus 2.0.0 / FPC 3.0.4
Re: Неправильно исполняется код
« Reply #5 on: August 12, 2019, 03:25:29 pm »
Я думаю, что если начнешь решать online задачки (если уже не начал), тебе будет легче.
Ты из России? Я так понял там популярен PascalABC. Это правда?
procedure mulu64(a, b: QWORD; out clo, chi: QWORD); assembler;
asm
  mov rax, a
  mov rdx, b
  mul rdx
  mov [clo], rax
  mov [chi], rdx
end;
(* Pointer game *) Inc(ptr, 1); (* vs *) ptr := ptr + 1;

devisa_san

  • New member
  • *
  • Posts: 12
Re: Неправильно исполняется код
« Reply #6 on: August 12, 2019, 03:35:54 pm »
Так мне не надо online задачки решать. Я в pascal-delphi-lazarus программирую с 2002 года, я школьнику преподаю и вот такое поведение lazarus для меня оказалось неожиданным. Хотелось бы причину понять. Независимо от того, что использовать read или readln в данном коде, программа себя не должна была вести так, как вела. Я из России. PascalABC использовать не хочу, так как планирую школьника обучать в том числе и программированию приложений с GUI. Повторюсь - мне причину понять интересно, так как код так работать не должен был и другая среда разработки это подтверждает.

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2235
    • havefunsoft.com
Re: Неправильно исполняется код
« Reply #7 on: August 12, 2019, 05:10:43 pm »
Я в pascal-delphi-lazarus программирую с 2002 года, я школьнику преподаю и вот такое поведение lazarus для меня оказалось неожиданным. Хотелось бы причину понять.
тонкости реализации read.

вот такой код:
Code: Pascal  [Select]
  1. program project1;
  2.  
  3. uses
  4.   SysUtils, Classes;
  5.  
  6. var
  7.   a,b: double;
  8.   c:  string;
  9. begin
  10.   try
  11.     read(a);
  12.     read(b);
  13.     read(c);
  14.     writeln(c);
  15.     writeln(byte(c[1]));
  16.     readln;
  17.   except
  18.     on e: exception do
  19.       writeln(e.message);
  20.   end;
  21. end.
  22.  
падает с AccessViolation.

ВНИМАНИЕ! в Delphi 10.3 он точно так же падает с Access Violation!

upd а падает он с AccessViolation потому что я сам дурак.
в данном примере Read(c) возвращает пустую строку. Причём оставшиеся в символы переноса, пудут прочитаны в следующем readln();
а тк я без проверки обращаюсь к c[1] - происходит тот самый AccessViolation

Независимо от того, что использовать read или readln в данном коде, программа себя не должна была вести так, как вела.
это вопрос к реализации процедуры read().
догадываюсь, что read просто пытается прочитать всё, с командной строки (игнорируя знак переноса), и в итоге, читает не то и ни туда.
по-этому использовать readln() безопаснее.
(а ещё раньше read умел читать в PChar, но функционал запретили)

... и другая среда разработки это подтверждает.
не думаю, что N-IDE будет авторитетом для FPC.
Т.к. N-IDE это интерпретатор, и у него вполне могут быть свои особенности.
« Last Edit: August 12, 2019, 05:16:17 pm by skalogryz »
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2235
    • havefunsoft.com
Re: Неправильно исполняется код
« Reply #8 on: August 12, 2019, 05:27:18 pm »
проблема в следующем:
Read() не очищает символы переноса строки в INPUT буфере.

по-этому каждый следующий read() вынужден сам разбираться с ними.

когда ты делаешь read(a) (или read(b)) где "a" и "b" double; то FPC игнорирует пустые строки, и продолжает ожидать ввод числа. (ты можешь это проверить сам. просто запусти программу, не вводя число, нажми "enter". Программа не будет падать, и будет настойчиво продолжать ввода числа).

НО, read(c) рабоатет подругому. Увидев символ конца строки (который остался ещё от ввода числа "b"), он код принимает решение о том, что ввели пустую строку, и тут же её возвращает.

В твоём коде, это приводит к выводу "Wrong" (потому пустая строка, не являеится символом операции).

т.е. нужно использовать именно ReadLn(), чтобы после прочтения значения, символы переноста строки подчищались;
Очевидно, что в N-IDE такими вещами не заморачивались. (надо думать, что у них своя обработка "командной строки", где нет симоволов переноса строк)

FPC работает правильно.
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz

julkas

  • Sr. Member
  • ****
  • Posts: 306
  • KISS principle / Lazarus 2.0.0 / FPC 3.0.4
Re: Неправильно исполняется код
« Reply #9 on: August 12, 2019, 05:38:20 pm »
Quote
(а ещё раньше read умел читать в PChar, но функционал запретили)
@skalogryz   Причина известна?
Я вообще новичок в FPC и просто исходил из опыта чтения входных данных на разных онлайн ...
procedure mulu64(a, b: QWORD; out clo, chi: QWORD); assembler;
asm
  mov rax, a
  mov rdx, b
  mul rdx
  mov [clo], rax
  mov [chi], rdx
end;
(* Pointer game *) Inc(ptr, 1); (* vs *) ptr := ptr + 1;

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2235
    • havefunsoft.com
Re: Неправильно исполняется код
« Reply #10 on: August 12, 2019, 05:45:18 pm »
Quote
(а ещё раньше read умел читать в PChar, но функционал запретили)
@skalogryz   Причина известна?
конечно. у PChar невозможно проверить границы памяти

https://www.freepascal.org/docs-html/current/rtl/system/read.html
Quote
In earlier versions of FPC, it was also allowed to read Pchar null-terminated strings, but this has been removed, since there is no buffer checking possible.
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz

devisa_san

  • New member
  • *
  • Posts: 12
Re: Неправильно исполняется код
« Reply #11 on: August 12, 2019, 07:10:45 pm »
проблема в следующем:
Read() не очищает символы переноса строки в INPUT буфере.

по-этому каждый следующий read() вынужден сам разбираться с ними.

когда ты делаешь read(a) (или read(b)) где "a" и "b" double; то FPC игнорирует пустые строки, и продолжает ожидать ввод числа. (ты можешь это проверить сам. просто запусти программу, не вводя число, нажми "enter". Программа не будет падать, и будет настойчиво продолжать ввода числа).

НО, read(c) рабоатет подругому. Увидев символ конца строки (который остался ещё от ввода числа "b"), он код принимает решение о том, что ввели пустую строку, и тут же её возвращает.

В твоём коде, это приводит к выводу "Wrong" (потому пустая строка, не являеится символом операции).

т.е. нужно использовать именно ReadLn(), чтобы после прочтения значения, символы переноста строки подчищались;
Очевидно, что в N-IDE такими вещами не заморачивались. (надо думать, что у них своя обработка "командной строки", где нет симоволов переноса строк)

FPC работает правильно.

Благодарю за развёрнутый ответ! Теперь всё на свои места встало. Но тогда у меня ещё один вопрос, а зачем Read() реализован так? Это же вот такие странные ситуации вызывает и, получается, делает невозможным ввод строк при помощи этого оператора.
Например в нижеприведённом коде мы сможем ввести только одну строку a. b окажется пустой.

program Project1;
var a,b:string;
begin
  read(a);
  read(b);
  writeln(a);
  writeln(b);
  readln;
  readln;
end.

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2235
    • havefunsoft.com
Re: Неправильно исполняется код
« Reply #12 on: August 12, 2019, 07:49:03 pm »
Благодарю за развёрнутый ответ! Теперь всё на свои места встало. Но тогда у меня ещё один вопрос, а зачем Read() реализован так? Это же вот такие странные ситуации вызывает и, получается, делает невозможным ввод строк при помощи этого оператора.
потому что Read() и Readln() был сделан для чтения текстовых файлов (где символы переноса строки имеют свой смысл).
Консоль в данном случае рассматривается только как частный случай файлов.

Если использовать read() для консоли, то правильнее исползовать именно readln(), а не read().
Потому что readln() обрабатывает входную строку целиком.

Можно добавить, что именно N-IDE работает неправильно ;)

а зачем в коде:
Code: Pascal  [Select]
  1. readln;
  2. readln;
  3. readln;
????
почему их именно 3?
« Last Edit: August 12, 2019, 07:56:40 pm by skalogryz »
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz

devisa_san

  • New member
  • *
  • Posts: 12
Re: Неправильно исполняется код
« Reply #13 on: August 14, 2019, 03:38:02 pm »

а зачем в коде:
Code: Pascal  [Select]
  1. readln;
  2. readln;
  3. readln;
????
почему их именно 3?

Если оставить хотя бы два readln, то в исходной версии кода программа сразу по нажатии на enter на этапе ввода операции завершиться.

В исправленном коде с read заменёнными на readln хватает и одного readln, чтобы она не завершалась сразу по вводу операции.

Но вообще помимо вопроса по данному конкретному примеру у меня есть вопросы по другим случаям. Возможно ли их тут озвучить или надо новые темы создавать?  В общем то они все связаны с тем, что код выполняется не так как ожидалось.

Один всё таки озвучу. Например буквально на днях в проекте создавал класс который включал в себя массив записей. В записях планировал создать два поля типа boolean, последовательность действий была такая - сначала описал только одно поле с данным типом, проверил - всё работало, как только добавил второе поле с таким же типом, программа работать перестала. Убирал второе поле - работало, добавлял - переставало. Сам код не сохранился, так как я решил по другому действовать, а вот пример объявления остался (соответственно в полях StatData были объявлены поля типа boolean):

type StatData = record
     date:TDateTime;
     input:integer;
     output:integer;
     end;

type TStatistic = class
     SData:array of StatData;
     procedure StatDataFloat(firstdate,lastdate:TDateTime;Method:integer;UseCol:boolean);
     procedure StatDataToStringGrid(var StringGrid:TstringGrid);
     procedure StringGridAutoSize(Var StringGrid:TstringGrid);
     procedure StatDataToTabel(var tab:TTabel);
     procedure FinanceStatistic(firstdate,lastdate:TDateTime;Method:integer;UseCol:boolean);
end; 

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2235
    • havefunsoft.com
Re: Неправильно исполняется код
« Reply #14 on: August 14, 2019, 03:49:02 pm »
Возможно ли их тут озвучить или надо новые темы создавать? 
конечно, можно здесь...

Один всё таки озвучу. Например буквально на днях в проекте создавал класс который включал в себя массив записей. В записях планировал создать два поля типа boolean, последовательность действий была такая - сначала описал только одно поле с данным типом, проверил - всё работало, как только добавил второе поле с таким же типом, программа работать перестала. Убирал второе поле - работало, добавлял - переставало.  Сам код не сохранился...
я бы предложил реализовать проект ещё раз, и проверить воспроизведётся ошибка или нет.
Без кода, разговор получится на пустом месте.

но я уже вижу тревожные звоночки в виде:
Code: Pascal  [Select]
  1.      procedure StatDataToStringGrid(var StringGrid:TstringGrid);
  2.      procedure StringGridAutoSize(Var StringGrid:TstringGrid);
  3.      procedure StatDataToTabel(var tab:TTabel);
а именно - тревожит наличие "var". Причём, я не думаю, что ошибка была в исползовании "var". Просто само его использование в данным случае излишне. "var" для класса имеет несколько иное значение, чем "var" для record-а.
« Last Edit: August 14, 2019, 03:52:54 pm by skalogryz »
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz