Спасибо за быстрый ответ. Работает как задумано, благодарю. Но тогда почему код работал в Pascal N-IDE?Это для меня тоже загадка. Надо опробовать N-IDE. Давно хотел ...
Я в pascal-delphi-lazarus программирую с 2002 года, я школьнику преподаю и вот такое поведение lazarus для меня оказалось неожиданным. Хотелось бы причину понять.тонкости реализации read.
Независимо от того, что использовать read или readln в данном коде, программа себя не должна была вести так, как вела.это вопрос к реализации процедуры read().
... и другая среда разработки это подтверждает.не думаю, что N-IDE будет авторитетом для FPC.
(а ещё раньше read умел читать в PChar, но функционал запретили)@skalogryz Причина известна?
конечно. у PChar невозможно проверить границы памятиQuote(а ещё раньше read умел читать в PChar, но функционал запретили)@skalogryz Причина известна?
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.
проблема в следующем:
Read() не очищает символы переноса строки в INPUT буфере.
по-этому каждый следующий read() вынужден сам разбираться с ними.
когда ты делаешь read(a) (или read(b)) где "a" и "b" double; то FPC игнорирует пустые строки, и продолжает ожидать ввод числа. (ты можешь это проверить сам. просто запусти программу, не вводя число, нажми "enter". Программа не будет падать, и будет настойчиво продолжать ввода числа).
НО, read(c) рабоатет подругому. Увидев символ конца строки (который остался ещё от ввода числа "b"), он код принимает решение о том, что ввели пустую строку, и тут же её возвращает.
В твоём коде, это приводит к выводу "Wrong" (потому пустая строка, не являеится символом операции).
т.е. нужно использовать именно ReadLn(), чтобы после прочтения значения, символы переноста строки подчищались;
Очевидно, что в N-IDE такими вещами не заморачивались. (надо думать, что у них своя обработка "командной строки", где нет симоволов переноса строк)
FPC работает правильно.
Благодарю за развёрнутый ответ! Теперь всё на свои места встало. Но тогда у меня ещё один вопрос, а зачем Read() реализован так? Это же вот такие странные ситуации вызывает и, получается, делает невозможным ввод строк при помощи этого оператора.потому что Read() и Readln() был сделан для чтения текстовых файлов (где символы переноса строки имеют свой смысл).
а зачем в коде:????
readln; readln; readln;
почему их именно 3?
Возможно ли их тут озвучить или надо новые темы создавать?конечно, можно здесь...
Один всё таки озвучу. Например буквально на днях в проекте создавал класс который включал в себя массив записей. В записях планировал создать два поля типа boolean, последовательность действий была такая - сначала описал только одно поле с данным типом, проверил - всё работало, как только добавил второе поле с таким же типом, программа работать перестала. Убирал второе поле - работало, добавлял - переставало. Сам код не сохранился...я бы предложил реализовать проект ещё раз, и проверить воспроизведётся ошибка или нет.
Один всё таки озвучу. Например буквально на днях в проекте создавал класс который включал в себя массив записей. В записях планировал создать два поля типа boolean, последовательность действий была такая - сначала описал только одно поле с данным типом, проверил - всё работало, как только добавил второе поле с таким же типом, программа работать перестала. Убирал второе поле - работало, добавлял - переставало. Сам код не сохранился...я бы предложил реализовать проект ещё раз, и проверить воспроизведётся ошибка или нет.
Без кода, разговор получится на пустом месте.
но я уже вижу тревожные звоночки в виде:а именно - тревожит наличие "var". Причём, я не думаю, что ошибка была в исползовании "var". Просто само его использование в данным случае излишне. "var" для класса имеет несколько иное значение, чем "var" для record-а.
procedure StatDataToStringGrid(var StringGrid:TstringGrid); procedure StringGridAutoSize(Var StringGrid:TstringGrid); procedure StatDataToTabel(var tab:TTabel);
По поводу var - хотелось бы знать отличие. В данном случае поставил var, чтобы процедура работала непосредственно с данными классами не создавая копию. Без них код не работал - данные из процедур не передавались далее. Кстати, процедура procedure StatDataToTabel(var tab:TTabel); у меня так и не заработала как надо. Почему опять таки я не понял.Тип класс-а в Object Pascal-е (и FPC и Delphi) всегда ссылочный.
По результату получается, что вся таблица Tab заполнена данными только за одну дату - последнююсогласно приведённом коду, именно так и должно работать.
Тип класс-а в Object Pascal-е (и FPC и Delphi) всегда ссылочный.
"var" для переменной класса, означает, что ссылка может быть изменена.
При наличии var, или без него, копии данных создаваться не будет (опять же потому что передаётся ссылка на объект класса)
В большинстве случаев нужды в var нет. Кроме тех случаев, когда нужно создать объект класса (или, реже, поменять ссылку на объект класса).
Тогда непонятно почему данные не передавались без var...По результату получается, что вся таблица Tab заполнена данными только за одну дату - последнююсогласно приведённом коду, именно так и должно работать.
Т.к. строки в таблицу не добавляются, а добавляется всего одна строка всего один раз.
После чего один ряд перезаписывается N раз (где N соответствует количеству дат - 1); И в единственно добавленный ряд попадает последняя запись из SDate
[code=pascal]
writeln('hello world');
[ /code]
(пробел в закрывающем тэге между "[" и "/code]" нужно убрать. здесь он для примера)В общем в цикле после SData идут квадратные скобки и индекс i внутри них. SData - это массив записей.это всё хорошо, но в цикле, в котором ты проходишь SData, ты не создаёшь новых рядов для TTabel.
правильно постить код, можно при помощи тэга:Code: [Select][code=pascal]
(пробел в закрывающем тэге между "[" и "/code]" нужно убрать. здесь он для примера)
writeln('hello world');
[ /code]
результат:
writeln('hello world');
https://wiki.freepascal.org/Forum#Use_code_tagsВ общем в цикле после SData идут квадратные скобки и индекс i внутри них. SData - это массив записей.это всё хорошо, но в цикле, в котором ты проходишь SData, ты не создаёшь новых рядов для TTabel.
У тебя даже закоментирован код tempTab.AddRow(new);
И он правильный, но только при условии, что "new" будет точно так же оздаваться внутри цикла, а не до него.
Т.е. должно работать, если new создавать каждый новый цикл?да
Потому что мы каждый раз при добавлении передаём ссылку на экземпляр класса в TTabel, а если этого не делать, то все записи в TTabel будут ссылками на один и тот же экземпляр и потому результат и получается таким, что таблица состоит только из того, что было в последней строке?нет. TTabel у тебя один.
нет. TTabel у тебя один.
у тебя на каждую итерацию нужно создавать новый TRow.
сколько рядов, столько раз TRow нужно создавать.
Почему нет? Фишка в том, что в результате получается таблица в которой количество TRow правильное, но эти TRow одинаковые. Что тогда в данном варианте происходит? Получается на каждой итерации я присваиваю значение одному и тому же экземпляру класса, а в TTabel у меня храняться только ссылки на него. И тогда мне становится понятно, почему вся таблица была заполнена теми значениями, что в SData были последние. И тогда действительно всё должно заработать, если создавать в цикле каждый раз новый TRow.
Почему нет?потому что ранее ты писал про "TTabel":
Потому что мы каждый раз при добавлении передаём ссылку на экземпляр класса в TTabel, а если этого не делать, то все записи в TTabel будут ссылками на один и тот же экземпляриз контекста понятно, что ты говоришь про TRow.
Почему нет?потому что ранее ты писал про "TTabel":Потому что мы каждый раз при добавлении передаём ссылку на экземпляр класса в TTabel, а если этого не делать, то все записи в TTabel будут ссылками на один и тот же экземпляриз контекста понятно, что ты говоришь про TRow.
Но т.к. ты создаёшь и TTabel и TRow тебе следует быть внимательнее.
В остальном размышления верны?да