Уроки для начинающих программистов
Выпуск N 20
(Юбилейный)
Ведущий рассылки Эдуард Дмитриев.
Сайт: http://prog.agava.ru/
Здравствуйте, уважаемые подписчики!
Это письмо желательно читать в броузере или развернуть на весь экран, тогда легче ориентироваться и приятнее читать!

В этом выпуске:
  1. Извинения
  2. Юбилей: Новости, итоги, планы
  3. Уроки программирования на Паскале

 

2. Юбилей: новости, итоги, планы

Юбилей. Нам с вами уже двадцать выпусков! Много или мало? Это решать вам. Я же со своей стороны постараюсь подвести итоги выполненной работы, при этом немножко заглянуть в будущее. Итак, чему же мы научились за двадцать выпусков?

А научились мы довольно многому. Пусть даже и не прошли всю теоретическую часть Паскаля, зато написали уже довольно много программ, а также на 90% прошли HTML. С полной уверенностью могу сказать, что та часть гипертекстового языка, которую мы завершили, позволит вам самостоятельно выполнить любой сайт, который вам придет в голову. За исключением Cgi и Dhtml, конечно, а также некоторых, связанных с этими технологиями инструментов - будь то заполняемые формы или элементы Java Script. Все это - еще впереди, в самом ближайшем будущем.
Паскаль. Что вы сейчас сможете написать на Паскале? В принципе, решить любую математическую или физическую задачу, работать с массивами, записями, создавать собственные процедуры. Хотя в этом плане мы затронули только вершину айсберга, этой огромной глыбы под названием программирование. Узнали немало, предстоит еще больше. Для начала, мы должны будем научиться работать с внешними файлами и добить типы данных. На это все уйдет не более двух-трех выпусков, которые я сейчас постараюсь делать как можно более частыми.
Далее - перейдем к динамических структурам данных, которые уже применяются в более продвинутом программировании. Затем начнем шагать по таким аспектам программирования как работа с графикой и системными средствами компьютера. Займемся объектно-ориентированным программированием, напоследок переключившись на искуственный интеллект. Здесь смоделируем несколько примитивов, которые будут прототипами реального интеллекта, наподобие поведения мухи или таракана :)), если дело пойдет без особых затруднений, создадим небольшой движок с несколькими объектами, которые будут генериться в реальном времени и уже кой-чего соображать :))
В общем, по ходу изучения Паскаля познакомимся с самыми наинтереснейшими аспектами программирования. Заглянем внутрь, так сказать.
Что дальше? Лично я считаю, что немаловажным шагом на пути начинающего программиста является переход от DOS к Windows. Здесь открываются новые горизонты программирования. Ну а дальше... дальше будет не то, чтобы скоро :)) там и будет видно. Я имею некоторые планы, но не знаю, как пойдет дело - если все сложиться удачно, то мы сможем узнать и основить очень много интересных вещей.

Думаю, общая картина ясна. Теперь хотелось бы отметить новые планы, которые у меня образовались во время своего непредвиденного отпуска. Сразу скажу, что в эти планы входит ваше самое активное участие в проекте, и не только в работе над сайтом Клуба, но и над рассылкой. Что же это за участие? Рассказываю по порядку.

Самое главное что отличает рассылку от обычной книги - это интерактивность. То есть читая рассылку вы получаете авторский материал, который составляется с учетом ваших же пожеланий и предложений. Далее - вы можете задать вопрос непосредственно автору материала, чот тоже немаловажно. При этом чем выше интерактивность, тем лучше и интереснее выходит наше с вами общение. В идеале вам было бы гораздо интереснее учавствовать в процессе не только в качестве вопрошающего, но и в качестве соавтора. К примеру, вы не понимали какую-то вещь - пусть это будет сортировка массива методом пузырька. Не понимали долго и интенсивно разбирались. В итоге собрали материал, выполнили злополучную сортировку и разом все прояснилось. Задумайтесь - ваш уровень мгновенно повысился, у вас появилась интересная авторская информация, которой вы можете поделиться с народом, причем не просто с группой человек, а даже с небольшим городком - с более чем 20000 жителей нашей рассылки. Разве вам это не интересно? Что для этого нужно? Все очень просто и достаточно изложить свой материал в электронном виде и предоставить на всеобщее обозрение.
ВСЕ! Вы уже участник проекта и соавтор нашего интерактивного процесса обучения. А проблемы типа приведенной мной сортировки массива возникают у всех - и не только на Паскале, а и на Си, и на Ассемблере, и в работе с Windows, в установке и настройке Linux, в создании сайта.

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

