IPB
ЛогинПароль:

 
 Ответить  Открыть новую тему 
> Безопасный ввод данных с клавиатуры
сообщение
Сообщение #1





Группа: Пользователи
Сообщений: 5
Пол: Мужской

Репутация: -  0  +


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

Я уже реализовал это таким способом, но он меня не совсем устраивает:
Procedure Input_From_Keyboard(Var aa,bb,cc: real);
Var
Error: integer;
Begin
Repeat
ClrScr;
WriteLn('Введите a,b,c');
{$I-}
ReadLn(aa,bb,cc);
{$I+}
Error:=IOResult;
if Error<>0 then Error_Message;
Until Error=0;
End;

Работает отлично, если, скажем, введена такая последовательность "-4 5 %" (знак процента числом, как видно, не является), но если ввести "-7 5 gj hu hfh eio", то программа после первого вывода сообщения об ошибке и нажатия клавиши выведет его ещё раз. Если ввести много левых данных через пробел, то она много раз выведет ошибку, так что приходится это много раз жать на "любую клавишу".

Другой вариант
Procedure Input_From_Keyboard(Var aa,bb,cc: real);
Var
Error: integer;
aaa,bbb,ccc: char;
Begin
Repeat
ClrScr;
Error:=0;
WriteLn('Введите a,b,c');
ReadLn(aaa,bbb,ccc);
val(aaa,aa,Error); if Error=0 then begin
val(bbb,bb,Error);
if Error=0 then val(ccc,cc,Error);
end;
if Error<>0 then Error_Message;
Until Error=0;
End;

Тут всё ещё печальнее, переменной bbb присваивается значение пробела. Использовать методику введения дополнительной переменной и записывания в неё пробелов как-то не хочется.
На всякий случай
Procedure Error_Message;
Begin
WriteLn('Введены некорректные данные.');
WriteLn('Нажмите любую клавишу и повторите ввод.');
WriteLn('Для выхода из программы нажмите клавишу Esc.');
if readkey=#27 then halt;
End;

Для компиляции используется Free Pascal 2.6.0 x64 на ОС Linux Ubuntu 10.04.3 (если это имеет какое-то значение)

Сообщение отредактировано: Yegor -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #2


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


Цитата
Если ввести много левых данных через пробел, то она много раз выведет ошибку, так что приходится это много раз жать на "любую клавишу".
Чтобы этого не происходило - надо кроме вывода служебного сообщения (Error_Message) еще и прекратить чтение данных. Это можно сделать единственным способом: прочесть все, что осталось, в строку:

procedure Input_From_Keyboard(var aa, bb, cc : real);
var
Error : integer;
s : string;
begin
repeat
writeLn('Введите a, b, c');
{$I-}
ReadLn(aa, bb, cc);
{$I+}
Error := IOResult;
if Error <> 0 then
begin
Error_Message;
readln(s); // !!!
end;
until Error = 0;
end;
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #3





Группа: Пользователи
Сообщений: 5
Пол: Мужской

Репутация: -  0  +


IUnknown, спасибо, помогло.
Но у этого метода есть один минус - программа становится уязвимой к введённым данным, получается, что если туда ввести чего-то очень много, то это что-то целиком запишется в оперативную память, что крайне нежелательно.
Знаю, что в паскаль можно вставить ассемблерные вставки, ассемблер, к сожалению, не знаю. Порылся в гугле, искал способы очистки буфера клавиатуры, всё, что находил по этому в итоге не компилировалось. Выводились ошибки, разные, то неизвестная ассемблерная команда, то ошибка синтаксиса.
Так что хотелось бы узнать, как очистить буфер клавиатуры с помощью ассемблерной вставки, раз, по словам IUnknown средствами паскаля это невозможно.

Сообщение отредактировано: Yegor -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #4


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


> что если туда ввести чего-то очень много, то это что-то целиком запишется в оперативную память

А оно где, по-твоему и так сидит?

> Так что хотелось бы узнать, как очистить буфер клавиатуры с помощью ассемблерной вставки

Это делается и без ассемблера (вроде надо просто сделать одно присвоение Mem[***:***] := Mem[***:***], только я адреса не помню), но в твоём случае это не надо.

> раз, по словам IUnknown средствами паскаля это невозможно.

Не говорил он такого.
Просто в твоём случае лезть в дебри не надо.

Сообщение отредактировано: TarasBer -


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #5





Группа: Пользователи
Сообщений: 5
Пол: Мужской

Репутация: -  0  +


> что если туда ввести чего-то очень много, то это что-то целиком запишется в оперативную память
А оно где, по-твоему и так сидит?
>> readln(s); - вот как раз в переменной s

