Уроки Phptoshop, Linux, Windows 7
23 Май 2012, 01:28:02 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
Новости:
 
  Начало   Форум   Помощь Поиск Календарь Пользователи Downloads Войти Регистрация  
Страниц: [1]   Вниз
  Печать  
Автор Тема: Алгоритмы  (Прочитано 7619 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Nm0n
Гость
« : 07 Август 2009, 11:55:34 »

Написание оптимального кода под Delphi
В данной статье рассмотрены принципы, помогающие компилятору Delphi генерировать более оптимальный с точки зрения скорости код. Если Вы не хотите вникать в подробности, в конце статьи есть «свод правил», которые рекомендуется соблюдать при написании программ.

Компилятор Delphi относится к разряду оптимизирующих. Но насколько качественно проводится оптимизация? Как «помочь» компилятору создать более быстрый код? Давайте разберемся с этим на экспериментах.
Оптимизация константных выражений
Пример 1:

const
z = 15616;
...
var
a,b: integer;
...
a := $abcd6123;
b := z+a;
....

С точки зрения оптимизации код можно упростить еще на этапе компиляции до
b:=15616+$abcd6123;
или того проще:
b:=$ABCD9E23;

Но написанный выше листинг преобразуется в
mov eax, $abcd6123
lea ebx, [eax + $00003D00]

С одной стороны компилятор не «сообразил», что значение переменной «a» можно преобразовать в константу и сложить с другой константой (которая, заметим, подставлена именно как константа) на этапе компиляции, с другой стороны был применен весьма хитрый трюк с LEA (об этом ниже). Тем не менее, код
mov ebx, $ABCD9E23
в любом случае быстрее и короче.
Пример 2:

...
b:=random(maxint); // b – заведомо не константа !
a:=$abcd6123;
if b>a then b:=a;
...

Скомпилированный код будет выглядеть
mov eax, $7fffffff // MaxInt
call @RandInt
mov ebx,eax
mov eax, $abcd6123
cmp eax, ebx
jnl +$02
...

А ведь значение, присвоенной переменной «а» являлось константой и наш пример можно было бы переписать как:
b:=random(maxint);
a:=$abcd6123;
if b>$abcd6123 then b:= $abcd6123;
Пример 3:

...
a:=$abcd6123;
b:=$abc34233;
c:=b-a;
...

После компиляции получаем:
mov eax, $abcd6123
mov ebx, $abc34233
mov ebx, edx
sub ebx, eax

Т.е. компилятор преобразовал код так, как он был написан, а ведь можно было бы просто записать:
mov ebx, $fff5e110
т.е. c:= $fff5e110;
Оптимизация алгебраических выражений
Пример 4:

...
var
a,b,c,d: integer;
p: pointer;
begin
p:=nil;
a:=0;
...
{далее по коду эти присвоения не используются}

После компиляции эти переменные будут удалены, причем с предупреждением
Value assigned to ... never used
Пример 5:

...
a:=0;
b:=a;
showmessage(inttostr(b));
...

Код скомпилируется как есть! Таким образом мы обманули компилятор псевдо использованием переменных. Delphi не исправляет нашей «кривости», поэтому эта задача ложится исключительно на плечи программиста.
Пример 6:

...
b:=random(maxint);
a:=b;
func(a,b);
a:=a+1;
func(a,b);
...

Данный код можно оптимизировать до
...
b:=random(maxint);
func(b,b);
a:=b+1;
func(a,b);
...

И этого Delphi за нас не сделает.
Пример 7:

...
c:=a div b;
c:=a*b;
...

В данном примере первую строчку можно безболезненно удалить, что Delphi делать умеет.
Пример 8:

if ((a*b)<$3d00) and (a*b)>0)) then ...

В данном случае можно избавится от одной операции умножения, присвоив значение выражения a*b временной переменной. Анализ ассемблерного листинга показывает, что компилятор именно так и поступает. Тем не менее, поменяв второе подвыражение на ((b*a)>0), компилятор принимает выражения за разные и генерирует умножение для обоих случаев, не смотря на то, что результат одинаков.
Оптимизация арифметических операций
Сложение и вычитание

Применение инструкции LEA вместо ADD позволяет производить сумму 3х операндов (двух переменных и одной константы) за один такт. Трюк заключается в том представление ближних указателей эквивалентно их фактическому значению, поэтому результат, возвращенный LEA равен сумме ее операндов. При возможности Delphi производит такую замену.
Деление

Операция деления требует гораздо больше тактов процессора, нежели умножение, поэтому замена деления на умножение может значительно ускорить работу. Существуют формулы, позволяющие выполнять такое преобразование. Тем не менее, Delphi не использует такую оптимизацию. Деление на степень двойки можно заменять сдвигом вправо на n бит, но даже в этом случае получаем следующий код:
mov esi,edi
sar esi,1
jns +$03
adc esi, $00

Здесь учитывается особенность самой операции div – округление в большую сторону. Поэтому, если можно пренебрегать округлением, используйте c:=a shr 1 вместо с:=a div 2.
Умножение

Умножение на степень двойки можно заменять сдвигами битов. Delphi заменяет умножение сдвигами при умножении на 4,8,16 итд. При умножении на 2 производится суммированием переменной с собой.

Умножать на 3,5,6,7,8,10 и т. д. можно и без операции умножения – расписав выражение по формуле (a shl n)+a, где n – показатель степени двойки. Например, при умножении на 3 n=1. Delphi при возможности прибегает к этому трюку. Заметим, операнд LEA умеет умножать регистр на 2,4,8, что также при возможности используется компилятором. Например, умножение на 3 преобразуется в инструкцию
lea esi, [ebx + ebx*2]
Оптимизация case of

Анализ скомпилированного кода показывает, что Delphi проводит утрамбовку дерева. Т.е. значения case сортируются и выбор нужного элемента производится при помощи двоичного поиска.

В случае, если элементы case of выстраиваются в арифметической прогрессии, компилятор формирует таблицу переходов. Т.е. создается массив указателей с индексами элементов, поэтому выбор нужно элемента выполняется за одну итерацию независимо от количества элементов.
Оптимизация циклов

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

Слияние циклов – не производится. Если два цикла, следующие друг за другом имеют одинаковые границы итерационной переменной, разумно оба цикла объединить в один.

Вынесение инвариантного кода за пределы цикла – не выносится. Наиболее распространенный недочет – условие цикла записывается как:
for i:=0 to memo1.lines.count – 1 do...

Delphi будет при каждой итерации вызывать метод count, вычитать из результата 1 и потом уже сверять. Настоятельно рекомендуется переписывать подобный код как
lin := .lines.count – 1;
for i:=0 to lin do...

Весь код VCL написан с нарушением этого правила. Очевидно, что проще подобного рода оптимизацию встроить в компилятор, нежели переписывать VCL :)

Замена циклов с предусловием на циклы с постусловием – производится. Циклы с постусловием имеют главное преимущество над другими видами циклов (с предусловием и с условием в середине) – они содержат всего одно ветвление. Delphi производит такую замену.

Замена инкремента на декремент – не производится. Более того, даже декрементный цикл компилируется в неоптимальный код, т.к. не используется флаг ZF. Вместо этого происходит сравнивание значения регистра с 0.

Удаление ветвлений – не производится.
Вывод:
Не используйте переменные для временного хранения констант или обязательно объявляйте «магические» числа как const, либо подставляйте в код непосредственные значения
Неиспользуемыми объявлениями и присвоениями можно безболезненно пренебрегать – Delphi умеет их вычищать.
Внимательно следите за использованием переменных, в частности лишним присвоениям их значений друг другу. Такого рода оптимизации Delphi делать не умеет.
Используйте свернутые математические выражения. (например, (3*a - a) /2 упрощается до a). Delphi не умеет упрощать математические выражения. (Да и что говорить, даже MathCAD не всегда грамотно умеет делать такие преобразования).
Не используйте конструкции типа a:=10*sin(45*pi/180); Delphi не вычислит эту константу на этапе компиляции, напротив, будет послушно вызывать sin и pi по ходу выполнения программы! В случае, если угол является переменной, по крайней мере pi можно заменить константой 3,1415...
Delphi прекрасно справляется с выражениями, полностью составленных из констант – они вычисляются на этапе компиляции.
Внимательно следите за условиями и их границами. Компилятор Delphi не умеет обнаруживать заведомо ложных условий. Также он не умеет удалять заведомо лишние условия. Например, (a>0) and (a<15616) and (a<>0)
Если в условии несколько раз проверяется одно и тоже выражение, следите, чтобы оно было выражено во всех конструкциях одинаково. В противном случае скомпилированный код будет не оптимален. Например, if ((a*b)>0) and ((a*b)<1024) then... При перестановке во втором случае b*a смысл выражения не изменится, но код будет иметь уже на одну операцию умножения, а две. Можно временно присвоить проверяемое выражение временной переменной, а затем уже проверять полученное значение.
Сообщение «Combining signed and unsigned types – widened both operands» сообщает не только о потенциальной ошибке – также вследствие преобразования мы теряем производительность. Например, z – объявлена как ineteger. условие if z>$abcd6123 then z:= $abcd6123; несмотря на его правильность вызовет данное предупреждение. Сгенерированный код будет, выполнять преобразования величин до 64-х бит, и дальнейшее уже сравнение 64-х битных операндов. Если изменить тип z на cardinal, мы избавимся от предупреждения и получим 3 строки кода, вместо 8 !
Delphi умеет оптимизировать сложение, умножение и частично деление. При делении на степень двойки, если не важно округление до большего, рекомендуется пользоваться shr 1 вместо div 2.
В case of при возможности используйте элементы, расположенные в арифметической прогрессии. Тем не менее, даже при невыполнении данного условия мы получим качественный код после утрамбовки дерева.
Выносите инвариантный код за тело цикла. Наиболее частая ошибка – for i:=1 to length(str) do... Дело в том, что при каждой итерации будет вызываться функция length, что пагубно скажется на производительности. Рекомендуется длину строки заранее присвоить переменной. Также не включайте в тело цикла код, заведомо не зависящий от изменения итерационной переменной.

