1) Вы выбрали совершенно неудачный способ передачи параметров. Во-первых, для чего здесь использовать массив? Массив используется для хранения однородных элементов, вектора, а здесь у вас в него валится и дискриминант, и корни. Имело бы смысл использовать массив для корней, если бы их могло быть больше двух, а тут...
Дискриминант - это часть внутренней реализации процедуры решения кв. ур-я - и его не следует выносить наружу! У вас интерфейсный код узнает, есть ли корни, по значению дискриминанта, а должен всего лишь получить TRUE/FALSE - есть ли корни или нет.
А если мы захотим изменить реализацию процедуры ReshKvUr - и будем вычислять корни, ну, к примеру, численным методом (пусть и маразм), без вычисления дискриминанта? Что возвращать в m[0] будем?
Думаю, убедил, что так нельзя.
А как тогда? Да заведите вы три выходных атомарных параметра:
PROCEDURE ReshKvUr* (a,b,c: REAL; OUT exist: BOOLEAN; OUT x1, x2: REAL).
Возвращайте наружу через exist, есть ли корни, а в x1, x2 - сами эти корни (если дискриминант равен нулю, то все равно два корня, только равны между собой).
Теперь по поводу возвращаемого значения процедуры. Ну, самое первое - если процедура имеет OUT-параметры, то возвращаемое значение ей обычно не задают. Это так называемый принцип "чистоты функций". Т.е. если пишем функцию, которую можно будет использовать в выражениях, то она не должна ничего менять ни вокруг себя, ни в своих параметрах, а только возвращать значение (как функция в математике).
Т.е. в вашем варианте вместо возврата значения надо было бы заводить еще один OUT-параметр: OUT noErrors: BOOLEAN).
Однако если мы отказались от массива, то он стал не нужен.
Однако - подумаем, а зачем он нужен вообще? Просто для проверки правильности входных данных - что нам подали на входе массив верного размера? Я вам открою еще один секрет - проверку через IF и возврат ошибки для этих случаев не делают. Соблюдение всех условий по входным данным - так называемых предусловий - это обязанность того, кто процедуру вызывает. А на входе процедуры ставится проверка соблюдения этих предусловий - оператор ASSERT: для вашего случая было бы - ASSERT(LEN(m) >= 3). И все. Что произойдет, если процедуре подадут неверные данные? Попробуйте - увидите, что выскочит окошко сбоя - трепа. Все правильно - нарушение предусловия процедуры - это и есть сбой, и выполнение процедуры немедленно прерывается.
А явные коды результатов "успех-неуспех" используются в случаях, когда ошибка может быть где-то в окружении, когда это не сбой в самой программе. Ну например, не удалось подключиться к серверу или открыть файл. Тогда мы как-то можем обрабатывать ошибку. А если нам неверный массив подали - то что тут обрабатывать? Нужно немедленно прерывать выполнение программы, что и делает ASSERT...
В общем, осмыслите все сказанное - это как раз очень важные вещи. И хорошо, что появилась возможность все их разом объяснить на разборе конкретных ошибок...
Кстати, а можно еще вообще не возвращать явно "есть ли корни, нет ли корней". У типа REAL есть особое значение - бесконечность, неопределенность. Записывается как INF.
Просто, если корней нет, то вернем x1=x2=INF.
А код верхнего уровня будет проверять IF x1 # INF THEN корни есть ELSE корней нет END.
2)
Цитата:
Если в StudKvur вместо OUT m: ARRAY OF REAL написать OUT m: ARRAY 3 OF REAL, то в StudKvurExF будет возникать ошибка: StudKvur.ReshKvUr(ar[тип не совпадает с типом формального VAR параметра],a,b,c)
Непонятно почему так нельзя…
Вкратце - массивы должны быть одного типа. Однако у вас возникает вопрос - а почему же они не одного типа, если объявлены одинаково?
Это еще ничего не значит, если размерности двух массивов случайно совпали - они все равно принадлежат к разным типам (может быть, в одном хранятся одни физические величины, а в другом - другие, какая же тут совместимость?)
Чтобы массивы стали совместимы, нужно явно объявить общий для них тип:
Код:
TYPE
Ответ = ARRAY 3 OF REAL;
PROCEDURE Resh (ответ: Ответ);
END Resh;
PROCEDURE Test;
VAR отв: Ответ;
BEGIN
Resh(отв)
END Test;
- вот так заработает.
Вдумайтесь еще раз, почему массивы одинаковой размерности по умолчанию все равно несовместимы. Ведь совпадение могло быть случайным, а массивы предназначались совсем для разных целей. Кто-то по ошибке его использовал, а затем я изменил размер массива в своей процедуре - и все, совпадение прекратилось, тот, кто моей процедурой поспешно воспользовался, остался в дураках...
Поэтому и нужно вводить явно специальный тип массива и потом его использовать.
А форма записи ARRAY OF.. - это открытый массив, он специально предназначен для написания процедур, обрабатывающих массивы переменных размеров.
3) С линковкой сейчас смотреть времени нет. Почитайте в Общих вопросах, там это обсуждалось. Вообще, для полной комплектации в EXE-файл надо линковать много модулей. Там в документации на DevLinker этот список есть, только добавьте National.
И все равно еще снаружи должны болтаться файлы ресурсов.
Чтобы собрать совсем один EXE, нужно потом применить еще DevPacker.
В общем, дело несложное (см.
viewtopic.php?t=196), но немножко разбираться в среде нужно...
4) По поводу указателей.
Эээ, батенька, указатели нужно изучить, без них далеко не уедешь. Динамическое выделение памяти используется сплошь и рядом. Почитайте для начала любую книжку хоть по Турбо Паскалю, ну не объяснять же все это здесь... В самоучителе от Info21 (у нас в Документации) вроде бы это тоже было...
Цитата:
Т.е. по большему счету это нужно для эффективности? Или есть еще какой смысл в них?
Ни одно реальное приложение не знает, сколько и каких переменных ему понадобится в момент выполнения. Например, открылось новое окно с документом и графическим объектом - ему требуется память. Она выделяется динамически.
NEW - это оператор языка для выделения памяти.
А New.. и т.п. - это уже разнообразные самые обычные процедуры, которые создают новый объект оператором NEW, чего-то там ему инициализируют в полях, а затем возвращают указатель.