Это делается и без ассемблера (вроде надо просто сделать одно присвоение Mem[***:***] := Mem[***:***], только я адреса не помню), но в твоём случае это не надо.
>> Адреса узнать не проблема, только почему не надо?

> раз, по словам IUnknown средствами паскаля это невозможно.
Не говорил он такого.
Просто в твоём случае лезть в дебри не надо.
>> "Это можно сделать единственным способом". Я имел ввиду то, что он сказал что невозможно иным способом, на счёт дебрей, почему бы и нет?)

И, кстати, такая печалька: free pascal 2.6.0 на linux ubuntu 10.04.3 операцию Mem не понимает. Пишет "Identifier not found"

Сообщение отредактировано: Yegor -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #6


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


Цитата
Но у этого метода есть один минус - программа становится уязвимой к введённым данным, получается, что если туда ввести чего-то очень много, то это что-то целиком запишется в оперативную память, что крайне нежелательно.
Пример "уязвимости" - в студию. Ибо пока вот что получается:

uses crt;
procedure error_message;
begin
writeln('error');
end;

Procedure Input_From_Keyboard(Var aa,bb,cc: real);
var
Error : integer;
s : string;
begin
repeat
writeLn('Введите a,b,c');
{$I-}
ReadLn(aa,bb,cc);
{$I+}
Error := IOResult;
if Error <> 0 then
begin
Error_Message;
readln(s); // !!!
end;
until Error = 0;
end;


var
a, b, c : real;
s : string;
begin
input_from_keyboard(a, b, c);
readln(s);
writeln(s);
end.

Попробуй эту "уязвимость" использовать. Вводи "1 2 3 hello world". И не запуская программу скажи, чего ожидаешь от нее. Что должно произойти после того, как нажмешь Enter? А потом запусти и посмотри, что произойдет. Так что в дебри действительно не надо лезть. Тем более в Ассемблер.

Цитата
И, кстати, такая печалька: free pascal 2.6.0 на linux ubuntu 10.04.3 операцию Mem не понимает. Пишет "Identifier not found"
Пичалька в том, что FPC вообще не понимает эту операцию: Reference for unit 'System': Variables: Mem/MemW/MemL доступны только в DOS

Сообщение отредактировано: IUnknown -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #7





Группа: Пользователи
Сообщений: 5
Пол: Мужской

Репутация: -  0  +


Не совсем корректно выразился. Эта переменная s будет ненужным грузом в оперативной памяти. А, насколько я знаю, есть ограничение в использовании оперативной памяти в 64 кб (если не ошибаюсь, но при попытке создать большой массив сыпятся непонятные ошибки). Пишу программы для математических расчётов, которые могут требовать довольно много памяти, так что вполне возможно что этих 256 байт (или сколько она максимально может содержать) не хватит.

Сообщение отредактировано: Yegor -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #8


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


Цитата
Эта переменная s будет ненужным грузом в оперативной памяти.
Ничего, что эта переменная описана локально? Как только ты вышел из процедуры - ее больше нет.

Цитата
А, насколько я знаю, есть ограничение в использовании оперативной памяти в 64 кб
Я тебя умоляю, не смеши меня... На кой тебе под x64 такой компилятор был бы нужен, который ограничивал бы использование памяти 64-мя килобайтами?

Цитата
если не ошибаюсь, но при попытке создать большой массив сыпятся непонятные ошибки
Максимальный размер одной структуры и общее ограничение объема доступной памяти - это несколько разные вещи. Но в любом случае единственное ограничение на размер массива, с которым я сталкивался на данный момент - это ограничение на размер индекса. Индексов не может быть больше, чем High(PTRINT). На 32-битной системе это 2147483647. То есть, массив на десяток мегабайт выделяется легко. Что за ошибки у тебя вылазили?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #9


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


>> readln(s); - вот как раз в переменной s

А ещё оно сидит в памяти той системной функции, которая считывает данные с клавиатуры. То есть можно просто открыть консоль, ввести два мимллиарда символов и система сдохнет, да?


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #10





Группа: Пользователи
Сообщений: 5
Пол: Мужской

Репутация: -  0  +


Вот такие ошибки сыпятся, когда пытаюсь хотя бы создать большой массив (скопировать в виде текста не удаётся, поэтому оставляю скрин)
Изображение
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #11


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


А ты умножь 100 000 на 100 000 на 10.

тебе 100 гигабайт надо на такой массив.
Нафига тебе столько? Бери всегда столько памяти, сколько нужно.

Сообщение отредактировано: TarasBer -


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 





- Текстовая версия 23.12.2024 22:41
500Gb HDD, 6Gb RAM, 2 Cores, 7 EUR в месяц — такие хостинги правда бывают
Связь с администрацией: bu_gen в домене octagram.name