Сравнивая Delphi с компиляторами Visual C++, WATCOM, Borland C++ (тестирование данных компиляторов приведено в [1]) приходим к выводу, что Delphi по своим оптимизирующим свойствам аналогичен Borland C++ (а кто сомневался? ;) ). Учитывая, что Borland C++ по итогам сравнения оказался последним, делаем несложный вывод. Весьма печален и тот факт, что большинство кода VCL написано с точки зрения «красоты» кода, а не его оптимальности с точки зрения скорости. Например, не соблюдается правило 12.
Записан
Nm0n
Гость
« Ответ #1 : 07 Август 2009, 11:56:26 »

Сайт внутри EXE файла
В этой статье мы рассмотрим как хранить HTML страницы и входящие в него картинки в вашем проекте. В конечном итоге мы получим один исполнимый файл содержащий HTML страницу
Шаг первый - создание HTML страницы.

Для начала мы создадим две простеньких HTML страницы. Для их создания вы можете воспользоваться вашим любимым HTML редактором. Создайте одну страницу с одним рисунком и ссылкой на другую страницу. Я назову свои delphiandprogramming.html и page2.html. Когда вы добавите картинку в страницу, то редактор напишет что-то вроде:
<img ... src="pics/delphiandprogramming.jpg">

Но нам нужно поменять в коде HTML значение параметра SRC так чтобы он был равен имени ресурса:
<img src="/JPEG/dpgjpeg" width="67" heught="61">

Вот код моей странички delphiandprogramming.html:
<HTML><HEAD><TITLE>Delhi And Programming Test Resources 3</HTML></HEAD></TITLE>
<a href="/HTML/page2">Look at second page[/url]

Welcome to<a href="http:/delfaq.wallst.ru"> <img src="/JPEG/dogjpeg" width="67"
height="61">![/url]
</BODY></HTML>

И page2.html:
<HTML><HEAD><TITLE>Delhi And Programming Test Resources Page2</HTML></HEAD></TITLE>
AND HERE WE GOES THRU EXE!
</BODY></HTML>
Создание файла ресурсов

Напомню, что для создания файла скрипта вам необходимо:
Создать пустой текстовый файл в директории с проектом
Переименовать его в TestRes3.rc
Написать в нем следующий код:
dpg HTML "delphiandprogramming.html"
page2 HTML "page2.html"
dpgjpeg JPEG "delphiandprogramming.jpg"

Тип ресурса - RT_HTML определенный как ресурс под номером "23", это ресурсный тип по умолчанию для HTML страниц.

Итак, мы создали файл скрипта ресурсов, страницу и связанную с ней картинку. Следующий шаг - откомпилировать скрипт. Для его компиляции, как это было описано во второй части этой серии мы выполним в командной строке следующую команду:
BRCC32 TestRes3.RC

Теперь подключим полученный файл ресурсов в наш проект следующей строчкой:
{$R TestRes3.RES}
Показ страницы в браузере

Когда мы откомпилировали наше приложение, (я его назвал testres3.exe) мы можем просмотреть нашу страничку в браузере, для этого в адресной строке браузера наберите следующий адрес:
res://C:Delphi5ProjectsTestRes3testres3.exe/HTML/dpg

Конечно путь " C:Delphi5ProjectsTestRes3testres3.exe" у вас может отличаться.
Показ страницы в своем приложении

А теперь мы покажем страницу в самом приложении! Разместите на форме компонент TWebBrowser (находится в Delphi 5 на закладке "Internet"). И на создание формы напишите следующий код:
Self.WebBrowser1.Navigate('res://C:Delphi5ProjectsTestRes3testres3.exe/HTML/dpg');

И все! Теперь вы можете отправлять свой сайт не заботясь о том что пользователь не сможет набрать эту хитрую строчку: 'res://C:Delphi5ProjectsTestRes3testres3.exe/HTML/dpg'.
Записан
Nm0n
Гость
« Ответ #2 : 07 Август 2009, 11:57:32 »

Забавное программирование в Delphi
Приведённый здесь материал можно озаглавить не иначе как "Чем заняться программисту, если нечего делать". На самом деле, Delphi настолько интересная среда, что в ней наряду с разработкой серьёзных приложений можно легко увлечься созданием абсолютно бесполезных вещей.

Итак, поехали...
Автоматически нажимающаяся кнопка

Этот компонент представляет из себя кнопку, на которую не надо нажимать, чтобы получить событие OnClick. Достаточно переместить курсор мышки на кнопку. При создании такого компонента традиционным способом, требуется довольно много времени, так как необходимо обрабатывать мышку, перехватывать её и т.д. Однако результат стоит того!

Предлагаю взглянуть на две версии данного компонента. В более простой версии обработчик перемещения мышки просто перехватывает сообщения Windows с нужным кодом и вызывает обработчик события OnClick:
type
  TAutoButton1 = class(TButton)
  private
    procedure WmMouseMove (var Msg: TMessage);
      message wm_MouseMove;
  end;

procedure TAutoButton1.WmMouseMove (var Msg: TMessage);
begin
  inherited;
  if Assigned (OnClick) then
    OnClick (self);
end;

Вторая версии имеет больше исходного кода, так как в ней я просто пытаюсь повторить событие мышки OnClick когда пользователь перемещает мышку над кнопкой либо по истечении определённого времени. Далее следует объявление класса:
type
  TAutoKind = (akTime, akMovement, akBoth);

  TAutoButton2 = class(TButton)
  private
    FAutoKind: TAutoKind;
    FMovements: Integer;
    FSeconds: Integer;
    // really private
    CurrMov: Integer;
    Capture: Boolean;
    MyTimer: TTimer;
    procedure EndCapture;
    // обработчики сообщений
    procedure WmMouseMove (var Msg: TWMMouse);
      message wm_MouseMove;
    procedure TimerProc (Sender: TObject);
    procedure WmLBUttonDown (var Msg: TMessage);
      message wm_LBUttonDown;
    procedure WmLButtonUp (var Msg: TMessage);
      message wm_LButtonUp;
  public
    constructor Create (AOwner: TComponent); override;
  published
    property AutoKind: TAutoKind
      read FAutoKind write FAutoKind default akTime;
    property Movements: Integer
      read FMovements write FMovements default 5;
    property Seconds: Integer
      read FSeconds write FSeconds default 10;
  end;

Итак, когда курсор мышки попадает в область кнопки (WmMouseMove), то компонент запускает таймер либо счётчик количества сообщений о перемещении. По истечении определённого времени либо при получении нужного количества сообщений о перемещении, компонент эмулирует событие нажатия кнопкой.
procedure TAutoButton2.WmMouseMove (var Msg: TWMMouse);
begin
  inherited;
  if not Capture then
  begin
    SetCapture (Handle);
    Capture := True;
    CurrMov := 0;
    if FAutoKind <> akMovement then
    begin
      MyTimer := TTimer.Create (Parent);
      if FSeconds <> 0 then
        MyTimer.Interval := 3000
      else
        MyTimer.Interval := FSeconds * 1000;
      MyTimer.OnTimer := TimerProc;
      MyTimer.Enabled := True;
    end;
  end
  else // захватываем
  begin
    if (Msg.XPos > 0) and (Msg.XPos < Width)
      and (Msg.YPos > 0) and (Msg.YPos < Height) then
    begin
      // если мы подсчитываем кол-во движений...
      if FAutoKind <> akTime then
      begin
        Inc (CurrMov);
        if CurrMov >= FMovements then
        begin
          if Assigned (OnClick) then
            OnClick (self);
          EndCapture;
        end;
      end;
    end
    else // за пределами... стоп!
      EndCapture;
  end;
end;

procedure TAutoButton2.EndCapture;
begin
  Capture := False;
  ReleaseCapture;
  if Assigned (MyTimer) then
  begin
    MyTimer.Enabled := False;
    MyTimer.Free;
    MyTimer := nil;
  end;
end;

procedure TAutoButton2.TimerProc (Sender: TObject);
begin
  if Assigned (OnClick) then
    OnClick (self);
  EndCapture;
end;

procedure TAutoButton2.WmLBUttonDown (var Msg: TMessage);
begin
  if not Capture then
    inherited;
end;

procedure TAutoButton2.WmLButtonUp (var Msg: TMessage);
begin
  if not Capture then
    inherited;
end;

Как осуществить ввод текста в компоненте Label ?

Многие программисты задавая такой вопрос получают на него стандартный ответ "используй edit box." На самом же деле этот вопрос вполне решаем, хотя лейблы и не основаны на окне и, соответственно не могут получать фокус ввода и, соответственно не могут получать символы, вводимые с клавиатуры. Давайте рассмотрим шаги, которые были предприняты мной для разработки данного компонента.

Первый шаг, это кнопка, которая может отображать вводимый текст:
type
  TInputButton = class(TButton)
  private
    procedure WmChar (var Msg: TWMChar);
      message wm_Char;
  end;

procedure TInputButton.WmChar (var Msg: TWMChar);
var
  Temp: String;
begin
  if Char (Msg.CharCode) = #8 then
  begin
    Temp := Caption;
    Delete (Temp, Length (Temp), 1);
    Caption := Temp;
  end
  else
    Caption := Caption + Char (Msg.CharCode);
end;