Когда мне пишут новички с вопросом "как мне можно принять участие в создании клуба" и я им отвечаю "изложите что-нибудь полезное для других, поделитесь опытом", за этим обычно следует сообщение "а я ничего не знаю... у меня-то и опыта нет...". Так вот, дорогие друзья, всем вышеизложенным материалом я хочу доказать, что не существует людей, у которых нет опыта или совершенно ничего не знающих. Если ничего не приходит в голову, вы не решаете никаких проблем - так начинайте! Задумайтесь, а что вас интересует? Вот кому, например, не интересно, как работает архиватор ZIP или каким образом можно программно открыть дверцу CD-ROM'а? А нарисовать свое имя в трехмерном простанстве, крутящимся вокруг какой-нибудь из осей?
В общем, призываю всех (!) к участию, ваши мысли и решение проблем, изложенных с виде электронной статьи увидят десятки тысяч людей! Глядишь, среди них пару тысяч найдут решение среди предоставленных материалов :))
Лично я постараюсь приложить все усилия по объединению и публикации вашего материала в рассылке и на сайте, для чего будут открываться новые разделы и пополняться имеющиеся.

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

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

 

3. Уроки программирования на Паскале

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

Обратите внимание на этот код:



 ......



    C := ReadKey;

    case C of

      '1'..'9': begin

                  Val(C, I, Code);

                  List_Item(I);

                end;

      'a': New_Item;

      #27: Quit := true;

    end;



 ......

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

Ну а мы интенсивно двигаемся дальше. Сегодня - как и было обещано, файлы. Пока только теория, которую вам нужно усвоить (ее довольно много), практика будет в следующем выпуске.

  Работа с файлами

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

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

  1. Создание (описание) файловой переменной;
  2. Связывание этой переменной с конкретным файлом на диске или с устройством ввода-вывода (экран, клавиатура, принтер и т.п.);
  3. Открытие файла для записи либо чтения;
  4. Действия с файлом: чтение либо запись;
  5. Закрытие файла.
Первое, на что хочу обратить внимание, это возможность связать файловую переменную не только с физическим файлом на носителе информации, но и с устройством. В качестве такового используются обычные псевдонимы устройств DOS. Вот основные два:
  1. CON - консоль (экран-клавиатура), то есть по записи в это устройство мы будем получать информацию на экран, при чтении информации из этого устройства, будем читать данные с клавиатуры.
  2. PRN - принтер. При записи в это устройство вы получите информацию на принтер.
Далее хочу обратить внимание на последний этап - закрытие файла. В принципе, не обязательное условие для файлов, из которых мы читаем данные. Если не закроем - ошибки это не вызовет, последствий тоже. Однако обязательно закрывать файл, если мы осуществляли в него запись. Дело в том, что если мы пишем данные в файл на диске и забываем его закрыть - информация не сохраниться. Она (информация) помещается во временный буфер, который запишется на диск только при закрытии файла.

  Типы файловых переменных

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

  1. Text - текстовый файл. Из переменной такого типа мы сможем читать строки и символы.

  2. File of _любой_тип_ - так называемые "типизированные" файлы, то есть файлы, имеющие тип. Этот тип определяет, какого рода информация содержится в файле и задается в переметре _любой_тип_. К примеру, если мы напишем так:

    F: File of Integer;

    То Паскаль будет считать, что файл F содержит числа типа Integer; Соответсвенно, читать из такого файла мы сможем только переменные типа Integer, ровно как и писать. Напишем так:

    type
    A = record

    I,J: Integer;
    S: String[20];
    end;

    var

    F: File of A;

    То получим очень интересную картину, когда файл содержит в качестве элементов записи. Мы сможем их читать, писать и производить с ними действия. Именно этим мы и займемся в процессе модификации нашей программы "Записная книжка".

  3. File - нетипизированный файл. Когда мы указываем в качестве типа файла просто File, то есть без типа:

    F: File;

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

Итак, разобрались с типами файлов. Теперь давайте по порядку разбирать действия, применяемые для работы с файлами. Я говорил о них выше.

  Связывание переменной с файлом

