МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ ФЕДЕРАЦИИ ФЕДЕРАЛЬНОЕ АГЕНТСТВО ПО ОБРАЗОВАНИЮ Московский государственный ин...
191 downloads
193 Views
536KB Size
Report
This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Report copyright / DMCA form
МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ ФЕДЕРАЦИИ ФЕДЕРАЛЬНОЕ АГЕНТСТВО ПО ОБРАЗОВАНИЮ Московский государственный институт электроники и математики (Технический университет)
Кафедра Управления и информатики в технических системах
ИНФОРМАТИКА Методические указания к лабораторным работам
Москва 2009 г. 1
Составитель ст. преп. В.Г. Кулаков УДК ???
Информатика. Метод, указания к лабораторным работам / Моск. гос. ин-т электроники и математики; Сост. В.Г. Кулаков. М., 2009, 27 с. Табл. 2. Ил. 5. Библиогр.:8 назв.
Методические указания к лабораторным работам по дисциплине «Информатика» предназначены для студентов первого курса дневного отделения. Основной целью лабораторных работ является освоение студентами правил элементарного программирования на языке Си. Методические указания составлены в соответствии с программой и планом для специальности «Управление и информатика в технических системах» - 210100.
ISBN ???
2
Содержание 1. Лабораторная работа №1. Знакомство с интегрированной средой Borland C++ 1.1. Цель лабораторной работы 1.2. Основы работы в IDE 1.3. Окна системы Borland C++ 1.4. Горячие клавиши 1.5. Упражнения 2. Лабораторная работа №2. Использование указателей при работе с видеопамятью 2.1. Цель лабораторной работы 2.2. Организация памяти IBM PC 2.3. Видеоконтроллер VGA 2.4. Вывод спрайтов на экран монитора 2.5. Упражнения 3. Лабораторная работа №3. Работа с файлами и каталогами 3.1. Цель лабораторной работы 3.2. Функции для работы с дисками и каталогами 3.3. Поиск файлов 3.4. Функции общего назначения для работы с файлами 3.5. Функции для работы с текстовыми файлами 3.6. Функции для работы с двоичными файлами 3.7. Упражнения 4. Лабораторная работа №4. Работа с структурами данных на примере файла BMP 4.1. Цель лабораторной работы 4.2. Организация видеопамяти в графическом режиме TrueColor 4.3. Функции VESA BIOS 4.4. Формат BMP для несжатого RGB-изображения 4.5. Параметры функции main 4.6. Упражнения Библиографический список
Стр. 4 4 4 4 5 6 8 8 8 9 12 12 15 15 15 16 17 17 18 19 20 20 20 22 23 24 24 26
3
1. Лабораторная работа №1 Знакомство с интегрированной средой Borland C++ 1.1. Цель лабораторной работы Целью работы является освоение интегрированной среды Borland C++. В настоящее время язык Си считается устаревшим и используется только в учебном процессе – для освоения основ программирования на алгоритмических языках, поэтому на персональных компьютерах для трансляции Си-программ используются компиляторы с языка C++ – усовершенствованной версии Си. На территории России в настоящее время наиболее распространены C++ компиляторы Microsoft (Visual C++ и Visual Studio) и Borland (Turbo C, Turbo C++ и Borland C++). И Microsoft, и Borland предоставляют возможность бесплатной закачки учебных версий компиляторов через Интернет, однако возможности таких компиляторов сильно ограничены. Фирма Borland предоставляет две бесплатные версии Си-компилятора, предназначенные для работы в среде MS DOS – Turbo C 2.01 и Turbo C++ 1.01. Это полноценные версии компиляторов, снабженные интегрированной средой разработки (включая подсказку и отладчик), но запуск компиляторов возможен только в среде MS DOS или в режиме эмуляции DOS под управлением Windows. 1.2. Основы работы в IDE В интегрированной среде разработки (IDE) системы Borland C++ имеется все необходимое для написания, редактирования, компиляции, компоновки и отладки программ пользователя. Для запуска IDE после приглашения DOS наберите BC. За этой командой могут следовать один или несколько параметров командной строки (обычно в качестве параметра задают имя исходного файла, который надлежит открыть в окне редактирования). IDE имеет три визуальных компоненты: строку меню у верхнего края экрана, область окна в средней части экрана и строку состояния у нижнего края экрана. Строка меню представляет собой основное средство доступа ко всем командам меню. Для доступа к меню обычно используется мышь, однако можно также перейти в строку меню, нажав клавишу F10. В результате выбора многих элементов меню на экран будут выдаваться диалоговые окна. Если за командой меню следует многоточие, то в результате выбора данной команды появляется диалоговое окно. Если за командой следует стрелка, то выбор данной команды приводит к появлению другого меню (всплывающего меню). Если рядом с командой не присутствует ни многоточие, ни стрелка, то это означает, что выбор данной команды приводит к немедленному выполнению того действия, которое закреплено за данной командой. Для отмены некоторого действия используют клавишу Esc. Для того, чтобы выйти из среды IDE, выберите команду Quit в меню File или нажмите комбинацию клавиш Alt-X. Если вы внесли в тексты программ какие-либо изменения, которые еще не были сохранены, то среда выдаст сообщение, в котором спрашивается, хотите ли вы сохранить перед выходом из системы ваши программы. 1.3. Окна системы Borland C++ Большая часть того, что вы видите и делаете в IDE, происходит в окне. Окно представляет собой область экрана, которую можно открывать, закрывать, перемещать, у которой можно изменять размеры, которую можно распахивать на весь экран и перекрывать с другими окнами. В IDE может быть открыто много окон, но в каждый момент времени активным может быть только одно окно. Активным окном является то окно, в котором вы в настоящий момент работаете. Любые выбираемые вами команды или вводимый вами текст, как правило, относится только к активному окну.
4
Маркер закрытия окна представляет собой прямоугольник, который расположен в левом верхнем углу окна. Для закрытия окна необходимо подвести к нему указатель мыши и щелкнуть кнопкой мыши. Можно также выбрать команду Close в меню Window или нажать комбинацию клавиш Alt-F3. Строка заголовка, являющаяся самой верхней строкой окна, содержит название данного окна и номер окна. Для того, чтобы распахнуть окно на весь экранный кадр, можно подвести указатель мыши к строке заголовка и дважды щелкнуть кнопкой мыши. Маркер распахивания окна на весь экран располагается в правом верхнем углу. Если пиктограмма в этом углу представляет собой стрелку вверх, то можно подвести к этой пиктограмме мышь и нажать кнопку, чтобы увеличить размеры окна. Если эта пиктограмма представляет собой стрелку с концами, направленными вверх и вниз, то окно уже имеет максимальный размер. В этом случае можно подвести к этой пиктограмме мышь и нажать кнопку мыши, чтобы окно приняло свой первоначальный размер. В правом верхнем углу первых девяти окон, которые вы открываете в системе Borland C++, имеется номер окна. Какое-либо окно можно сделать активным нажатием клавиши Alt в комбинации с номером окна. Если за элементом меню располагается многоточие, то в результате выбора данной команды будет открыто диалоговое окно. Диалоговое окно представляет собой удобный способ просмотра и задания многих параметров. Когда вы осуществляете установку в диалоговом окне, вы работаете с пятью основными типами средств управления: кнопками с независимой фиксацией, кнопками с зависимой фиксацией, кнопками действия, окнами ввода и окнами-списками. В диалоговом окне содержатся также окна ввода, которые позволяют вам вводить текст. 1.4. Горячие клавиши Для выполнения часто используемых операции используются так называемые горячие клавиши и комбинации клавиш. Клавиши общего назначения: F1 – вызвать подсказку; F2 – сохранить файл; F3 – открыть файл; F4 – выполнить программу до строки, на которой установлен курсор; F5 – развернуть/свернуть активное окно; F6 – перейти к следующему окну; F7 – выполнение программы в режиме отладки с трассировкой; F8 – выполнение программы в режиме отладки; F9 – откомпилировать программу и создать исполняемый файл; F10 – перейти в меню. Клавиши активации меню: Alt+пробел – системное меню; Alt+C – меню компиляции; Alt+D – меню отладки; Alt+E – меню редактирования; Alt+F – меню операций с файлами; Alt+H – меню подсказки; Alt+O – меню настроек; Alt+P – меню проекта; Alt+R – меню запуска; Alt+S – меню поиска; Alt+W – меню выбора окна; Alt+X – выход из системы. Клавиши режима редактирования: Ctrl+Del – удалить выделенный текст; 5
Ctrl+Ins – скопировать выделенный текст в буфер; Shift+Del – скопировать выделенный текст в буфер и удалить его; Shift+Ins – вставить текст из буфера в файл; Аlt+Bksрc – возвращает текст в предыдущее состояние. Клавиши управления окнами: Alt+F3 – закрыть активное окно; Alt+F4 – открыть окно проверки; Alt+F5 – отобразить экран пользователя. Клавиши активации режима подсказки: F1 – выдать инструкцию по использованию подсказки; Shift+F1 – вызвать тематический указатель по системе подсказки. Ctrl+F1 – вызывать контекстную подсказку. Клавиши режима выполнения и отладки: Alt+F4 – открыть окно проверки; Alt+F7 – возврат к предыдущей ошибке; Alt+F8 – перейти к следующей ошибке; Alt+F9 – создать объектный файл (компиляция без компоновки); Ctrl+F2 – реинициализация выполняющейся программы; Ctrl+F3 – вывести на экран окно со стеком вызовов функций; Ctrl+F4 – вычислить выражение; Ctrl+F7 – добавить просматриваемое выражение; Ctrl+F8 – установить или отменить точку останова; Ctrl+F9 – выполнить программу. Блоком называют произвольный фрагмент текста размером от одного символа до сотен строк текста, который выделен на экране специальным образом. В каждый момент времени в окне может существовать только один блок текста. Блок маркируется с помощью мыши или путем перемещения маркера от начала блока до его конца при нажатой клавише Shift. Будучи помеченным, блок может быть скопирован, перемещен, удален, отпечатан или записан в файл. Команды работы с блоками начинаются с комбинации Ctrl+K, после чего следует нажать клавишу с определенным символом: B – начало отметки блока; K – конец отметки блока; Y – удалить блок; C – скопировать блок; V – переместить блок.
1) 2)
1.5. Упражнения Упражнение 1. Требуется выполнить следующую последовательность действий: Запустить интегрированную среду Borland C++, набрав в командной строке команду BC. Набрать в окне редактирования следующий текст: #include <stdio.h> main() { printf(”Здравствуй, мир!\n”); return 0; }
3) 4) 5) 6)
Записать программу на диск в файл с именам HELLO.C, нажав клавишу F2. Установить курсор на функцию printf и вызвать контекстную подсказку, путем нажатия комбинации клавиш Ctrl+F1. Закрыть окно подсказки путем нажатия комбинации клавиш Alt+F3. Скомпилировать программу, нажав клавишу F9. Если программа набрана правильно, в окне результатов компиляции будет указано, что количество ошибок (ERRORS) и
6
7) 8) 9) 10) 1) 2)
предупреждений (MESSAGES) равно нулю. В том случае, если в процессе набора были допущены ошибки, появится окно сообщений об ошибках. Если выбрать в окне какое-либо сообщение и нажать клавишу Enter, в окне редактирования строка программы, содержащая ошибку, будет выделена красным цветом. После устранения всех обнаруженных ошибок запустить программу на выполнение путем нажатия комбинации клавиш Ctrl+F9. Просмотреть результат работы программы, для чего требуется перейти на пользовательский экран путем нажатия комбинации клавиш Alt+F5. Вернуться из пользовательского окна в окно редактирования можно путем нажатия любой произвольной клавиши. Выйти из интегрированной среды путем нажатия комбинации клавиш Alt+X. Упражнение 2. Требуется выполнить следующую последовательность действий: Запустить интегрированную среду. Набрать в окне редактирования следующий текст: #include #include void main() { int c; while ((c = getch()) != ’0’) putch(isupper(c) ? tolower(c) : c); }
Записать программу на диск в файл с именам LOWER.C. Скомпилировать программу. После устранения всех обнаруженных ошибок запустить программу на выполнение. Ввести в пользовательском окне любую произвольную последовательность символов, наблюдая за результатом преобразования. Ввод завершить нажатием цифры 0. 7) Выйти из интегрированной среды путем нажатия комбинации клавиш Alt+X. Упражнение 3. Составить, скомпилировать и запустить на выполнение программу, которая запрашивает у пользователя ввод целого числа N, а затем выводит на экран квадраты целых чисел от 1 до N. Упражнение 4. Составить программу, которая запрашивает у пользователя ввод положительного целого числа N, а затем выполняет поиск всех делителей числа N методом простого последовательного перебора и выводит найденные числа на экран. Если число N простое, вывести соответствующее сообщение. Упражнение 5. Транспонированная матрица AT (NM) получается из матрицы A (MN) путем перестановки элементов: столбцы становятся строками и наоборот, т.е. aTji = aij, где i = 1, …, M, j = 1, …, N. Требуется сформировать квадратную матрицу A размером 55, содержащую целые числа от 1 до 25 (при заполнении матрицы использовать циклы for) и вывести ее на экран по строкам, а затем создать транспонированную матрицу AT на месте матрицы A и вывести ее на экран по строкам. 3) 4) 5) 6)
7
2. Лабораторная работа №2 Использование указателей при работе с видеопамятью 2.1. Цель лабораторной работы Целью данной лабораторной работы является изучение организации внутренней памяти ATсовместимых персональных компьютеров и освоение правил работы с дальними указателями. Работа с указателями рассматривается на примере видеоконтроллера. Отчет о лабораторной работе не оформляется. Прием задания производится непосредственно на компьютере по предъявлению работающей, полностью отлаженной программы. 2.2. Организация памяти IBM PC При работе в MS DOS современные AT-совместимые персональные компьютеры вынуждены использовать организацию адресного пространства, унаследованную от IBM PC (рис. 2.1).
Рис. 2.1. Организация адресного пространства IBM PC Память ЭВМ IBM PC была организована следующим образом: первые 640 Кбайт адресного пространства с адресами от 00000 до 9FFFF выделены под оперативную память, а остальные 384 Кбайт c адресами от A0000 до FFFFF используются для размещения ПЗУ и отображаемого на память ввода-вывода. В начале области ОЗУ размещена область векторов прерываний: 256 векторов, занимающих по 4 байта памяти. После них расположены области данных и программ операционной системы. Оставшуюся часть ОЗУ занимают программы пользователя. Адреса в области ПЗУ и отображаемого ввода-вывода распределены следующим образом: A0000-BFFFF – область ввода-вывода видеоконтроллера, C0000-FFFFF – область ПЗУ жесткого диска, видеоадаптера и других устройств. Программы используют пространство памяти в 1 Мбайт в виде сегментов. Сегмент представляет собой логическую единицу памяти размером 64 Кбайт. Каждому сегменту программой назначается базовый адрес, являющийся адресом его первого байта в адресном пространстве памяти. Все сегменты начинаются на 16-байтных границах памяти, называемых 8
границами параграфов. Сегменты могут быть соседними (смежными), непересекающимися, частично или полностью перекрывающимися. Физическая ячейка памяти может принадлежать одному или нескольким сегментам. Во время выполнения программы процессору в любой момент времени непосредственно доступны один сегмент кода и один сегмент данных – при работе с ними процессор может использовать «короткие» 16-разрядные адреса. Для работы с данными, расположенными в других сегментах, используются так называемые дальние указатели. Дальний указатель (far-указатель) – это двойное слово, представляющее собой полный адрес памяти «сегмент:смещение». Старшее слово задает базовый адрес (начало сегмента), а младшее – смещение от начала сегмента. Для создания дальнего указателя в Borland C используется библиотечная функция MK_FP, описанная в заголовочном файле <dos.h>: void far* MK_FP(unsigned segment, unsigned offset) где segment задает сегмент, а offset указывает смещение. 2.3. Видеоконтроллер VGA Видеоконтроллеры IBM PC/AT и совместимых с ними машин могут работать в двух режимах – текстовом и графическом. В связи с тем, что стандартные процедуры BIOS, предназначенные для вывода на экран текста и графики, выполняются медленно, на практике применяются только процедуры переключения видеорежимов, а все остальные операции выполняются путем прямого взаимодействия с аппаратурой. С точки зрения процессора видеопамять выглядит как одномерный массив, а с точки зрения видеоконтроллера – как матрица. Ось Y и в текстовом, и в графическом режиме направлена сверху вниз. При работе в цветных текстовых режимах контроллер отображает на видеопамять область адресного пространства B8000h–BFFFFh . Начало этой области соответствует левому верхнему углу экрана. Каждому символу соответствует два байта памяти: младший байт кодирует вид символа, а старший байт – цвет символа и цвет фона, на котором будет отображен символ. Старший байт при этом имеет формат, показанный на рис. 2.2.
Рис. 2.2. Формат байта описания цвета символа в текстовом режиме Значения цветовых кодов следующие: 0 – черный, 1 – синий, 2 – зеленый, 3 – бирюзовый, 4 – красный, 5 – фиолетовый, 6 – коричневый, 7 – светло-серый, 8 – темно-серый, 9 – светло-синий, 10 – светло-зеленый, 11 – голубой, 12 – светло-красный, 13 – малиновый, 14 – желтый, 15 – белый. Для кодирования цвета символов можно использовать значения от 0 до 15, а для кодирования фона – только значения от 0 до 7.
9
Порядок отображения содержимого видеопамяти на экран в текстовом режиме показан на рис. 2.3.
Рис. 2.3. Отображение видеопамяти на экран в текстовом режиме Современные видеоконтроллеры позволяют использовать несколько десятков графических видеорежимов с различным разрешением, палитрой цветов и частотой кадров. С точки зрения программиста все видеорежимы различаются количеством отображаемых на экране монитора точек (разрешением экрана по вертикали и горизонтали) и количеством байт, выделенных в видеопамяти для хранения информации о цвете одной точки. Любые манипуляции с графическими изображениями на растровом устройстве в своей основе опираются на одну-единственную операцию – «нарисовать точку». Данная операция тривиальна и заключается в записи кода цвета точки в ячейку видеопамяти, соответствующую положению точки на экране. Существует два основных режима адресации видеопамяти: 1) Устаревший страничный режим, в котором доступ к памяти осуществляется через окно размером в 64 Кбайт, размещенное в первом мегабайте адресного пространства процессора; 2) Современный линейный режим, в котором процессор видит всю видеопамять целиком как участок своей оперативной памяти и может работать с ней непосредственно. Для тренировки мы будем в дальнейшем использовать самый простой режим – восьмиразрядный режим с разрешением 320200 точек и страничной адресацией видеопамяти. В страничном режиме процессор видит участок памяти видеоконтроллера как область размером 64 Кбайт внутри своего адресного пространства (рис. 2.4). Эта область начинается по адресу 0A0000h. Особенность режима с разрешением 320200 точек состоит в том, что в этом случае доступный процессору сегмент видеопамяти соответствует полному экрану, а не отдельному его участку и нет необходимости в переключении видеостраниц. Восьмиразрядный режим позволяет отобразить 256 различных цветовых оттенков. Каждой точке экрана соответствует один байт видеопамяти.
10
Рис. 2.4. Страничная адресация видеопамяти Порядок отображения содержимого видеопамяти на экран в восьмиразрядном графическом режиме показан на рис. 2.5. Информация о точках располагается по строкам, слева направо, сверху вниз. Нулевой адрес видеопамяти соответствует левому верхнему углу экрана. Значения кодов первых шестнадцати оттенков совпадают с теми, которые используются в текстовом режиме.
Рис. 2.5. Отображение видеопамяти на экран в восьмиразрядном графическом режиме При работе с видеопамятью следует избегать записи информации в тот участок памяти, который в данный момент выводится на экран монитора лучом электронно-лучевой трубки (ЭЛТ). Если луч ЭЛТ пересекает область вывода изображения, то на экране одновременно оказываются участки двух кадров изображения – старого и нового; в результате возникают неприятные видеоэффекты: мерцание, разрезание изображения или потеря отдельных его участков. В случае, когда на экран выводится статическое изображение (рисунок, фотография, график), синхронизация не нужна; если же на экране должны отображаться динамические объекты, вывод изображения должен быть синхронизирован с началом обратного хода луча по кадру. Параметры работы видеоконтроллера хранятся в специальных восьмиразрядных ячейках памяти – регистрах видеоконтроллера. Доступ к регистрам осуществляется не через адресное пространство оперативной памяти, а через так называемые порты ввода-вывода. Для синхронизации вывода изображения с началом обратного хода луча по кадру используется так называемый регистр состояния видеоконтроллера, доступный для чтения через порт 3DAh. Синхронизация осуществляется путем проверки значения третьего разряда этого регистра, который содержит признак обратного хода луча по кадру: 0 – прямой ход, 1 – обратный ход луча. 11
Пример функции синхронизации вывода изображения с частотой кадров: void WaitSync() { // Ожидание начала обратного хода луча по кадру while(inportb(0x3DA)&0x8); // Ожидание окончания обратного хода луча по кадру while(!(inportb(0x3DA)&0x8)); }
2.4. Вывод спрайтов на экран монитора Самый простой способ создания на экране иллюзии движения – спрайтовая анимация. Движение объекта в этом случае отображается путем вывода на экран последовательности картинок, отображающих различные фазы указанного движения. В общем случае для каждой фазы выполняемого объектом движения должен быть задан рисунок, изображающий объект в том состоянии, которое соответствует данной фазе движения, и маска прозрачности изображения, которая показывает, какие точки рисунка должны быть отображены поверх фона. И рисунок объекта, и маска представляют собой матрицы чисел одинакового размера MN. Каждая ячейка матрицы рисунка содержит код цвета соответствующей точки рисунка, а вывод спрайта на экран осуществляется путем простого копирования этой матрицы из оперативной памяти компьютера в видеопамять. Если не использовать маску, то все точки матрицы будут выведены на экран и получится прямоугольное изображение. Для того, чтобы можно было выводить на экран рисунки сложной формы, применяют маску прозрачности, каждая ячейка которой содержит числовой код, показывающий, выводить ли в данном месте точку рисунка или сохранить фон (например, 0 – сохранить фон, 1 – вывести точку). При использовании маски прозрачности вывод изображения на экран усложняется: прежде чем копировать точку из матрицы рисунка на экран, процессор должен числовое значение в соответствующей позиции маски (если оно равно нулю, точка пропускается). Применение маски прозрачности удваивает расход оперативной памяти, поэтому рисунок объекта часто совмещают с маской прозрачности, используя некоторые числовые коды для обозначения прозрачных участков изображения (например, предполагают, что код 0 соответствует прозрачному пикселю). Совмещение изображения с маской позволяет ускорить его обработку – процессору нужно считывать данные только из одной области памяти. Полученную в результате совмещения объединенную матрицу часто называют маской спрайта или просто спрайтом. При использовании спрайтовой анимации порядок вывода движущегося изображения следующий: 1) вычислить текущее местоположение изображения движущегося объекта в видеопамяти; 2) сохранить участок фона, поверх которого будет выводиться изображение; 3) вывести изображение объекта; 4) ожидать начала обратного хода луча по кадру; 5) восстановить участок фона, стирая тем самым изображение движущегося объекта. Данные операции повторяются при выводе каждого кадра. Старое изображение объекта каждый раз стирается, после чего объект выводится на новом месте, создавая иллюзию движения.
1)
2)
2.5. Упражнения Упражнение 1. Требуется выполнить следующую последовательность действий: Ввести, откомпилировать и запустить программу, которая выполняет очистку экрана и вывод текстовых символов путем непосредственного обращения к видеопамяти. Текст программы приведен в листинге 2.1. Изменить программу таким образом, чтобы вместо очистки экрана выполнялась раскраска фона в виде шахматной доски с синими и зелеными клетками (использовать по два знакоместа на каждую клетку, чтобы клетки были квадратными).
12
3)
Вывести «бегущий ноль». При запуске в левом верхнем углу экрана выводится символ „0‟. Далее при каждом нажатии на клавишу Enter символ должен перемещаться в следующую колонку, а при достижении конца строки – в следующую строку. Работа программы должна прекращаться по достижении конца третьей строки.
Листинг 2.1. Программа, которая выполняет очистку экрана и вывод текстовых символов путем непосредственного обращения к видеопамяти. #include #include <dos.h> // Создание указателя на видеопамять unsigned char far *screen = (unsigned char *) MK_FP(0xB800, 0); // Очистка экрана void ClearScreen() { int i; for(i=0; i // Создание указателя на видеопамять unsigned char far *screen = (unsigned char *) MK_FP(0xA000, 0); // Установка видеорежима (параметр Mode – код видеорежима) void SetMode(int Mode) { union REGS regs; regs.h.ah = 0; regs.h.al = Mode; int86(0x10, ®s, ®s); } // Очистка экрана void ClearScreen() { unsigned i; for(i=0; i #include void main(void) { char buffer[256]; getcwd(buffer, 256); printf("Текущий каталог: %s\n",buffer); }
15
Функция mkdir создает новый каталог с заданным именем. При успешном завершении функция возвращает 0, при возникновении ошибки – -1. Синтаксис: int mkdir(const char *path);
Пример: mkdir("DIRNAME");
Функция rmdir удаляет каталог, маршрут к которому указан в path (каталог не должен быть текущим или корневым). Функция возвращает 0, если каталог был успешно удален, иначе – значение -1. Синтаксис: int rmdir(const char *path);
3.3. Поиск файлов Функция findfirst производит в каталоге диска поиск первого файла, соответствующего заданному шаблону. При успешном завершении поиска функция возвращает 0, иначе – -1. Синтаксис: int findfirst(char * pathname, struct ffblk * ffblk, int attrib);
Параметр pathname представляет собой строку, содержащую имя диска, маршрут поиска и имя файла, которое содержать шаблоны (? и *). Если соответствующий файл найден, структура ffblk заполняется информацией о файле. Структура определена следующим образом: struct ffblk { char ff_reserved[21]; char ff_attrib; int ff_ftime; int ff_fdate; long ff_fsize; char ff_fname[13]; };
// // // // // //
зарезервировано атрибуты время дата размер имя файла
Параметр attrib – это байт атрибута файла, который может задаваться при помощи констант: FA_RDONLY – только для чтения, FA_HIDDEN – скрытый файл, FA_SYSTEM – системный файл, FA_LABEL – метка тома, FA_DIREC – каталог, FA_ARCH – архив. Функция findnext используется для выборки последовательности файлов, соответствующих параметру pathname, задаваемому функцией findfirst. При успешном завершении поиска файла функция возвращает значение 0, в противном случае – значение -1. Синтаксис: int fidtnext(struct ffblk * ffblk);
Параметр ffblk – это тот же самый блок, который заполняется при вызове функции findfirst. Данный блок содержит всю необходимую информацию для продолжения поиска. При каждом вызове функции findnext будет возвращаться одно имя файла до тех пор, пока не закончатся файлы, соответствующие параметру pathname. Пример: #include <stdio.h> #include void main(void) { struct ffblk ffblk; int done; printf("Листинг текущего каталога:\n"); done = findfirst("*.*",&ffblk,0); while (!done) { printf("%s\n", ffblk.ff_name); done = findnext(&ffblk); } }
16
3.4. Функции общего назначения для работы с файлами Прототипы функции, предназначенных для выполнения операций с файлами, заданы в заголовочном файле stdio.h. Функция fopen открывает файл, именованный параметром filename и связывает его с соответствующим потоком stream. При успешном завершении fopen возвращает указатель на открытый поток stream, в случае ошибки – значение NULL. Синтаксис: FILE * fopen(char * filename, char * type);
Строка type, используемая в функции fopen может принимать следующие значения: r – открыть файл для чтения; w – создать файл для записи; а – открыть файл для продолжения записи с конца файла (если файл не существует, он создается); r+ – открыть существующий файл для обновления (чтения и записи); w+ – создать новый файл с возможностью изменения (перезаписи данных); a+ – открыть файл для продолжения записи (с возможностью перезаписи данных). Если данный файл открывается или создается в текстовом режиме, вы можете приписать символ t к значению параметра type (rt, w+t, и т.д.); аналогично, для спецификации двоичного режима вы можете к значению type добавить символ b (wb, a+b, и т.д.). При открытии файла в режиме обновления, над результирующим потоком stream могут быть выполнены как операции ввода, так и вывода. Тем не менее вывод не может следовать непосредственно за вводом и наоборот без вмешательства функций fseek или rewind. Функция fclose закрывает указанный поток stream. Буфера, связанные с потоком, перед закрытием сбрасываются и освобождаются. При успешном завершении функция возвращает 0, если были обнаружены ошибки – значение EOF. Синтаксис: int fclose (FILE * stream);
Функция remove удаляет файл, имя которого определяется параметром filename (строка с именем файла может включать маршрут). Если файл был открыт, его следует закрыть. При успешном завершении remove возвращает 0, при ошибке – -1. Синтаксис: int remove(const char *filename);
Функция rename изменяет имя файла с oldname на newname. Функцию rename можно использовать для перемещения файла из одного каталога в другой. При успешном переименовании файла функция возвращает 0, при ошибке – -1. Синтаксис: int rename(const char *oldname, const char *newname);
Функция feof является макрокомандой, которая производит проверку данного потока stream на признак конца файла EOF. Функция возвращает ненулевое значение, если при последней операции ввода из потока stream был обнаружен конец файла, и 0 в противном случае. Синтаксис: int feof(FILE * stream);
Функция fflush записывает в файл содержимое буфера, связанного с потоком stream, если он был открыт на вывод. В случае успешного завершения возвращает 0, при ошибке – EOF. Синтаксис: int fflush(FILE * stream);
3.5. Функции для работы с текстовыми файлами Функция fgetc возвращает следующий символ из указанного входного потока stream. При успешном завершении функция возвращает символ, преобразованный к типу int, при обнаружении конца файла – EOF. Синтаксис: int fgetc(FILE * stream);
Функция fgets считывает из потока stream строку символов и помещает ее в s. Ввод завершается после ввода n–1 символа или при вводе символа перевода строки. При успешном завершении функция возвращает указатель на s, при ошибке или конце файла – NULL. Синтаксис: char * fgets(char s, int n, FILE *stream);
Функция fprintf выводит данные в поток stream. Функция возвращает число выведенных байт, а при появлении ошибки – значение EOF. Синтаксис: int fprintf(FILE * stream, const char *format [,argument,...]);
17
Пример: fprintf(stream,"%d %c %f",i,c,f);
Функция fputc выводит символ с в поток stream. В случае успеха возвращается символ с, в случае ошибки – EOF. Синтаксис: int fputc(int c, FILE * stream);
Функция fputs копирует строку в поток stream. Она не добавляет в конец строки символ перехода на новую строку. При успешном завершении fputs возвращает последний выведенный символ, в случае ошибки – EOF. Синтаксис: int fputs(char * string, FILE * stream);
Пример вызова функции: fputs("Тестовый пример",stdout);
Функция fscanf сканирует посимвольно набор вводимых полей, считывая их из потока, а затем каждое поле из потока форматируется в соответствии со спецификацией формата, которая передается fscanf в виде указателя на строку format. Полученные значения fscanf запоминает в аргументах, передаваемых после параметра format. Функция возвращает количество успешно прочитанных входных полей. Если fscanf делает попытку чтения в конце файла, то возвращается EOF. Если не было записано ни одного поля, возвращается значение 0. Синтаксис: int fscanf(FILE * stream, char * format[, adress,...]);
Пример вызова функции: fscanf(stdin,"%d",&i);
Пример использования функций fopen, fgetc, fputc, feof и fclose: // Программа создает дубликат файла AUTOEXEC.BAT #include <stdio.h> int main(void) { FILE *in, *out; if((in = fopen("AUTOEXEC.BAT","rt"))==NULL) return(1); if((out = fopen("AUTOEXEC.BAK","wt"))==NULL) return(1); while(!feof(in)) fputc(fgetc(in), out); fclose(in); fclose(out); return 0; }
3.6. Функции для работы с двоичными файлами Функция fread считывает n элементов данных, каждый длиной size байтов, из потока stream в блок с адресной ссылкой ptr. Функция возвращает количество прочитанных элементов данных. Синтаксис size_t fread(void *ptr, size_t size, size_t n, FILE * stream);
Функция fseek устанавливает адресный указатель файла, соответствующий потоку stream, в новую позицию, которая расположена по смещению offset относительно места в файле, определяемого параметром fromwhere. Параметр fromwhere может иметь одно из трех значений: 0 (начало файла), 1 (текущая позиция указателя) или 2 (конец файла). Функция возвращает значение 0, если указатель файла успешно перемещен, и ненулевое значение в случае ошибки. Синтаксис: int fseek(FILE * stream, long offset, int fromwhere);
Пример – перевести указатель в конец файла: fseek(stream, 0L, 2);
Функция ftell возвращает положение указателя текущей позиции файла, связанного с потоком stream. При успешном завершении функция возвращает положение указателя, при ошибке – значение -1L. Синтаксис long int ftell(FILE *stream);
Функция fwrite добавляет n элементов данных (каждый элемент имеет размер size байт) в указанный поток. Данные записываются из ptr (ptr должен быть объявлен как указатель на
18
некоторый объект). Функция возвращает число выведенных элементов. Общее число выведенных байт равно n*size. Синтаксис: size_t fwrite(void * ptr, size_t size, size_t n, FILE * stream);
Функция rewind устанавливает указатель в начало потока. Синтаксис: int rewind(FILE *stream);
Пример: #include<string.h> #include<stdio.h> int main(void) { FILE *stream; char msg[] = "Тестовый пример"; char buf[20]; if((stream = fopen("DUMMY.FIL","w+")) == NULL) return 1; fwrite(msg,strlen(msg)+1,1,stream); // вывести данные fseek(stream,SEEK_SET,0); // перейти на начало файла fread(buf,strlen(msg)+1,1,stream); // прочитать данные printf("%s\n",buf); fclose(stream); return 0; }
1)
2) 3) 4) 5)
6)
7)
3.7. Упражнения Требуется составить программы, которые будут выполнять следующие действия: Ввести текст с клавиатуры (с помощью функции gets), сохраняя каждую введенную строку в файле text.txt с помощью функции fputs. Работа продолжается, пока не будет введена пустая строка. Вывести на экран текст из файла text.txt (чтение из файла производить с помощью функции fgets, вывод строк на экран – с помощью функции puts). С помощью функций fseek и ftell определить размер файла text.txt в байтах и вывести полученное значение на экран. Сформировать массив из 20 элементов типа int, содержащий значения от 1 до 20, и сохранить его в текстовом файле numbers.txt. Каждое число размещается в отдельной строке. Ввести с клавиатуры значение N типа int. Сформировать массив из N элементов типа int, содержащий значения от 1 до N, и сохранить его в двоичном файле numbers.bin (вначале в файл записывается значение N, а затем – элементы массива). Прочитать массив чисел из двоичного файла numbers.bin (вначале считывается количество элементов N, а затем производится считывание элементов массива), отобразить массив на экране, а затем удалить файл numbers.bin. Написать программу, которая выводит в текстовый файл dir.txt следующую информацию: имя активного дисковода, полное имя маршрута для текущего каталога и список файлов в текущем каталоге. Каждую программу сохранять в отдельном файле.
19
4. Лабораторная работа №4 Работа с структурами данных на примере файла BMP 4.1. Цель лабораторной работы Целью данной лабораторной работы является изучение современных графических видеорежимов контроллера SVGA и правил работы со структурами данных. В качестве примера рассматривается вывод изображения из файла в формате BMP на экран. В процессе работы требуется преобразовать информацию из одной формы представления, принятой для хранения в BMP-файлах, в другую, используемую для вывода на экран. Отчет о лабораторной работе не оформляется. Прием задания производится непосредственно на компьютере по предъявлению работающей, полностью отлаженной программы. 4.2. Организация видеопамяти в графическом режиме TrueColor Структура таблицы данных файла BMP соответствует организации памяти видеоконтроллера в режиме TrueColor24. В режимах TrueColor для кодирования каждого из трех основных цветов используется по одному байту (рис. 4.1).
Рис. 4.1. Кодирование цвета пикселя в режиме TrueColor При выводе кода цвета точки в видеопамять первым передается младший байт, соответствующий синей компоненте. Старший байт в 32-битовом режиме не используется – он добавлен только для выравнивания адресов памяти на границу двойного слова и должен иметь значение 0. Пример организации видеопамяти в режиме TrueColor32 показан на рис. 4.2.
Рис. 4.2. Отображение видеопамяти на экран в режиме TrueColor32 1024768 Существует два режима работы с видеопамятью – линейная адресация и передача данных через буфер кадра. При работе в MS DOS можно использовать только режим адресации через буфер. В этом режиме процессор видит участок памяти видеоконтроллера как область размером 64 Кбайт с начальным адресом 0A0000h (рис. 4.3).
20
Рис. 4.3. Организация доступа к видеопамяти в оконном режиме Обмен данными между процессором и видеопамятью при адресации через буфер кадра осуществляется заметно медленнее, чем при линейной адресации, так как необходимо постоянно контролировать пересечение границ блока и производить при необходимости переключение на следующий блок. В видеорежимах с длиной строки в байтах, не равной 2N, границы блоков оказываются неровными – конец блока может находиться в любом произвольном месте строки экрана. Для упрощения работы с памятью можно изменить логическую длину строки, увеличив ее до ближайшего значения 2N, превышающего физическую ширину экрана. Такая операция приводит границы сегментов к прямоугольной форме (рис. 4.4).
Рис. 4.4. Реорганизация видеопамяти путем изменения логической длины строки Используемый в лабораторной работе режим TrueColor32 1024768 автоматически обеспечивает прямоугольные границы сегментов. Каждый сегмент отображается в виде узкой полосы шириной 1024 и высотой 16 точек. Всего на экране помещается 48 таких полос.
21
4.3. Функции VESA BIOS Функции VESA BIOS были введены ассоциацией VESA с целью обеспечения использования новых возможностей современных видеоконтроллеров в операционной системе MS DOS. Обращение к VESA BIOS выполняется по прерыванию 0x10 с номером функции 0x4F. Передача данных производится через регистры процессора. После выполнения вызова в регистре AX будет возвращен код результата. В данной работе используются две подфункции: установка режима и переключение окон. Подфункция 0x02 устанавливает видеорежим с заданным номером. Перед вызовом прерывания 0x10 требуется занести в регистр АХ код 0x4F02, в BX – код видеорежима, который имеет следующий формат: биты 0–8 – номер режима; биты 9–13 – зарезервированы (имеют значение 0); бит 14 – режим адресации памяти (0 – оконный, 1 – линейный); бит 15 – очистка видеопамяти (0 – очищать, 1 – не очищать). Обычно бит 15 имеет значение 0 – при переключении режима производится очистка памяти. Номера часто используемых режимов стандартизированы (табл. 4.1). В лабораторной работе используется режим номер 0x118. Подфункция 0x05 предназначена для управления отображением видеопамяти на адресное пространство процессора при использовании оконного режима. Перед вызовом прерывания требуется занести в регистр АХ значение 0x4F05, в BH – код операции (0 – установить заданное окно), в BL – значение 0, в DX – номер окна. Таблица 4.1. Стандартизированные номера графических режимов Номер режима Разрешение Число Бит на точку оттенков 0x100 640x400 256 8 0x101 640x480 256 8 0x102 800x600 16 4 0x103 800x600 256 8 0x104 1024x768 16 4 0x105 1024x768 256 8 0x106 1280x1024 16 4 0x107 1280x1024 256 8 0x10D 320x200 32К 1:5:5:5 0x10E 320x200 64К 5:6:5 0x10F 320x200 16М 8:8:8 или 8:8:8:8 0x110 640x480 32К 1:5:5:5 0x111 640x480 64К 5:6:5 0x112 640x480 16М 8:8:8 или 8:8:8:8 0x113 800x600 32К 1:5:5:5 0x114 800x600 64К 5:6:5 0x115 800x600 16М 8:8:8 или 8:8:8:8 0x116 1024x768 32К 1:5:5:5 0x117 1024x768 64К 5:6:5 0x118 1024x768 16М 8:8:8 или 8:8:8:8 0x119 1280x1024 32К 1:5:5:5 0x11A 1280x1024 64К 5:6:5 0x11B 1280x1024 16М 8:8:8 или 8:8:8:8
22
4.4. Формат BMP для несжатого RGB-изображения Формат BMP для несжатого изображения – самый простой из всех форматов, предназначенных для хранения фотографий. Он воспринимается большинством графических редакторов, но порождает файлы гигантских размеров, поскольку одна точка изображения кодируется тремя байтами данных, по байту на каждую из цветовых компонент. Файл BMP состоит из двух частей: заголовка файла и данных изображения. Формат заголовка файла описан в таблице 4.2. Таблица 4.2. Формат заголовка файла для несжатого RGB-изображения Смещение Размер Значение Описание 0x00 WORD 0x4D42 (“BM”) Признак файла BMP 0x02 DWORD Полный размер файла в байтах 3LH+54 0x06 WORD 0 Не используется 0x08 WORD 0 Не используется 0x0A DWORD 54 (0x36) Смещение области данных от начала файла 0x0E DWORD 40 (0x28) Размер описателя изображения 0x12 DWORD L Ширина изображения в пикселях 0x16 DWORD H Высота изображения в пикселях 0x1A WORD 1 Число битовых плоскостей 0x1C WORD 24 (0x18) Число битов на пиксель 0x1E DWORD 0 Метод сжатия 0x22 DWORD Размер изображения в байтах 3LH 0x26 DWORD 0 Разрешение по горизонтали в пикселях на метр 0x2A DWORD 0 Разрешение по вертикали в пикселях на метр 0x2E DWORD 0 Число оттенков в растровом изображении 0x32 DWORD 0 Число важных цветов изображения Соответствующая структура данных на языке Си имеет следующий вид: // Структура заголовка файла BMP struct TagBMPHeader { unsigned BMPSign; // unsigned long FileSize; // unsigned Res1; // unsigned Res2; // unsigned long DataShift; // unsigned long HeaderSize; // unsigned long Width; // unsigned long Height; // unsigned Planes; // unsigned BitCount; // unsigned long Compression; // unsigned long SizeImage; // unsigned long XPels; // unsigned long YPels; // unsigned long ClrUsed; // unsigned long ClgImportant; // } BMPHeader;
Признак файла BMP Полный размер файла Не используется Не используется Смещение области данных Размер описателя изображения Ширина изображения в пикселях Высота изображения в пикселях Число битовых плоскостей Число битов на пиксель Метод сжатия Размер изображения в байтах Разрешение по горизонтали Разрешение по вертикали Число оттенков Число важных цветов
Область данных изображения следует за заголовком файла и имеет смещение 0x36 от начала файла. Неприятной особенностью формата BMP является перевернутый по отношению к экрану монитора порядок записи строк в файл – первой записывается нижняя строка изображения. Другая особенность – каждая строка дополняется пустыми (не содержащими информации)
23
байтами для выравнивания на границу двойного слова, чтобы длина строки в байтах была кратна 4. Пример размещения данных для изображения размером 4х2 показан на рис. 4.5. Нижняя строка
Верхняя строка
С7 С5 С3 С1
З7 З5 З3 З1
К7 К5 К3 К1
С8 С6 С4 С2
З8 З6 З4 З2
К8 К6 К4 К2
Х Х Х Х
Х Х Х Х
Рис. 4.5. Порядок размещения строк изображения в файле BMP 4.5. Параметры функции main В лабораторной работе потребуется изменить текст программы таким образом, чтобы можно было при запуске передавать имя BMP-файла в виде параметра. Параметры, передаваемые программе, выступают в роли аргументов функции main. Параметр argc имеет тип int и определяет число строк-параметров. Параметр argv имеет тип char*[] и является массивом указателей на строки параметров программы. Первая строка argv содержит полное имя программы (включая путь доступа). Пример программы, которая печатает все переданные аргументы: #include <stdio.h> void main(int argc, char *argv[]) { int i; for(i=0; i<argc; i++) printf("%s\n", argv[i]); }
1) 2)
3) 4)
5) 6)
7)
8) 9)
4.6. Упражнения Требуется выполнить следующую последовательность действий: Ввести, откомпилировать и запустить программу, приведенную на листинге 4.1. Добавить в программу функцию, рисующую горизонтальные отрезки заданного цвета с заданной координатой Y от левого до правого края экрана, а также функцию, рисующую вертикальные отрезки заданного цвета с заданной координатой X от верхнего края экрана до нижнего. С помощью добавленных функций разлиновать экран линиями белого цвета, чтобы получить клетки 3232. Добавить описатель структуры заголовка файла BMP. В главном модуле отрыть для чтения двоичный файл rgb1.bmp. Прочитать из файла заголовок. Добавить в программу массив из 4096 элементов типа unsigned char для промежуточного хранения строки изображения. Используя информацию о ширине и высоте изображения, построчно читать и выводить на экран данные из файла. Добавить указатель для работы с видеопамятью как c массивом типа unsigned long, чтобы можно было передавать точку изображения за одну операцию. Добавить функцию, переворачивающую изображение слева направо. Перевернуть изображение, ожидать нажатия любой клавиши, вернуть изображение в исходное состояние, ожидать нажатия клавиши. Добавить функцию, переворачивающую изображение сверху вниз. Перевернуть изображение, ожидать нажатия клавиши, вернуть в исходное состояние, ожидать нажатия клавиши. Добавить функцию, преобразующую изображение в черно-белое (с 256 градациями яркости). Изменить программу таким образом, чтобы имя файла передавалось из командной строки через параметры функции main(). Ниже приведен пример программы, которая работает в режиме TrueColor32 1024768.
24
Листинг 4.1. Программа, которая выполняет заливку экрана синим цветом в графическом режиме с разрешением 320200 точек. #include <stdio.h> #include #include <dos.h> // Создание указателя на видеопамять unsigned char far *screen = (unsigned char *) MK_FP(0xA000, 0); // Установка режима TrueColor32 с разрешением 1024x768 void SetTrueColorMode(void) { union REGS regs; regs.x.ax = 0x4F02; regs.x.bx = 0x118; int86(0x10, ®s, ®s); } // Восстановление текстового режима void SetTextMode(void) { union REGS regs; regs.h.ah = 0; regs.h.al = 3; int86(0x10, ®s, ®s); } // Переключение окон (параметр Page – номер полосы) void SetPage(unsigned Page) { union REGS regs; regs.x.ax = 0x4F05; regs.x.bx = 0; regs.x.dx = Page; int86(0x10, ®s, ®s); } // Заливка экрана заданным цветом (параметры: B – яркость синей, // G - яркость зеленой, R – яркость красной компоненты) void FillScreen(unsigned char B, unsigned char G, unsigned char R) { unsigned i,j; for(i=0; i