С меткой (label) дела обстоят немного сложнее, так как прийдётся создать некоторые ухищрения, чтобы обойти её внутреннюю структуру. Впринципе, проблему можно решить созданием других скрытых компонент (кстати, тот же edit box). Итак, посмотрим на объявление класса:
type
  TInputLabel = class (TLabel)
  private
    MyEdit: TEdit;
    procedure WMLButtonDown (var Msg: TMessage);
      message wm_LButtonDown;
  protected
    procedure EditChange (Sender: TObject);
    procedure EditExit (Sender: TObject);
  public
    constructor Create (AOwner: TComponent); override;
  end;

Когда метка (label) создана, то она в свою очередь создаёт edit box и устанавливает несколько обработчиков событий для него. Фактически, если пользователь кликает по метке, то фокус перемещается на (невидимый) edit box, и мы используем его события для обновления метки. Обратите внимание на ту часть кода, которая подражает фокусу для метки (рисует прямоугольничек), основанная на API функции DrawFocusRect:
constructor TInputLabel.Create (AOwner: TComponent);
begin
  inherited Create (AOwner);

  MyEdit := TEdit.Create (AOwner);
  MyEdit.Parent := AOwner as TForm;
  MyEdit.Width := 0;
  MyEdit.Height := 0;
  MyEdit.TabStop := False;
  MyEdit.OnChange := EditChange;
  MyEdit.OnExit := EditExit;
end;

procedure TInputLabel.WMLButtonDown (var Msg: TMessage);
begin
  MyEdit.SetFocus;
  MyEdit.Text := Caption;
  (Owner as TForm).Canvas.DrawFocusRect (BoundsRect);
end;

procedure TInputLabel.EditChange (Sender: TObject);
begin
  Caption := MyEdit.Text;
  Invalidate;
  Update;
  (Owner as TForm).Canvas.DrawFocusRect (BoundsRect);
end;

procedure TInputLabel.EditExit (Sender: TObject);
begin
  (Owner as TForm).Invalidate;
end;

Кнопка со звуком

Когда Вы нажимаете на кнопку, то видите трёхмерный эффект нажатия. А как же насчёт четвёртого измерения, например звука ? Ну тогда нам понадобится звук для нажатия и звук для отпускания кнопки. Если есть желание, то можно добавить даже речевую подсказку, однако не будем сильно углубляться.

Компонент звуковой кнопки имеет два новых свойства:
type
  TDdhSoundButton = class(TButton)
  private
    FSoundUp, FSoundDown: string;
  protected
    procedure MouseDown(Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer); override;
  published
    property SoundUp: string
      read FSoundUp write FSoundUp;
    property SoundDown: string
      read FSoundDown write FSoundDown;
  end;