Самый универсальный шаг. Выполняется одной и той же процедурой для всех типов файлов, а именно процедурой Assign:

Assign(_переменная_файлового_типа_, 'путь к файлу');

Как видите, в качестве параметров задаются переменная либого файлового типа и строка - путь к файлу, который, по правилам DOS, не может быть длиннее 79 символов. Вот пример использования assign:



var

  T: Text;

  F1: File of Byte;

  F2: File;



begin

  Assign(T, '1.txt');

  Assign(F1, 'C:\Programm\Tp\2.txt');

  Assign(F2, 'F:\usr\bin\apache\conf\httpd~1.con');



  ..........

Как видите, это очень просто и сама процедура Assign проблем не вызывает. Давайте теперь рассмотрим следующий этап.

  Открытие файла

Открытие файла - это уже более усложненный процесс, нежели связывание с ним переменной. Здесь учитывается, зачем открывается файл - для записи или чтения, а также в зависимости от типа файла процедуры выполняют различные действия.

Тем не менее этот процесс не сложен и заключается в использовании одной из трех имеющихся процедур:

  1. Reset(_любая_файловая_переменная_);
    Открыват файл на чтение. В качестве параметра - файловая переменная любого из перечисленных выше типов. Это может быть текстовый, типизированный либо не типизированный файл. В случае с текстовым файлом, он открывается только на чтение. В случае с типизированным и нетипизированным файлом - он открывается на чтение и запись.

  2. Append(T: Text);
    Эта процедура открывает текстовый файл (только текстовый!) на запись. Выше я сказал, что Reset при задании параметра типа Text не позволит писать в него данные, открыв файл лишь для чтения. То есть если вы используете текстовый файл и хотите производить в него запись, нужнo использовать Append. Если чтение - Reset. В остальных случаях дело обходиться одной процедурой Reset.
    Также обратите внимание, что если вы до этого уже открыли файл на чтение, вам не нужно закрывать его и открывать снова на запись. В этом случае файл закрывается сам и открывается заново. При записи данных в файл при открытии его с помощью этой процедуры они записываются в конец файла.

  3. ReWrite(F) - создает новый файл либо перезаписывает существующий. Будьте осторожны, если не хотите случайно удалить нужный файл. Напомню, файл, открытый с помощью этой процедуры будет полностью перезаписан.
В использовании процедур, думаю, проблем не будет. Однако возникает другой вопрос - что, если файла, который открыватся, нет? Если он не существует на диске, то как мы сможем из него читать информацию? Программа выбъет ошибку в такой ситуации. Это реальная проблема, которая, кстати, очень просто решается.

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

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

Оформляются ключи следующим образом: в скобках комментариев "{}" первым символом после открывающей скобки "{" ставиться знак доллара "$", после чего указывается имя ключа и его значение. Нас интесует ключ, который выключает вывод ошибок ввода-вывода, называется он "I". Выглядит все это следующим образом:

{$I+} - включение вывода ошибок
{$I-} - выключение вывода ошибок

По сути дела осутствие файла - это ошибка, которая возвращается функцией IOResult. Если же эта функция возвращает 0, то файл успешно открыт, без ошибок. Вот и вырисовывается последовательность действий, необходимых для проверки на наличие файла:
  1. Связываем переменную с файлом;
  2. Выключаем вывод ошибок на экран - {$I-}
  3. Окрываем файл необходимой нам процедурой;
  4. Включаем вывод ошибок {$I+} - пусть будет для дальнейшего отслеживания таковых;
  5. Проверяем, если IOResult возвращает нуль, то все было путем и файл открыт. Иначе выводим ошибку.
Вот пример такой программы:



var

  T: Text;

  S: String;



begin

  Write('Enter filename: ');

  Readln(S);

  Assign(T, S);

{$I-}

  Reset(T);   { открываем файл для чтения }

{$I+}

  if IOResult <> 0 then   { если не нуль, то была ошибка }

  begin

    Write('Error when open file!');

    Halt;

  end;

  { иначе все в порядке, продолжаем }

  ..........

end.

  Закрытие файла

Выше я говорил о том, зачем нужно закрывать файл и когда надо это делать. Закрытие файла производиться с помощью процедуры Close(F), где F - это переменная файлового типа. Эта процедура одна для всех типов файлов.

  Запись и чтение файлов, часть I.

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

Чтение файлов. Чтение файлов производится с помощью отлично известных нам процедур Read и Readln. Они используются также, как и при чтении информации с клавитуры. Отличие лишь в том, что перед переменной, в которую помещается считанное значение, указывается переменная файлового типа (дескриптор файла):

Read(F, C);
Здесь F - дескриптор файла, C - переменная (Char, String - для текстовых, любого типа - для типизированных файлов).

Также сразу хочу упомянуть о одной, пожалуй самой главной функции при чтении файлов. Это функция поверки на конец файла - Eof(F): Boolean;. В качестве параметра - файловая переменная любого типа. Функция возвращает TRUE если достигнут конец файла и FALSE иначе.

Здесь все очень просто, демонстрации ради давайте напишем небольшую программку. Пусть имеем текстовый файл. Давайте его распечатаем и заодно посчитаем, например, количество пробелов:



var

  T: Text;

  С: Char;

  Spaces: Word;

  S: String[79]; { 79-макс. длина пути в DOS }



begin

  Write('Enter filename: ');

  Readln(S);

  Assign(T, S);



{ открываем файл для чтения }

{$I-}

  Reset(T);

{$I+}



{ если не нуль, то была ошибка }

  if IOResult <> 0 then

  begin

    Write('Error when open file ', S, ' !');

    Halt;

  end;



{ иначе все в порядке, продолжаем }



{ ЦИКЛ: пока НЕ КОНЕЦ ФАЙЛА }

  While (not Eof(T)) do 

  begin

{ читаем из файла переменную }

      Read(T, C);

{ если пробел, увеличиваем счетчик }

      If C = ' ' then Inc(Spaces);

      Write(C);

  end;

  Writeln('КОЛИЧЕСТВО ПРОБЕЛОВ: ', Spaces);

  Readln;

end.

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

Запись в файлы. Вы еще не догадались? Запись в файлы производиться точно так же, как и запись на экран - с помощью процедур Write и Writeln. Как и в случае с чтением, перед записываемой в файл переменной указывается тескриптор файла:

Write(F, S);

Здесь F - дескриптор, S - переменная.

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

План дейтсвий:

  • Отрываем типизированный файл из Integer; (проверяем на ошибку и т.п.)
  • Читаем все числа в массив (считываем, пока не конец файла)
  • Сортируем массив по возрастанию;
  • Записываем отсортированный массив обратно в файл.

Получается такая программа:



Program Sorting;

uses Crt;



var

  F: File of Integer;

  I, J, M: Word;

  Mas: Array[1..500] of Integer;

  S: String;



begin

  ClrScr;

  Write('Enter filename: ');

  Readln(S);



{ открываем файл }

  Assign(F, S);

{$I-}

  Reset(F);

{$I+}

  if IOResult <> 0 then

  begin

    Write('Error when open file!');

    Halt;

  end;



{ пока не конец файла, читаем массив }

  While (not Eof(F)) do

  begin

    Inc(M);

    Read(F, Mas[M]);

    Write(Mas[M], ' ');

  end;



{ сортируем массив по возрастанию }

  For I := 1 to M do

    For j := 1 to M do

      if Mas[I] < Mas[J] then

      begin

        inc(mas[j], mas[i]);

        mas[i] := mas[j]-mas[i];

        dec(mas[j], mas[i]);

      end;



  Writeln; Writeln('=============================================');



{ перезаписываем файл  }

  ReWrite(F);

  For I := 1 to 100 do

  begin

    Write(Mas[I], ' ');

    Write(F, Mas[i]);

  end;



  Writeln; Write('Elements in file: ', M);



  Close(F);

  Readln;

end.

Программа очень проста и хорошо демонстрирует работу с типизированными файлами. В качестве сортировки массива я использую метод пузырька, чтобы перезаписать файл использую ReWrite. Вроде не должно возникать никаких сложностей... Будут проблемы, пишите.

Ну а на сегодня, пожалуй, все. Этой информации вам будет достаточно, в следующем выпуске займемся, как я уже сказал, нетипизированными файлами и продолжим писать программу "Записная книжка".

До встречи!

 


ї Эдуард Дмитриев (E-mail: ed1@mailru.com). http://www.proglib.com/

Назад

Hosted by uCoz