Звуки будут проигрываться при нажатии и отпускании кнопки:
procedure TDdhSoundButton.MouseDown(
  Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  PlaySound (PChar (FSoundDown), 0, snd_Async);
end;

procedure TDdhSoundButton.MouseUp(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  PlaySound (PChar (FSoundUp), 0, snd_Async);
end;

Экранный вирус

Никогда не видели экранного вируса? Представьте, что Ваш экран заболел и покрылся красными пятнами :) А если эта болезнь нападёт на какое-нибудь окно ? Всё, что нам надо, это получить контекст устройства при помощи API функции GetWindowDC и рисовать, что душе угодно.

К исходному коду особых комментариев не требуется, скажу лишь только то, что основная часть кода находится в обработчике события OnTimer:
type
  TScreenVirus = class(TComponent)
  private
    FTimer: TTimer;
    FInterval: Cardinal;
    FColor: TColor;
    FRadius: Integer;
  protected
    procedure OnTimer (Sender: TObject);
    procedure SetInterval (Value: Cardinal);
  public
    constructor Create (AOwner: TComponent); override;
    procedure StartInfection;
  published
    property Interval: Cardinal
      read FInterval write SetInterval;
    property Color: TColor
      read FColor write FColor default clRed;
    property Radius: Integer
      read FRadius write FRadius default 10;
  end;

constructor TScreenVirus.Create (AOwner: TComponent);
begin
  inherited Create (AOwner);
  FTimer := TTimer.Create (Owner);
  FInterval := FTimer.Interval;
  FTimer.Enabled := False;
  FTimer.OnTimer := OnTimer;
  FColor := clRed;
  FRadius := 10;
end;

procedure TScreenVirus.StartInfection;
begin
  if Assigned (FTimer) then
    FTimer.Enabled := True;
end;

procedure TScreenVirus.SetInterval (Value: Cardinal);
begin
  if Value <> FInterval then
  begin
    FInterval := Value;
    FTimer.Interval := Interval;
  end;
end;

procedure TScreenVirus.OnTimer (Sender: TObject);
var
  hdcDesk: THandle;
  Brush: TBrush;
  X, Y: Integer;
begin
  hdcDesk := GetWindowDC (GetDesktopWindow);
  Brush := TBrush.Create;
  Brush.Color := FColor;
  SelectObject (hdcDesk, Brush.Handle);
  X := Random (Screen.Width);
  Y := Random (Screen.Height);
  Ellipse (hdcDesk, X - FRadius, Y - FRadius,
    X + FRadius, Y + FRadius);
  ReleaseDC (hdcDesk, GetDesktopWindow);
  Brush.Free;
end;

Шутки над пользователем

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

В приведённом ниже примере при помощи обычного диалогового окна пользователю показывается сообщение об ошибке, причём кнопка "close" накак не хочет нажиматься. У этого диалога есть зависимое окно, которое показывается, при нажатии кнопки "details".

Поддельная форма с сообщением об ошибке имеет кнопку "details", которая открывает вторую часть формы. Это достигается путём добавления компонента за пределы самой формы:
object Form2: TForm2
  AutoScroll = False
  Caption = 'Error'
  ClientHeight = 93
  ClientWidth = 320
  OnShow = FormShow
  object Label1: TLabel
    Left = 56
    Top = 16
    Width = 172
    Height = 65
    AutoSize = False
    Caption =
      'Программа выполнила недопустимую ' +
     'операцию. Если проблема повторится, ' +
      'то обратитесь к разработчику программного обеспечения.'
    WordWrap = True
  end
  object Image1: TImage
    Left = 8
    Top = 16
    Width = 41
    Height = 41
    Picture.Data = {...}
  end
  object Button1: TButton
    Left = 240
    Top = 16
    Width = 75
    Height = 25
    Caption = 'Close'
    TabOrder = 0
    OnClick = Button1Click
  end
  object Button2: TButton
    Left = 240
    Top = 56
    Width = 75
    Height = 25
    Caption = 'Details >>'
    TabOrder = 1
    OnClick = Button2Click
  end
  object Memo1: TMemo // за пределами формы!
    Left = 24
    Top = 104
    Width = 265
    Height = 89
    Color = clBtnFace
    Lines.Strings = (
      'AX:BX    73A5:495B'
      'SX:PK    676F:FFFF'
      'OH:OH   7645:2347'
      'Crash    3485:9874'
      ''
      'What'#39's going on here?')
    TabOrder = 2
  end
end

Когда пользователь нажимает кнопку "details", то программа просто изменяет размер формы:
procedure TForm2.Button2Click(Sender: TObject);
begin
  Height := 231;
end;

Вторая форма, которая наследуется от первой имеет перемещающуюся кнопку "close":
procedure TForm3.Button1Click(Sender: TObject);
begin
  Button1.Left := Random (ClientWidth - Button1.Width);
  Button1.Top := Random (ClientHeight - Button1.Height);
end;

В заключении, можно сделать дырку в окне, используя API функцию SetWindowRgn:
procedure TForm1.Button4Click(Sender: TObject);
var
  HRegion1, Hreg2, Hreg3: THandle;
  Col: TColor;
begin
  ShowMessage ('Ready for a real crash?');
  Col := Color;
  Color := clRed;
  PlaySound ('boom.wav', 0, snd_sync);
  HRegion1 := CreatePolygonRgn (Pts,
    sizeof (Pts) div 8,
    nate);
  SetWindowRgn (
    Handle, HRegion1, True);
  ShowMessage ('Now, what have you done?');
  Color := Col;
  ShowMessage ('Вам лучше купить новый монитор');
end;
Записан
Nm0n
Гость
« Ответ #3 : 07 Август 2009, 11:58:28 »

Защита программ от взлома
Эта статья посвящена достаточно актуальной в настоящее время тематике - защите программ от взлома и нелегального копирования. Этой теме посвящено много статей, одна из наиболее интересных (из тех, которые попались мне) - статья "Защита shareware-программ" Владимира Каталова в Компьютерре Online#240. Он привел ряд советов по написанию shareware программ и я не хочу повторяться - сходите, почитайте.

Рассмотрим некоторые тонкости организации защиты на достаточно популярном примере - предполагаем, что программа защищена некоторым кодом (серийным номером, паролем), который сообщается пользователю после соблюдения им определенных условий. До регистрации в этой программе заблокирован ряд каких либо полезных функций, используется надоедливая реклама или ограничен строк работы. После ввода этого кода производится его проверка и при положительном исходе проверки программа начинает нормально работать. По неизвестной мне причине в большинстве современных программ данная защита сделана однообразно и для ее снятия необходимо 10-15 минут. В этой статье я постараюсь поделиться опытом в построении систем защиты. Могу сразу предупредить - хорошему хакеру противостоять практически бесполезно, да и не нужно - при желании любая защита может быть взломана, это вопрос времени.

Инструментарий хакера. Современный хакер имеет в своем арсенале набор разнообразных утилит для взлома. Их можно подразделить на несколько категорий
Отладчики. Позволяют прерывать выполнение программы при достижении заранее заданных условий, производить пошаговое выполнение программы, изменять содержимое памяти и регистров и т.п. . Наиболее популярным, удобным и мощным является отладчик SoftICE, который при достаточно примитивном интерфейсе обладает приличными возможностями и весьма стабильно работает.
Дизассемблеры. Производят дизассемблирование программы для дальнейшего изучения полученного кода. Один из наиболее популярных - IDA. От дизассемблера достаточно легко защититься - зашифровать или заархивировать программу. Тогда дизассемблируется только архиватор или кодировщик.
Средства мониторинга. Это набор утилит, отслеживающих операции с файлами, реестром, портами и сетью.
Средства пассивного анализа программы. Показывают разную информацию о программе - извлекают ресурсы, показывают связи, используемые библиотеки. Классический пример - утилита DEPENDS.EXE из комплекта Visual Studio. Она показывает, какие библиотеки используются программой и какие функции импортируются.
Прочие утилиты. Их великое множество (можно найти на диске типа "Все для хакера", причем в изобилии). Это разнообразные редакторы, анализаторы ...

Наиболее популярны следующие программы мониторинга :

FileMon - утилита, позволяющая вести мониторинг всех операций с файлами. Имеет удобный фильтр, может сохранять отчет в файле. Поэтому нет смысла делать "секретные" файлы где-нибудь в Windows/System - их элементарно найти.

RegMon - аналог FileMon, только ведется мониторинг всех операций с реестром. Аналогично файлам, бессмысленно создавать в реестре "секретные" ключи - они сразу бросаются в глаза.

PortMon - мониторинг работы с портами ввода/вывода

TCP_VIEW - монитор соединений по TCP-IP

RegUtils - набор утилит для контроля за реестром - делает копии реестра, позволяет сравнивать копии и просматривать изменения.

Утилиты типа FileMon могут резко упростить взлом программы - легко определить место, в котором программа обращается к указанному файлу или ключу реестра.

Основы построения защиты - шаг за шагом

Как ввести регистрационный код. Ввод пароля или регистрационного номера является ответственным делом - хакер постарается отловить адрес памяти, в который будет записан пароль. Затем на обращение по этому адресу ставится точка останова (команда BPM в SoftICE), что позволяет поймать начало процедуры проверки регистрационного кода. Если для ввода используются стандартные элементы ввода Windows, то алгоритм действий хакера можно формализовать и выглядит он примерно так:
Устанавливает точку останова на считывание текста из стандартного элемента ввода (функции GetWindowText, GetGlgItemText модуля KERNEL32)
При вызове этой функции анализируем ее параметры и таким образом определяем, по какому адресу будет размещено считываемое значение и ставим обращение к этой области памяти точку останова. А достоверности определенного адреса легко убедиться - после выполнения функции там появится введенная строка
При срабатывании этой точки останова мы попадаем в анализатор введенного значения и либо делаем генератор регистрационных ключей, либо ломаем процедуру проверки. И то, и другое весьма просто сделать - достаточно только изучить ассемблер и API

Набор этих действий стандартен и мне не раз попадались подробные руководства типа "Взлом Windows программ - шаг за шагом", ориентированные на продвинутого пользователя.

Рассмотри несколько решений, которые могут затруднить взлом на этом этапе.

Совет _0. Старайтесь как можно меньше применять стандартные функции (особенно API-шные) и компоненты VCL. Так что Assembler, Assembler и еще раз Assembler ...

Сущность этого совета надеюсь очевидна - современные дизассемблеры умеют распознавать стандартные процедуры высокоуровневых языков, а API - вообще отдельный разговор - SoftICE обладает изумительной возможностью - загружать символьные имена для любых указанных библиотек (особенно для KERNEL32.DLL) - отладка резко упрощается, т.к. мы видим имена вызываемых функций и можем ставить точки останова на вызов функций по их имени.

Совет _1. Применяйте нестандартный способ ввода пароля.

Наипростейший путь - написать свой визуальный компонент для ввода регистрационного кода. Он конечно должен будет обрабатывать события от клавиатуры, но момент считывания кода нельзя поймать избитыми методами. Это уже что-то, но есть второй способ взлома, основанный на поиске введенного кода в памяти. Для этого в SoftICE есть удобная команда "S стартовый адрес L длина 'образец'" , которая позволяет найти введенное значение в памяти.

Совет _2. Не храните введенный код в одном месте !

Совет _3. Не храните введенный код открытым текстом !

Итак, что же следует сделать. Для начала необходимо завести в программе 5-10 переменных типа STRING и после ввода кода переписать введенное значение в них. Делать это лучше всего не в одном месте, а распределить по программе. Таким образом поиск даст кучу адресов, по которым будет находиться введенный код. Я в таком случае поступаю так - по таймеру создаю в динамической памяти новую строковую переменную, пишу в нее код. Затем на следующем срабатывании таймера создаю новую переменную, переписываю в нее код, а старую уничтожаю. При определенном навыке можно заполонить память значениями введенного кода и сделать поиск почти бесполезным. Причем такое копирование можно совместить с проверкой кода или эмуляцией этой проверки. Затем с эти строками неплохо поделать какие-либо операции - сравнить с чем-нибудь ...

Советы 3 и 1 можно объединить - создать свой компонент, который позволит вводить код нестандартным способом с его одновременной шифровкой.

Анализ регистрационного кода. Итак, код введен и приняты меры для того, чтобы его было непросто найти (хотя найти то его можно, но это время, навык ...). Теперь следующий шаг - анализ. Поэтому сразу совет:

Совет _4. Ни в коем случае не анализируйте код сразу после его ввода.

Чем дальше ввод кода от его анализа, тем лучше. Самое разумное - после ввода кода поблагодарить пользователя за сотрудничество и сообщить, что со временем будет выполнена регистрация программы. А анализ кода произвести, например, через 1-2 минуты в совершенно другом месте программы.

Совет _5. Не проверяйте код только в одном месте и не пишите для проверки функцию.

Достаточно найти и отключить эту проверку, и защита взломана. Если проверок несколько, они разные и распределены по программе, то взлом затрудняется.

Совет _6. Не проверяйте пароль одним алгоритмом.

Рекомендуется разработать 2-3 алгоритма проверки, например 1-2 цифры должны делиться на 3, а 3-7 наложенные по какому-либо алгоритму на имя пользователя должны дать в сумме 4. Эти две проверки осуществляем в различных местах с достаточно большим временным разносом - взломав первый метод хакер не будет догадываться о существовании еще нескольких, которые проявятся со временем.

Совет _7. Ни в коем случае не предпринимайте никаких действий после проверки. По неизвестной причине большинство программ выглядят примерно так
IF NOT(SuperRegCodeCheck) then
 Begin
  ShowMessage('Неверный код, дальнейшая работа невозможна');
  halt;
 end;

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

Совет _8. Отвлекающие маневры.

Кроме реальных функций проверки кода очень неплохо сделать пару бутафорских - они будут вызываться после ввода кода, проводить активные манипуляции с введенным значением, выдавать сообщения о некорректности введенного кода ... - т.е. отвлекать внимание от реальной проверки.

Совет _9. Не храните результатов проверки в переменной и не используйте ее для явного ограничения функций незарегистрированной программы.

Классический пример нарушения этого правила
IF NOT(LegalCopy) then
 ShowMessage('Сохранение работает только в зарегистрированной версии')
else
 SaveFile;

Таким образом элементарный анализ показывает, что переменная LegalCopy хранит результат проверки и поставив на нее точку останова можно выловить саму проверку. Отредактировав это значения в памяти можно временно сделать копию "зарегистрированной",а установка точки останова на изменение этой переменной выведет на место ее проверки. Да и взлом сводится к тому, что функция проверки кода урезается до двух команд ассемблера:
 MOV [адрес LegalCopy], 1
 RET

Совет _10. (вытекает из 9) Не храните результатов проверки на диске или в реестре.

Типичная ошибка - выяснили, что копия зарегистрирована и сделали где-нибудь метку. Отловить это достаточно просто (см. описание REGMON и FILEMON). Наилучший способ - сохранить пароль и имя пользователя в том виде, в котором он их ввел. Затем при каждом запуске программы проверять корректность этого кода, но не забывая Совет _11. Ничего не проверяйте сразу при запуске приложения или сразу после считывания сохраненного имени или кода. Помните, что считывание кода и его ввод в окне регистрации идентичны по мерам защиты - дублирование в разных областях памяти, шифрование ...

Выводы: мы устроим проверку кода в нескольких местах программы, при этом применим несколько алгоритмов проверки, не будем использовать API.Кроме того, стоит проделать несколько отвлекающих маневров.

Общие советы по защите программ
CRC - контрольные суммы. Любой файл, строку или блок данных можно защитить контрольной суммой, которую затем можно рассчитать и сравнить с эталоном. При сравнении с эталоном конечно следует весть осторожно - см. первые 11 советов. Итак, совет 12. Защищайте программы и данные контрольными суммами. Это поможет не только от взлома, но и защитит программы от вируса или внедрения троянца.
Применяйте шифровку программ и данных. Очень неплохо сжать программу и данные. Я, например, разработал свой собственный архиватор - RAR-у и ZIP-у он конкуренции не составит, но сжатые им данные разжать очень непросто, придется изрядно повозиться. Да и изменить их проблематично - придется разжать, изменить и сжать.
Отлов пошаговой отладки программы. Существует много способов, я в свое время провел целое исследование этого вопроса под DOS, насобирал и придумал не менее 20 методов, но они мало приемлемы под Windows. Самый простой и надежный способ - таймер. При работе программы периодически фиксируем системное время и рассчитываем время работы фрагментов кода между ними. И если 200-400 команд процессора работают 2-3 минуты, то тут есть над чем задуматься.
Совет 13. Не определяйте дату и время стандартными способом !! Придумайте что-нибудь оригинальное.

Совет 14.Не стоит хранить что-либо секретное в файлах или реестре. Работа с файлами или реестром может быть детально запротоколирована и проанализирована, и все тайное станет явным.

Совет 15.Не храните ничего важного открытым текстом, особенно сообщения типа "Это незарегистрированная версия ...", "Введенный пароль не верен ...".
Они для хакера - как для быка красная тряпка, и действительно - находим такое сообщение, ставим точку останова на обращение к участку памяти с этим сообщением и получаем возможность поймать момент выдачи этого сообщения.

Советы по созданию меток для организации ограничения по времени

Защита "ограничение времени работы" состоит в том, что программа каким образом фиксирует момент своего первого запуска и работает установленное время (обычно 20-30 дней). После истечения этого срока программа отказывается запускаться. Как проверить текущую дату я уже где-то тут писал - нестандартным способом, например по дате на файлах реестра или свежесозданном своем файле. Весь фокус в другом - как зафиксировать на компьютере дату первого запуска (естественно так, чтобы изничтожение программы и ее повторная установка не давали эффекта). Использование "секретных" файлов в системных папках или изменения в существующих файлах легко отловить при помощи FILEMON. Реестр то же отпадает из-за REGMON. Прочие методы (типа записи в ВООТ сектор ...) тоже неприемлемы - не те времена, по Windows все это не пройдет. Наиболее оригинально (на мой взгляд) прошить дату в саму программу и постоянно обновлять ее на своем сайте (естественно, автоматически). Таким образом отсчет неявно идет от момента скачивания программы с сайта. Есть тут правда и минус - после завершения срока можно повторно скачать эту программу и получить еще 15-20 дней ... . С другой стороны это оригинально - пользователю рано или поздно надоест скачивать эту программу и он или откажется от нее, или купит. Но при этом стоит помнить, что программу можно скачать несколько раз и сравнить варианты, выявив, где лежит дата. Поэтому стоит позаботиться о том, чтобы изменился почти весь файл (например, изменить пару опций компилятора)

Советы по формированию регистрационных кодов

Формирование кодов может вестись по следующим основным направлениям:
Жестко фиксированные коды, прошитые в программу. Их обычно немного и их огласка сводит защиту к нулю.
Некий алгоритм проверки кода. Немного лучше первого, но лишь немного. Возьмите за пример код Windows - его знает любой пользователь
Алгоритм проверки кода, использующий имя пользователя. Очевидно, что для каждого имени будет уникальный номер (или номера - их может быть несколько, в зависимости от алгоритма). Это уже лучше, но нелегальное распространение держится на эгоизме зарегистрированных пользователей - ничто не мешает им предать имя/пароль огласке, но тогда хотя бы можно вычислить виновника и заблокировать его код
Алгоритм проверки кода, использующий имя пользователя и некоторые уникальные или динамически изменяющиеся параметры, например информацию о компьютере. Это надежно, дает привязку к компьютеру, но в наш век постоянных апгрейдов очень неудобен.
On-Line регистрация. Состоит в том, что программа в On-Line связывается с сайтом разработчиков (или компании, осуществляющей продужу софта) и передает туда ревизиты пользователя. В ответ программе передается регистрационная информация. Этот метод может и хорош для ряда программ, но на мой взгляд не выдерживает никакой критики по двум соображениям:
1. Никто не может гарантировать, что конкретно передаст программа в Инет. А передать она может все, что угодно - параметры компьютера, пароли, любые данные и т.п.
2. Конкретный пользователь ножет не иметь доступа к Инет. Это особенно важно для программ, работа которых не связана напрямую с Сетью. И зарегистрировать такую программу его практически никто к себе на компьютер не пустит (из соображений п.п. 1)

Рекомендовать тут что-либо бесполезно, но я например использую разновидности метода 3.
Записан
Nm0n
Гость
« Ответ #4 : 07 Август 2009, 12:00:35 »

Какова роль классов и объектов Delphi
Не секрет, что роль классов и объектов при создании программ Delphi велика, но для того, чтобы убедиться в этом, необходимо рассмотреть более подробно сами эти понятия. Библиотека классов широко используется для реализации интерфейса.
Именно классы позволяют поддерживать форму, которая содержит не только кнопки, но и иные элементы оформления. Приложение Delphi осуществляет в процессе проектирования оформления все необходимые добавления в автоматическом режиме. Все это в свою очередь фиксируется в окне редактора. Там можно найти как описание пустой формы, так и указания на внесение изменений.
Не секрет, что роль классов и объектов при создании программ Delphi велика, но для того, чтобы убедиться в этом, необходимо рассмотреть более подробно сами эти понятия. Библиотека классов широко используется для реализации интерфейса.
Именно классы позволяют поддерживать форму, которая содержит не только кнопки, но и иные элементы оформления. Приложение Delphi осуществляет в процессе проектирования оформления все необходимые добавления в автоматическом режиме. Все это в свою очередь фиксируется в окне редактора. Там можно найти как описание пустой формы, так и указания на внесение изменений.
При внесении изменений в процессе создания формы программисту не приходится создавать описания класса, это делает за него Delphi.
В библиотеке классов можно найти не только видимые компоненты, которые можно оценить визуальным путем. Здесь так же размещены совершенно не воспринимаемые зрительно компоненты, которые не только помогают создавать те или иные объекты, но и обеспечивают наличие доступа к ним в целях определения свойств, параметров.
Так в качестве такого, не воспринимаемого взором, компонента может выступать таймер, а так же основные элементы, позволяющие вести управление базами данных.
В языке Delphi понятию класса отводится значимая роль. Так класс является не только сложно структурой, он содержит в себе различные описания от структур до процедур и функций. В свою очередь функции класса именуются методами, а вот данные принято именовать полями.
Вначале указывается имя класса, например «TPerson= class», далее следует описание имен полей, например «fname: string[16]; faddress: string[36]», и только потом указывается имя метода.
В языке Delphi принято всегда при указании имен полей в начале слова ставить букву «f». А вот описание класса необходимо разместить в особом разделе, который служит для описания типов.
То, что классы в Delphi важны – это неопровержимо, но какова роль объектов в этом языке.



Для того, чтобы заявить об объекте, необходимо использовать при написании программы раздел var. Именно он позволяет заявить об объекте как о представителе класса.
Объект в этом языке является изменяемым и описывается как переменная. Притом сам объект данные содержать не может, но может указать ссылку на место хранения таковых. В свою очередь появляется необходимость в выделении памяти, способной обеспечить хранения данных, на которые и будет ссылаться объект.
В целях выделения памяти используется конструктор. Конструктор при этом является представителем метода класса. Как правило, конструктор именуется «constructor Create», а записывается строкой «constructor Cireate; // конструктор».
Но каким образом обеспечивается выделение места для хранения данных? Для этого происходят преобразования конструктора. Значение присваивается к типу объекта при помощи конструктора.
Более того после того, как место для хранения данных определено происходит указание начальных значений, что иначе именуется, как «инициализация объекта».
Сам конструктор имеет несколько отличительных черт. Так в его толе нет часто встречающихся инструкций, которые призваны проводить работу по выделению памяти. Притом конструктор не производит возвращение значений в процессе обращения к нему, как к методу.
Стоит вернуться к тому, что любому объекту необходима инициализация. Для ее осуществления достаточно установить само значение поле объекта. Для этого необходимо осуществить доступ к полю.
Осуществление такого доступа производится путем указания, как имени самого объекта, так и имени его поля, при их разделении знаком «.» в написании.
Выше уже было сказано, что любой сам объект подразумевает наличие ссылки, но вот в конце его имени не нужно помещать знак верхнего индекса, как его принято ставить после указания имени переменной.
В качестве примера для составления описания объекта «professor» к полю «fname» недопустимо писать «professor*.fname», знак «*» не стоит употреблять.
Как известно, именно такой доступ более предпочтителен. Для того, чтобы экономно использовать ресурсы памяти при необходимости производят удаление полей не употребляемого объекта.
С этой целью применяется не конструктор, а деструктор, который так же является методом и именуется как «Free». Он освобождает память от ненужной или лишней информации объекта, именуемого как «profess» при составлении строки записи «profess.Free».
При рассмотрении классов и объектов неминуемо упоминание о методах. Так что же представляет собой метод в языке Delphi? Как известно, существуют методы класса, они включают в себя не только основные функции, но и все необходимые процедуры. Эти процедуры и функции применяются при описании класса.
Не стоит забывать о том, что имя объекта отделено от имени метода точкой. Так строка «profess.Show» реализует применение метода «show» к объекту, именуемому как «profess». Принято считать, что указанное выше применение метода, как и применение метода в любом другом случае представляет собой запись инструкции вызова процедуры.
Записан
Nm0n
Гость
« Ответ #5 : 07 Август 2009, 12:01:12 »

Использование драйвера ASCII, атрибуты описания файла
Драйвер ASCII позволяет передавать информацию о данных ASCII-поля определенной длины, так же он может передавать информацию о файлах с разделительной запятой. Как известно процесс трансляции ASCII файла определяется сопровождающей схемой (Schema File). Файл схемы данных ASCII несет информацию об атрибутах, которые позволяют осуществлять преобразования в значения полей информацию, содержащуюся в файле.
Не является сложным процессом установление полей для файла с ASCII полями, длина которых находится на заранее установленном уровне. Для осуществления этого достаточно определить позиции всех полей, притом необходимо учесть, что эти позиции одинаковы для всех строк.
Драйвер ASCII позволяет передавать информацию о данных ASCII-поля определенной длины, так же он может передавать информацию о файлах с разделительной запятой. Как известно процесс трансляции ASCII файла определяется сопровождающей схемой (Schema File). Файл схемы данных ASCII несет информацию об атрибутах, которые позволяют осуществлять преобразования в значения полей информацию, содержащуюся в файле.
Не является сложным процессом установление полей для файла с ASCII полями, длина которых находится на заранее установленном уровне. Для осуществления этого достаточно определить позиции всех полей, притом необходимо учесть, что эти позиции одинаковы для всех строк.
Появляются некоторые сложности только при ведении работы связанной с использованием файлов с разделительной запятой. Проблематичность заключена в том, что данные такого файла не имеют одинаковой длины во всех строках. Поэтому работа, связанная с ними, и требует более детального изучения.
Поля файла не являются чувствительными к регистру, это необходимо учитывать при выборе названия, так написание названия «CAW» и «caw» являются тождественными. Следует учесть и тот момент, что то имя, которое содержит файл данных ASCII, должен иметь файл схемы при указании соответствующего расширения SCH.
Так атрибуты описания файла должны включать File name, Filetype, Delimiter, Separator, CharSet, которые необходимо рассмотреть более подробно. Так File name – это имя файла, оно помещается в квадратные скобки, резширение указывается «TXT».



Далее следует рассмотреть Filetype или тип файла, с помощью которого можно определить, присутствует ли в файле данных структура с полями различной длины.



Атрибуты Delimiter и Separator являются определителями символов, которые разделяют отдельные значения данных. Такие атрибуты состоят из видимых символов и имеют десятичный код. Атрибут же CharSet является определителем языкового драйвера.
Определители поля, которые размещены дальше, чем атрибуты файла, становятся определяющими правил строк данных ASCII. Они становятся прекрасным источником информации для программ Delphi, а так же для BDE. Эта информация участвует в создании виртуального поля, она помогает хранить данные. Только после ого, как будет прочтена информация из ASCII файла, устанавливается тип данных поля.
Так же необходимо выделить несколько атрибутов, которые становятся определяющими для файла данных ASCII, к ним относятся Field, Field name, Field type, Data value length, Offset, Number of decimals.
Как известно, виртуальное поле должно иметь имя, этим именем становится Field, оно сопровождается порядковым номером в виде целого числа, то есть выглядит как Field5, Field6,… Field10 и так далее. Имя поля или Field name размещается как заголовок колонки.
Атрибут Field type, как это видно из названия определяет тип файла или иначе – тип данных BDE. Данный атрибут необходим для осуществления передачи значений. Атрибут Data value length является определяющей длины поля виртуального типа. Приложением поля FLOAT, определяющим общее число цифр становится атрибут Number of decimals.
Атрибут Offset должен быть задан для всех строк без исключения, он определяет позицию или наличие отступа, что необходимо при оформлении строки.
Так в качестве примера для рассмотрения небольшой схемы с тремя полями можно использовать такую схему, где первое поле типа String, а вот второе и третье имеет тип Date. Все данные вышеприведенной схемы должны быть помещены в файле DATES.SCH. Они делают возможным процесс определения полей.

Выглядеть такая запись будет как:
Field1=Text,Char,5,00,00
Field3=Second,Date,9,00,13
Field2=First Contact,Date,11,00,03

В качестве наглядного примера можно использовать чтение строки: Field1=Text,Char,5,00,00. Так наименование «Text» становится определителем типа данных, число 5 показывает, что максимальная длина значения данных не может превышать пяти символов. А такая запись, как Char гласит, что данное поле имеет тип character, не имеет никакого определения десятичного порядка, а так же без отступа строки.
При анализе записи Field2=First Contact,Date,11,00,03 можно установить, что длина этого поля данных составляет 11, десятичный порядок не определен, а вот отступ в данном случае равен 3.
Третье поле задано строкой Field3=Second,Date,9,00,13, оно соответственно имеет длину 9, не имеет определение десятичного порядка, а его отступ равен 13.
Не стоит забывать о таком важном моменте, что параметр длины указывает максимальное значение, при этом не происходит учета кавычек или разделителей. Вот только при оценке значений String возникает больше проблем и затруднений.
Записан
Nm0n
Гость
« Ответ #6 : 07 Август 2009, 12:01:54 »

В чем заключается инкапсуляция объектов
Прежде чем рассмотреть инкапсуляцию объектов необходимо установить то, что представляет сам объект в языке Delphi. Объект в этом языке задается как представитель класса, он не содержит данных в самом себе, но точно указывает на ту ссылку, где эти данные находятся.
В свою очередь необходимо хранить данные в отдельном специально отведенном для этих целей месте. Для выделения памяти применяется специальный конструктор.
Прежде чем рассмотреть инкапсуляцию объектов необходимо установить то, что представляет сам объект в языке Delphi. Объект в этом языке задается как представитель класса, он не содержит данных в самом себе, но точно указывает на ту ссылку, где эти данные находятся.
В свою очередь необходимо хранить данные в отдельном специально отведенном для этих целей месте. Для выделения памяти применяется специальный конструктор.
При необходимости можно произвести удаление всех данных об одном, более не используемом объекте при написании командной строки с содержанием указания «Free», где указывается имя неиспользуемого объекта, а через точку пишется само название «Free».
Иногда появляется необходимость осуществления скрытия объектов таким образом, чтобы возможно было осуществлять к ним доступ при помощи методов класса. Именно это и подразумевает под собой такое понятие, как инкапсуляция.
Судя из того, что в Delphi ограничение доступа к объекту можно осуществить только через изменение параметров его свойств, можно сделать вывод, что инкапсуляция имеет прямую связь со свойствами объекта. Проводя анализ далее, можно заметить, что характеризуют эти интересующие нас свойства поля объекта.
Поле хранит значения свойства, а вот методы и обеспечивают процесс доступа уже не к объекту, а только к полю. Особый вид методов, которые призваны устанавливать значение свойства, именуются «write». Судя из названия, можно установить, что они обеспечивают процесс записи свойства. Соответственно должен существовать метод, который должен читать эти записи, такой метод есть, и он именуется «read».
Именно при помощи метода чтения и становится возможным воспринимать занесенные записи свойств в поле объекта.
Теперь более подробно стоит поговорить об оформлении строки описания класса. Так непосредственно перед указанием имени свойства ставят «property», что в переводе и будет означать не что иное, как «свойство». Далее указывается тип, а только после этого ставится имя метода, который призван поддерживать доступ к значению property.
Если упомянуто в строке «read», то далее необходимо поставить имя того метода, который сделает возможным осуществление чтение свойства. То же самое относится и к упоминанию в строке «write», тогда нужно указать имя метода, призванного обеспечить запись свойства.
Особые требования предъявляются к программе, способной устанавливать значения свойств. Она не должна содержать в себе инструкцию по ее взаимодействию с объектом метода определения искомого значения. Для того, чтобы выше рассмотренный нюанс был более понятен, необходимо рассмотреть пример.
Предположим, что нам требуется присвоить такое свойство, как «Name» объекта именуемого «pupil». Для этого необходимо сделать запись «pupil. Name := 'Адриан';». Как видно из записи, присвоение осуществляется достаточно легко, что важно и для запоминания.
Далее при помощи компилятора осуществляется перетрансляция данного описания, из которого уже происходит формирование инструкции необходимой для присвоения значения. Таким образом, происходит обращение к инструкции метода и ее вызов.



В действительности поле объекта имеет множество отличий от свойств объекта, притом принципиальных. Вот только внешне это практически не проявляется, и от того не всеми установлено. Вот, например процесс чтения и присвоения всегда приводит к выполнению процедуры, обеспечивающей осуществления данного процесса. Сама процедура запускается в автоматическом режиме, чтобы обеспечить выполнение работы.
При написании программы широко используются как свойства, так и методы. На них кроме обычных задач полагаются и дополнительные, более сложные для выполнения.
Так, например, совсем непросто при помощи метода осуществлять процесс проверки того, насколько корректны значения, которые присваиваются тому или иному свойству. Бывает, что появляется необходимость установить наличие логической связи или осуществить автоматизированный вызов дополнительной процедуры. Все это, а так же установление значений иных полей выполняют различные варианты методов.
Далее необходимо рассмотреть более подробно само оформление данных объекта, которое играет немаловажную роль. Вот, например, осуществить ограничение доступа к полям, которые содержат в себе важные значения, можно именно при помощи свойств объекта. Так указание одного только имени метода чтения при создании описания позволяет оставить значения свойств объекта без изменения со стороны инструкций программ. Такая небольшая деталь важна, и о ней необходимо помнить.
А вот при попытке все же присвоить значение тому свойству, которое может только быть прочитано, неминуемо приведет к появлению ошибки.
Записан
Nm0n
Гость
« Ответ #7 : 07 Август 2009, 12:02:33 »

Грамотная работа с массивами данных
Массивы, как необходимость часто встречается при проведении работ, поэтому всем нужно иметь хотя бы общее представление о массивах. Массив является не просто дополнительным элементом, а элементом способным расширить обычные возможности программы. Конечно, каждый массив должен быть включен в программу.
Так массив, прежде чем ввести в программу, нужно объявить. Объявление происходит в том разделе, который специально отведен для объявления переменных. Процесс объявления массива несложен, но требует более подробного рассмотрения.
Массивы, как необходимость часто встречается при проведении работ, поэтому всем нужно иметь хотя бы общее представление о массивах. Массив является не просто дополнительным элементом, а элементом способным расширить обычные возможности программы. Конечно, каждый массив должен быть включен в программу.
Так массив, прежде чем ввести в программу, нужно объявить. Объявление происходит в том разделе, который специально отведен для объявления переменных. Процесс объявления массива несложен, но требует более подробного рассмотрения.
Можно даже назвать это описание инструкцией объявления. Так сначала указывается имя массива (в примере оно казано в общем как «Имя»), далее идут индексы и тип: «Имя: array [нижний_индекс. .верхний_индекс] of тип». Слово «array» написано на языке Delphi, именно оно позволяет программе понять, что мы описываем массив при указании его имени.
При указании как нижнего, так и верхнего индексов не стоит забывать о том, что они должны быть только целыми, а не дробными числовыми значениями. Эти числа определяют диапазон, в пределе которого осуществляется изменение элементов. Так же переменные, в общем, определяют размер массива или иначе – число входящих в его состав элементов. Далее, как было сказано, указывается тип, соответственно элементов массива.
Ниже приведены несколько примеров объявления массивов:



Как правило, при объявлении массива применяются исключительно именованные константы. Эти константы так же необходимо объявить в уже упомянутом разделе объявления констант. Этот раздел чаще всего расположен до раздела служащего для объявления переменных. Именно такое размещение является максимально удобным при написании программ. Оно позволяет быстро ориентироваться как в константах, так и в переменных. А это в свою очередь ускоряет процесс работы.
Раздел, в котором объявляются константы, начинается со слова «const», само название которого указывает на назначение раздела. При объявлении в первую очередь нужно указать имя константы, а затем, после знака «=» привести ее значение. В итоге получится примерно такая запись для указания числа игроков команды и их имен:

const
NG = 30; // число игроков
SN = 25; // предельная длина имени игроков var
team: array[1..NG] of string[SN];

Не стоит забывать о том, что использовать как константу, так и переменную можно только после ее объявления и описания. После того, как именованная константа объявлена и ей задано значения, то она может использоваться в качестве числовой константы или символьного постоянного значения.
Далее рассматривая обозначение массива, необходимо упомянуть о том, что еще перед использованием массива указывается его имя и индекс особым образом. Так индекс, иначе называемый номером элемента, пишется в квадратных скобках. При выборе индекса можно применять не только константы, но и целые выражения, только обязательно целого типа.
В качестве примера можно использовать название команды «Локомотив». Запись первой строки будет иметь следующий вид «team [ 1] := ' Локомотив '». В данном случае было использовано выражение целого типа.
Более сложным является метод инициализации массива. Он применяется в тех случаях, когда массив не является константой, а объявляется в форме переменной. В этом случае массив нельзя назвать неизменным. Он объявляется при непосредственной обработке данных в развитии событий. Массив, как переменная задается в таком случае в разделе для объявления переменных модуля, ему только присваивается начальное значение.
Вот так, примерно обрисовывается процесс инициализации или иначе процесс объявления массива «Имя:array[нижний_индекс..верхний_индекс]of тип = (список)». Стоит пояснить, что слово «список» подразумевает перечисление элементов массива, эти элементы друг от друга отделяются символом «,». В качества примера можно привести строку «a: array[9] of integer = (1,1,1,1,1,1,1,1,1)».
При этом необходимо выполнения соответствия между количеством элементов, которые выглядят в примере, как 9 единиц «1,1,1,1,1,1,1,1,1» и размерности массива, которая равна девяти, судя из записи «array[9]». Если этого не соблюдать, то неминуемо появится сообщение об ошибке «Number of elements differs from declaration», что в переведенной форме говорит о несоответствии.
Пример ярко выраженной ошибки может быть представлен в виде:

for i := 2 to 9 do
a:= 1;

В данном примере количество значений, размещенных в интервале от двух до девяти, не может составлять всего один символ.
После того, как массив объявлен и полностью определен, происходит его дальнейший вывод на экран для визуального восприятия результата.
Записан
Nm0n
Гость
« Ответ #8 : 07 Август 2009, 12:03:07 »

Основные операции, производимые с массивом
При помощи массива совершается обработка определенного интервала чисел или набора данных. Количество чисел или данных напрямую зависит от размера массива. Прежде чем ввести в программу массив, его необходимо обозначить. Только после того, как обозначение совершено происходит вывод массива.
То насколько грамотно записан массив, становится заметным только после его отображения. Но прежде чем отобразить данные их необходимо ввести. Но как происходит ввод массива и что под этим подразумевается? Самым простым решением в данном случае является создание поля ввода массива для каждого элемента. Это допустимо в тех случаях, когда массив мал и имеет от 5 до 15 элементов, но в тех случаях, когда число элементов превышает 30 или даже 1000, то данный вариант становится совершенно неприемлемым.
При помощи массива совершается обработка определенного интервала чисел или набора данных. Количество чисел или данных напрямую зависит от размера массива. Прежде чем ввести в программу массив, его необходимо обозначить. Только после того, как обозначение совершено происходит вывод массива.
То насколько грамотно записан массив, становится заметным только после его отображения. Но прежде чем отобразить данные их необходимо ввести. Но как происходит ввод массива и что под этим подразумевается? Самым простым решением в данном случае является создание поля ввода массива для каждого элемента. Это допустимо в тех случаях, когда массив мал и имеет от 5 до 15 элементов, но в тех случаях, когда число элементов превышает 30 или даже 1000, то данный вариант становится совершенно неприемлемым.
Так же следует учесть, что любую последовательность чисел удобно задавать не в одну троку, а заполняя ячейки таблицы. Каждое число должно размещаться в своей строго определенной ячейке. Существует два варианта, которые обеспечивают удобство процесса ввода массива, к таким вариантам относится использование компонентов именуемых как:

- Memo
- StringGrid



Когда массив полностью задан, то происходит его вывод или отображение. Под выводом следует понимать отображение элементов на экране при использовании диалогового окна. Так как размер массива бывает различным, то и вывод может осуществляться как всех, так и некоторых его элементов. В том случаи, когда необходим отображение всех элементов используют инструкцию «for». В данном случае инструкция позволяет применять ее в качестве индекса элементов.
Так при помощи «for» и переменной-счетчика данной инструкции производится нумерация элементов при их отображении на экране. Все элементы выводятся друг под другом, а нумерация размещается слева, так формируется ровный список. Вот только для получения отображения списка необходимо соблюдение некоторых условий. Например, свойству «Label1.AutoSize» присваивается значение «False». (Иной результат можно получить при присвоении свойству «Label1.AutoSize» значения «True»).
Массив уникален тем, что позволяет производить множество операций с введенными элементам, самой распространенной операцией является сортировка элементов массива. Под сортировкой принято понимать перестановку элементов, в результате которой задается определенный порядок значений или их расстановка по своим местам. Так в том случае, когда задан массив целых чисел, то можно их расположить в порядке возрастания или убывания. Так для выполнения сортировки по возрастанию нужно указать условие
Записан
Nm0n
Гость
« Ответ #9 : 07 Август 2009, 12:03:41 »

Сортировка элементов массива
Прежде чем начать детальное описание и подробное анализирование процесса осуществления сортировки, необходимо установить то, для чего она предназначена. В том случае, когда массив содержит небольшое количество элементов, вести работу с ними весьма просто, но при количестве, превышающем 100 или даже 1000 значений, процесс обработки данных значительно усложняется. Например, совсем непросто отыскать нужный элемент, который может и не встретиться в 500 вариантах. Это сравнимо с поиском иголки в стогу сена.
Самостоятельно без помощи специально созданной программы анализ, а тем более сортировку, произвести очень сложно. В данном случае возникает острая необходимость упрощения процесса обработки данных, которые помогает обработать программа для массива. Так самым распространенным методом является сортировка, которая позволяет отсортировать элементы или расположить их в строго определенном заранее порядке.
Прежде чем начать детальное описание и подробное анализирование процесса осуществления сортировки, необходимо установить то, для чего она предназначена. В том случае, когда массив содержит небольшое количество элементов, вести работу с ними весьма просто, но при количестве, превышающем 100 или даже 1000 значений, процесс обработки данных значительно усложняется. Например, совсем непросто отыскать нужный элемент, который может и не встретиться в 500 вариантах. Это сравнимо с поиском иголки в стогу сена.
Самостоятельно без помощи специально созданной программы анализ, а тем более сортировку, произвести очень сложно. В данном случае возникает острая необходимость упрощения процесса обработки данных, которые помогает обработать программа для массива. Так самым распространенным методом является сортировка, которая позволяет отсортировать элементы или расположить их в строго определенном заранее порядке.
Самым простым примером является сортировка, как по возрастанию, так и по убыванию. Эта сортировка проводится среди элементов массива.
Для того, чтобы произвести сортировку по возрастанию элементов массива, нужно задать условие с указанием верхней границы, например, в виде «SIZE», тогда условие будет выглядеть, как:
Записан
Nm0n
Гость
« Ответ #10 : 08 Август 2009, 11:34:12 »

Общая характеристика многомерных массивов
При обработке тех или иных информационных данных часто приходиться проводить работу с таблицами, в которых эти данные хранятся. В качестве примера можно рассмотреть результат работы компании, представленной в виде таблицы отчета за 12 месяцев по пяти наименованиям продукции. В такой таблице колонками будут являться месяцы, а строками – виды продукции.
Известно, что чаще всего информация, представленная в одной колонке или строке, однородна, поэтому эти данные можно обрабатывать при помощи использования одномерного массива. Приведенный пример может быть представлен в виде такого одномерного массива, как:
При обработке тех или иных информационных данных часто приходиться проводить работу с таблицами, в которых эти данные хранятся. В качестве примера можно рассмотреть результат работы компании, представленной в виде таблицы отчета за 12 месяцев по пяти наименованиям продукции. В такой таблице колонками будут являться месяцы, а строками – виды продукции.
Известно, что чаще всего информация, представленная в одной колонке или строке, однородна, поэтому эти данные можно обрабатывать при помощи использования одномерного массива. Приведенный пример может быть представлен в виде такого одномерного массива, как:



Известно, что каждый массив хранит информацию о месячной реализации одного вида товара, а его значения соответствуют объему реализации определенного месяца.
Рассмотрим иное представление той же таблицы:

jan: array [1..5] of integer;
feb: array [1..5] of integer;
mar: array [1..5] of integer;
-----------------------------
dec: array [1..5] of integer;

В данном случае каждый массив хранит в себе информацию об объеме продаж пяти видов товаров в определенном месяце, а значение элементов соответствует объему продаж в данном месяце одного из пяти товаров.
Только в том случае, когда все данные таблицы однородны, можно использовать для ее представления и анализа двумерный массив. Для того, чтобы правильно задать двумерный массив, необходимо следовать инструкции. Так общий вид описания массива выглядит так:

Имя: array[НижняяГраница1..ВерхняяГраница1,
НижняяГраница2..ВерхняяГраница2] of Тип

Под понятием «Имя» подразумевается имя указываемого двумерного массива. Слово «array», написанное на языке Delphi, становится прямым указанием на то, что объявляется массив. В качестве границ массива могут использоваться константы в виде целых числовых значений. Эти границы указывают на диапазон, в котором происходит изменение индексов, они определяют и количество элементов, входящих в массив. Соответственно, понятие «Тип» подразумевает указание типа не всего массива, а его элементов, которые всегда однотипны.
В приведенном выше примере таблицы, содержащей данные о производстве товаров в течение года все данные однотипны, поэтому к ним допустимо применить двумерный массив, который будет выглядеть следующим образом:

rezultat: array [1..12, 1..5] of integer

В том случае, когда необходимо вычислить общее число элементов массива, то можно применить для этого простую формулу:

(ВерхГр1-НижГр1+1)х(ВерхГр2-НижГр2+1)

В этой формуле под обозначениями «ВерхГр1/2» понимается первая и вторая верхние границы соответственно, а под обозначениями «НижГр1/2» понимается первая и вторая нижние границы соответственно. Числа 1 и 2 являются обозначениями индексов.
Таким образом, можно вычислить общее число элементов двумерного массива «rezultat: array [1..12, 1..5] of integer», приведенного выше. В процессе подстановки получаем (12-1+1) х (5-1+1)= 60 значений типа integer массива rezultat.
После того, как массив будет задан, работа производится порой не с ним целиком, а с его отдельными элементами. Для этого необходимо уметь указывать конкретный элемент массива. Для этого сначала указывается имя самого массива, а только потом пишутся координаты элемента. Координаты состоят из двух чисел-индексов для двумерного массива. Первый индекс – это номер строки таблицы, а второй номер – это номер колонки.
В нашем примере элемент rezultat [2,3] в себе будет содержать данные об объеме проданного товара №2 (он указан во второй строке) в третьем месяце (в марте).
Часто в процессе обработки данных таблиц применяется инструкция «for». Она позволяет рассчитывать общее количество проданных товаров одного из пяти видов в течение года (в данном случае производится расчет объема годовой продажи продукции tovar3). Для этого необходимо сделать соответствующие записи:

s := 0; for j := 1 to 12 do
s := s + rezultat [3,j];

Можно иначе применить инструкцию «for» для расчета всего объема продаж пяти видов продукции совместно за 12 месяцев. Для этого необходимо произвести суммирование, как по строкам, то есть по видам товаров, так и по столбцам таблицы, то есть по месяцам производства. Это можно осуществить путем составления следующих записей:

s:=0;
for i := 1 to 5 do // пять видов товара
for j := 1 to 12 do //12 месяцев s := s + rezultat [i,j];

Метод подсчета основан на том, что программа выполняет цикл по j, когда наступает его завершение, значение i увеличивается и становится равным «i+1», тогда снова начинается цикл по j. В данном случае цикл по j именуется внутренним циклом, а цикл по i именуется внешним. В процессе выполнения этих циклов к переменной s последовательно добавлются и суммируются значения элементов массива rezultat: rezultat [l,l], rezultat [l,2], ..., rezultat [l,12], rezultat [2,l], rezultat [2,2], ..., rezultat [2,12] и т. д. до последнего элемента rezultat [5,12].
Записан
Nm0n
Гость
« Ответ #11 : 08 Август 2009, 11:34:57 »

Процесс составления алгоритма и программы
Перед тем, как начать создавать программу, необходимо точно определить цель ее написания. Так, когда цель точно определена, следует рассмотреть более подробно методы достижения поставленной перед программой цели, эти методы достижения бывают представлены в наборе определенных действий, при этом каждое действие запускается поочередно, то есть в определенном заранее заданном порядке.
Таким образом, необходимо не только указать набор действий, но и определить их поочередность. Именно алгоритм содержит в себе поэтапный процесс пути следования к поставленной цели. После того, как алгоритм примерно определен, его необходимо описать с подробным указанием всех деталей. Описание может быть как словесным, так и графическим. При графическом описании применяются условные обозначения в идее схем. Для того, чтобы условные обозначения были понятны, создан специальный набор символов, в котором производится подробное описание каждого элемента блок-схемы.
Перед тем, как начать создавать программу, необходимо точно определить цель ее написания. Так, когда цель точно определена, следует рассмотреть более подробно методы достижения поставленной перед программой цели, эти методы достижения бывают представлены в наборе определенных действий, при этом каждое действие запускается поочередно, то есть в определенном заранее заданном порядке.
Таким образом, необходимо не только указать набор действий, но и определить их поочередность. Именно алгоритм содержит в себе поэтапный процесс пути следования к поставленной цели. После того, как алгоритм примерно определен, его необходимо описать с подробным указанием всех деталей. Описание может быть как словесным, так и графическим. При графическом описании применяются условные обозначения в идее схем. Для того, чтобы условные обозначения были понятны, создан специальный набор символов, в котором производится подробное описание каждого элемента блок-схемы.
Блок-схема помогает визуально оценить алгоритм, более подробно рассмотреть порядок действий, найти ошибки и недочеты. Не стоит забывать о том, что в процессе создания программ на языке Delphi одна программа содержит в себе, как правило, не один, а сразу несколько алгоритмов, необходимых для достижения поставленной цели или для решения конкретной задачи. Количество алгоритмов влияет на быстроту определения решения, поэтому их число должно быть минимальным.
Для того, чтобы алгоритм начал работать, его необходимо занести в программу, но прежде этого идет детальная разработка, которая и является самым сложным процессом. При создании или разработке алгоритма необходимо учесть, что верных вариантов составления алгоритмов всегда несколько, поэтому из всех существующих вариантов необходимо выбрать самый короткий (быстро реализуемый) путь решения поставленной перед программистом задачи. Но для того, чтобы этот выбор осуществить, нужно сначала найти и рассмотреть все варианты.
Для того, чтобы наглядно представить пример алгоритма, нужно подробно рассмотреть один из его вариантов. Для этого можно рассмотреть массив, состоящий из целых чисел. Перед алгоритмом поставлена цель определения самого минимального/максимального значения среди элементов заданного массива.
Суть процесса заключается в следующем: в алгоритме осуществляется поочередное сравнение элементов. Сначала за минимальное/максимальное значение условно принимается первый элемент. Далее идет сравнение с этим элементом второго, третьего, четвертого … последнего. В том случае, когда найдется среди остальных элементов тот, что меньше/больше условно принятого минимального/максимального значения, то данный элемент становится условным минимумом/максимумом, а после этого снова начинается проверка. Этот процесс завершается тогда, когда будет обнаружен настоящий минимум/максимум.
Диалоговое окно, которое выводится при осуществлении поиска, обязательно включает в себя особым образом настроенный компонент, именуемый «stringGridi». Данный компонент необходим для реализации вывода элементов.
Для предоставления информационного оповещения о проведенной работе используется поля меток «Label1», а так же «Labeia», вместе с ними используется кнопка «Buttonl». Именно эта кнопка осуществляет процесс запуска поиска необходимого минимального или максимального значения. Когда поиск закончен, то в результате предоставляется не только значение искомого элемента, но и его номер.
После того, как процесс составления алгоритма на примере поиска максимального или минимального элемента массива был оговорен, необходимо перейти к рассмотрению процесса записи инструкции программы.



Самым главным и основным моментом является то, что инструкции в программе друг от друга всегда отделяются знаком «;», то есть это знак ставится непосредственно в самом конце инструкции. В таком случае инструкции можно записывать в одну строчку друг за другом, применяя разделение в виде «;», и они будут выполняться.
Вот только для того, чтобы написанная программа была более удобна при визуальном прочтении, необходимо каждую инструкцию размещать на новой строке. Иногда применимо использовать несколько строк, которые при этом входят в состав одной инструкции. В данном случае применяются отступы для улучшения визуально восприятия.
Каждая инструкция имеет начало и конец, поэтому принято размещать на одном расстоянии от начала строки начало и конец соответствующей инструкции, именно для этого применяются отступы.
Еще необходимо учесть то, что в записи не учитываются «лишние» пробелы, поэтому их можно широко применять, как и пустые сточки для отделения разделов программы. Допустимо использовать дополнительные комментарии, которые при этом необходимо поместить в фигурные скобки, например, «{расчет коэффициентов}»
Записан
Уроки Phptoshop, Linux, Windows 7
   

 Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  



* Счетчики
Наша Кнопка

Powered by SMF 1.1.16 | SMF © 2006-2009, Simple Machines | Sitemap
Платим за ответы, sd 8gb.
SimplePortal 2.3 © 2008-2009, SimplePortal