- •Директивы препроцессора
- •Определяющие директивы Символические константы
- •Void main(void)
- •Void main(void)
- •Void main(void)
- •Void main(void)
- •Void main(void)
- •Void main(void)
- •Void main(void)
- •Void main(void)
- •Void main(void)
- •Void main(void)
- •Void main(void)
- •Void main(void)
- •Void main(void)
- •Void main(void)
- •Void main(void)
- •Void main(void)
Void main(void)
{
#ifdef TRACE
puts("функция main\n");
#endif
getline();
}
void getline(void)
{
#ifdef TRACE
puts("функция getline");
#else
puts("hello!");
#endif
return;
}
/* текст программы после обработки препроцессором, если */
/* есть #define TRACE нет #define TRACE */
/* содержимое файла stdio.h */ /* содержимое stdio.h */
void getline(void); void getline(void);
void main(void) void main(void)
{ {
puts("функция main\n"); getline();
getline(); }
} void getline(void)
void getline(void) {
{ puts("hello!");
puts("функция getline"); return;
return; }
}
Пример 9.
/* в зависимости от значения MAX получаем три разных загрузочных модуля (генератор программ) текст программы до обработки препроцессором */
#define MAX 3
#include<stdio.h>
Void main(void)
{
#if MAX==5
puts("MAX=5");
#elif MAX==3
puts("MAX=3");
#else
puts("MAX другое");
#endif
}
/* в исходном модуле */
/* MAX равно 3 MAX равно 5 MAX равно 10 */
/* текст программы после обработки препроцессором */
/* содержимое файла stdio.h */
void main(void) void main(void) void main(void)
{ { {
puts("MAX=3"); puts("MAX=5"); puts("MAX другое");
} } }
Примечание. Текст любого системного заголовочного файла может служить примером использования условной компиляции.
ЗАДАНИЕ
Выполнить следующие варианты заданий, используя как можно больше директив препроцессора:
Вариант 1
Ваша программа содержит функцию. Определение функции находится в отдельном файле и чтобы получить загрузочный модуль в Турбо Си++ необходимо составить файл проекта. Напишите текст программы так, чтобы выполнить ее обычным способом.
Вариант 2
Напишите программу, внешне напоминающую вам Паскаль, но которую обработает компилятор языка Си.
Вариант 3 ___сделать это_!!!!!!!!!
Составьте небольшую произвольную программу. Включите строки для отладочного выполнения программы, которые не должны присутствовать при выполнении программы в рабочем режиме. Выполните программу в отладочном и рабочем режимах.
Вариант 4
Определить макрофункцию вычисления куба числа и включить ее в состав программы так, чтобы ею могли воспользоваться и другие программы. Вычислить кубы следующих чисел:
х, х+2, 5.6х+3, -3.
Вариант 5
Определить макрофункцию для вывода на экран одного целого числа и включить ее в состав программы так, чтобы ею могли воспользоваться и другие программы. Вывести на экран числа х, х-6, 5х, abs(-5).
Вариант 6
Определить и использовать в программе макрофункцию обнуление любого одномерного массива произвольной длины и включить ее в состав программы так, чтобы ею могли воспользоваться и другие программы.
Вариант 7
Напишите два фрагмента программы. Напишите программу main так, чтобы при выборе одной модели памяти выполнялся один фрагмент программы, а при другой - второй.
Оформить фрагменты программы так, чтобы ими могли воспользоваться и другие программы.
Вариант 8
Программа обрабатывает одномерный массив и должна вы-
полняться двояким образом:
если размер массива больше 10, то память для массива выделить динамически и к элементам массива обращаться через указатели;
если размер массива не больше 10, то память для массива выделить до начала выполнения программы и к элементам массива обращаться по имени.
Вариант 9
Программа обрабатывает матрицу и должна выполняться двояким образом:
если в программе есть константы, определяющие количество строк и столбцов, то память для матрицы выделить динамически и к элементам массива обращаться через указатели;
если хотя бы одной константы нет, память для массива
выделить до начала выполнения программы и к элементам массива обращаться по имени.
Вариант 10
Написать фрагмент программы, который можно включать в состав любой функции. В результате выполнения этого фрагмента должна выдаваться на экран следующая информация:
файл <полное имя файла> содержит <количество> строк и выполняется <дата> с использованием <имя модели памяти>. Каково местоположение фрагмента в функции?
/* ЛАБОРАТОРНАЯ РАБОТА 2 (IN_OUT)
ФУНКЦИИ ВВОДА И ВЫВОДА ВЕРХНЕГО УРОВНЯ
Функции ввода и вывода в стандартной библиотеке Си позволяют читать данные с клавиатуры, диска или порта ввода-вывода и выводить результат на терминал, диск или порт ввода-вывода.
Функции ввода/вывода делятся на группы:
1. ввод/вывод верхнего уровня
2. ввод/вывод системного уровня
3. ввод/вывод для консольного терминала
4. ввод/вывод через порт.
Для пользователя файл, открытый на верхнем уровне, представляется как последовательность считываемых или записываемых байтов. Чтобы отразить эту особенность, используется понятие "поток" (stream).
Функции ввода/вывода работают с буферизацией. Обмен информацией происходит не между программой и файлом, а между программой и буфером, расположенным в оперативной памяти.
Буферизация ускоряет работу программы из-за уменьшения количества обращений к внешним устройствам.
Чтобы получить доступ к файлу, необходимо связать его с соответствующей структурой типа FILE, объявленной в stdio.h и содержащей разнообразную информацию о файле. Эта операция называется открытием файла и осуществляется с помощью функции fopen, которая в качестве результата возвращает указатель на структуру FILE - указатель файла. Указатель файла в дальнейшем используется функциями для ввода/вывода информации в файл.
Указатель файла позиционируется в соответствии с открытием потока: если поток открыт для чтения - на начало файла, если для дозаписи - на конец файла. Указатель файла изменяется в соответствии с операцией записи или чтения.
После окончания ввода/вывода поток необходимо закрыть с помощью функции fclose или fcloseall, после чего указатель файла можно использовать для последующего открытия файла.
Потоки бывают текстовые или двоичные (по умолчанию - текстовые). При вводе текстового потока система Турбо Си преобразует символы возврат коретки и перевод строки в символ перевода строки, а при выводе текстового потока в среду операционной системы происходит обратное преобразование.
При вводе/выводе двоичного потока никаких преобразований не происходит.
При выполнении любой программы автоматически открываются пять стандартных потоков, имеющих следующие указатели файлов: stdin - поток ввода, stdout - поток вывода, stderr - поток вывода для сообщений об ошибках ( для вывода в поток stderr используется функция perror ), stdaux - последовательный порт и stdprn - устройство печати. Первые три потока по умолчанию связываются с консольным терминалом. Имена указателей стандартных потоков ввода/вывода могут указываться в функциях ввода/вывода.
Для переопределения стандартных потоков используется функция freopen.
Прототипы функций ввода/вывода описаны в stdio.h, и там же объявлен ряд макроопределений, в том числе NULL - нулевой байт, EOF - символ конца файла, BUFSIZ - размер буфера.
Далее приводятся описания прототипов функций с кратким пояснением.
Доступ к файлу
FILE * fopen(char *pathname, char *type);
функция открывает файл (имя задает первый аргумент) для
(второй аргумент):
"r" - чтения существующего файла
"w" - записи (перезаписи) файла
"a" - записи (дозаписи) файла
"r+" - чтения и записи существующего файла
"w+" - чтения и записи (перезаписи) файла
"a+" - чтения и записи (дозаписи) файла.
В конец строки записывается t - текстовый режим или b - дво-
ичный режим. Например: "rt" , "w+b".
Возврат при ошибке: NULL.
Закрытие потока
int fclose(FILE *stream);
int fcloseall(void);
Возврат при ошибке: EOF.
Конец файла
int feof(FILE *stream);
Возврат: 0 - не конец файла, иначе - конец файла.
Данные в файле могут быть организованы как:
1. непрерывный поток символов
2. последовательность строк переменной длины
3. форматированные поля, разделенные определенным символом
4. последовательность записей фиксированной длины.
В соответствии с этим разделим функции ввода/вывода верхнего уровня на группы.
Ввод/вывод символа
int getchar(void); - ввод из stdin
int putchar(int); - вывод в stdout
int fgetc(FILE *stream); - ввод из потока
int fputc(int c, FILE *stream); - вывод в поток
int getc(FILE *stream); - ввод из потока
int putc(int c,FILE *stream); - вывод в поток
int ungetc(char c, FILE *stream); - возврат введенного символа в поток.
Возврат при ошибке: EOF.
Построчный ввод/вывод
char * fgets(char *s,int n, FILE *stream); - cтрока из входного потока помещается в s (не более n-1 символа).
char * gets(char *s); - строка из stdin помещается в s.Возврат при ошибке: NULL.
int fputs(char *s, FILE *stream); - cтрока помещается в вы ходной поток.
int puts(char *s); - cтрока помещается в stdout.
Возврат при ошибке: EOF.
Форматный ввод/вывод
int fprintf(FILE *stream,<строка формата>,<список имен>); форматный вывод в поток.
int fscanf(FILE *stream,<строка формата>,<список адресов>); форматный ввод из потока.
int printf(<строка формата>,<список имен>); форматный вывод в stdout.
int scanf(<строка формата>,<список адресов>); форматный ввод из stdin. Ввод/вывод записей
int fread(void *bufer, int size, int count, FILE *stream); функция читает count элементов длины size из входного потока и помещает в bufer.
int fwrite(char *bufer, int size, int count, FILE *stream); функция дописывает count элементов длины size из области bufer в поток. Как правило, эти функции используются для ввода/вывода массивов и структур.
Внутреннее преобразование данных
int sprintf(char *s,<строка формата>,<список имен> ); вывод данных в строку.
int sscanf(char *s,<строка формата>,<список адресов>); ввод из строки по адресам.
Возврат при ошибке: EOF.
Прямой доступ к файлу
int fseek(FILE *stream, long offset, int origin); - функция перемещает указатель файла на offset позиций относительно начала файла, если origin равно 0, текущей позиции, если origin равно 1, конца файла, если origin равно 2. Если значение offset положительно - движение вперед, иначедвижение назад. Возврат при ошибке: не нуль.
Текущая позиция в файле
long ftell(FILE *stream); - возвращает номер текущей позиции от начала файла.
Пример 1.
/* создание копии autoexec.bat в autoexec.bak */
#include<stdio.h>
void main (void)
{
/* указатели входного и выходного потоков */
FILE *in, *out;
/* открытие входного потока */
if((in=fopen("\\autoexec.bat","rt"))==NULL)
{
fprintf(stderr, "cannot open input file\n");
exit(1);
}
/* открытие выходного потока */
if((out=fopen("autoexec.bak","wt"))==NULL)
{
fprintf(stderr, "cannot open output file\n");
exit(1);
}
/* символ из входного потока записать в выходной */
while(!feof(in))
fputc(fgetc(in), out);
/* закрытие потоков */
fclose(in);
fclose(out);
}
Пример 2.
/* внутреннее преобразование данных - из строки в float */
#include<stdio.h>
void main (void)
{
char s[20];
float chislo;
puts("\nввод числа");
gets(s);
sscanf(s,"%f",&chislo);
printf("полученное число %f\n", chislo);
}
Пример 3.
/* прямой доступ к файлу - печать 21-го символа из ес.bat */
/* в результате печатается n */
#include<stdio.h>
void main (void)
{
FILE *in, *out;
if((in=fopen("ec.bat","rt"))==NULL)
{
fprintf(stderr, "cannot open input file\n");
exit(1);
}
/* сместить указатель файла на 20 позиций от начала файла */
fseek(in,20L,0);
fprintf(stdout,"21-ый символ равен %c\n", fgetc(in));
}
/* содержимое ec.bat */
rrrrrrrrrrrrrrrrrrrdnyyyy
/* Порядок выполнения задания
1. Получить задание у преподавателя.
2. Проанализировать задачу.
3. Определить круг используемых функций.
4. Изучить необходимые функции.
5. Написать текст программы.
6. Разработать контрольный пример.
7. Провести отладку программы.
8. Выполнить программу.
9. Проверить правильность полученного результата.
/* ЗАДАНИЕ
Вариант 1
Даны два файла. Создать третий файл , объединяющий два файла в один. Имена файлов вводить по запросу.
Вариант 2
Дан файл. Имя файла не содержит расширения и задается с терминала по запросу. Создать копию файла. Имя файла-копии отличается от исходного тем, что имеет расширение bak. Использовать функцию strcat.
Вариант 3
Дан файл. Подсчитать количество слов в файле, начинающихся на букву а.
Вариант 4
Дан файл. Создать результирующий так, что он содержит каждый n-ый символ исходного файла, где n задается по запросу.
Вариант 5
Дан файл. Переписать его в обратном направлении.
Вариант 6
Программа производит ввод элементов матрицы из файла.
Вариант 7
Произвести вывод матрицы в файл.
Вариант 8
Исходный файл переписать таким образом, чтобы все буквы верхнего регистра были переведены в нижний регистр и наоборот. Использовать функции tolower, toupper, isupper.
Вариант 9
Дан файл. Подсчитать количество строк в файле и выдать номер самой длинной строки. Использовать функцию strlen.
Вариант 10
Дан файл. "Разрезать" исходный файл на несколько, каждый из которых содержит n строк, где n задается с терминала. Имя результирующих файлов должно быть связано с исходными. Использовать функцию strcat.
Вариант 11
Дан файл. Определить количество символов в файле и вывести на экран слово, стоящее посередине файла.
/* ЛАБОРАТОРНАЯ РАБОТА 3 (IN_OUT1)
ФУНКЦИИ ВВОДА И ВЫВОДА СИСТЕМНОГО УРОВНЯ
Все функции ввода/вывода верхнего уровня построены на базе более примитивных функций - функций ввода/вывода системного уровня. Наличие большого количества функций ввода/вывода верхнего уровня является их достоинством, а также недостатком, поскольку использование в одной программе нескольких функций ведет к расходу большего количества памяти. Когда применение функций ввода/вывода верхнего уровня не приносит особых преимуществ программе, можно использовать функции ввода/вывода системного уровня.
Для использования функций ввода/вывода системного уровня необходимо подключать следующие заголовочные файлы:
io.h , содержащий прототипы функций,
fcntl.h, содержащий макроопределения,
sys/stat.h, содержащий макроопределения (для open).
Для получения доступа к файлу используется функция open, которая в качестве результата возвращает неотрицательное целое значение, - дескриптор файла (handle) - которое используется при вызовах функций ввода/вывода. После окончания ввода/вывода файл необходимо закрыть с помощью функции close, после чего дескриптор файла можно использовать для последующего открытия файла.
Файлы могут быть открыты в двоичном или текстовом режиме.
При выполнении любой программы автоматически открываются пять стандартных файлов, имеющих следующие дескрипторы файлов: 0 - файл ввода, 1 - файл вывода, 2 - файл для сообщений об ошибках, 3 - последовательный порт, 4 - устройство печати. Для переопределения дескрипторов используется функция dup.
Далее приводятся описания прототипов функций с кратким пояснением.
Доступ к файлу
int open(const char *path, int access [, int permiss]);
функция открывает файл с указанным именем и готовит его в соответствии с параметром access:
O_RDONLY - для чтения
O_WRONLY - для записи
O_RDWR - для чтения и записи
Остальные параметры в сочетании (используя |):
O_APPEND - дозапись в конец файла
O_CREAT - создать файл, доступ в соотв. permiss
O_EXCL - только с O_CREAT,ошибка,если файл существует
O_TRUNC - файл усекается до 0,если существ,доступ записи
O_BINARY - двоичный режим
O_TEXT - текстовый режим
Если используется O_CREAT, permiss принимает значения: (используется заголовочный файл sys\stat.h)
S_IWRITE - запись
S_IREAD - чтение
S_IREAD | S_IWRITE - запись и чтение
Возврат при ошибке: -1.
Создать файл
int creat(const char *path, int amode);
Функция (устаревшая) создает файл или усекает до 0, если есть доступ к записи. Для amode см выше параметр permiss. Возврат при ошибке: -1.
Режим чтения файла
int setmode (int handle, int amode);
Для открытого файла с известным дескриптором устанавливается режим чтения файла (параметр amode):
O_BINARY - двоичный O_TEXT - текстовый. Возврат при ошибке: -1.
Закрытие файла
int close (int handle); Функция закрывает файл с дескриптором handle.
Конец файла
int eof (int handle);
Возврат: 0 - не конец файла, 1 - конец файла, -1 - ошибка.
Чтение из файла
int read (int handle, void *buf, unsigned len); Функция считывает len байтов из файла с дескриптором handle в буфер buf. После чтения указатель продвигается на число прочитанных байтов. Возвращает число прочитанных байтов (0 - конец файла). Возврат при ошибке: -1.
Запись в файл
int write (int handle, void *buf, unsigned len);
Функция записывает len байтов из буфера buf в файл. Возвращает число записанных байтов. Возврат при ошибке: -1.
Прямой доступ к файлу
long lseek (int handle, long offset, int fromwhere);
Функция перемещает указатель файла на offset байтов относительно fromwhere:
SEEK_SET - начала файла
SEEK_CUR - текущей позиции указателя
SEEK_END - конца файла.
Возвращает смещение относительно начала файла. Возврат при ошибке: -1L.
Текущая позиция в файле
long tell (int handle);
Функция возвращает номер текущей позиции файла относительно начала файла.
Возврат при ошибке: -1L.
Пример 1. Программа переписывает содержимое файла \autoexec.bat
в utoexec.bak.
#include<io.h>
#include<fcntl.h>
#include<sys\stat.h>
#include<stdlib.h>
#define BUFSIZE 512
void main (void)
{
int in, out; /* описание дескриптеров файлов */
int n;
char bufer[BUFSIZE]; /* буфер для ввода/вывода */
/* открыть файл для чтения */
if((in=open("\\autoexec.bat",O_RDONLY))==-1)
{
/* вывод в файл вывода сообщений об ошибках */
write(2, "cannot open input file\n",25);
exit(1);
}
/* открыть файл для чтения и записи. Если он не существует, создать с возможностью записи, если существует-перезаписать*/
if((out=open("utoexec.bak",O_CREAT|O_RDWR|O_TRUNC,S_IWRITE))==-1)
{
perror("cannot open output file\n");
exit(1);
}
/* чтение и запись идет из буфера по 512 байт */
while((n=read(in,bufer,BUFSIZE))>0)
if(write(out,bufer,n)!=n)
perror("write error");
close(in);
close(out);
}
/* Порядок выполнения задания
1. Получить задание у преподавателя.
2. Проанализировать задачу.
3. Определить круг используемых функций.
4. Изучить необходимые функции.
5. Написать текст программы.
6. Разработать контрольный пример.
7. Провести отладку программы.
8. Выполнить программу.
9. Проверить правильность полученного результата.
ЗАДАНИЕ
Выполнить следующее задание, передавая имена файлов в качестве аргументов функции main.
Вариант 1
Даны два файла. Создать третий файл , объединяющий два файла в один.
Вариант 2
Дан файл. Имя файла не содержит расширения и задается с терминала по запросу. Создать копию файла. Имя файла-копии отличается от исходного тем, что имеет расширение bak. Использовать функцию strcat.
Вариант 3
Дан файл. Подсчитать количество слов в файле, длиннее пяти символов.
Вариант 4
Дан файл. Создать результирующий так, что он содержит каждый n-ый символ исходного файла, где n задается через аргументы функции main.
Вариант 5
Дан файл. Переписать его в обратном направлении.
Вариант 6
Сравнить два файла построчно. Напечатать номер первой неравной строки.
Вариант 7
Дан файл. Создать новый так, чтобы все строки были не длиннее n символов. Длинные строки делить на несколько.
Вариант 8
Исходный файл переписать таким образом, чтобы все буквы верхнего регистра были переведены в нижний регистр и наоборот. Использовать функции tolower, toupper, isupper.
Вариант 9
Дан файл. Подсчитать количество строк в файле и выдать номер самой длинной строки.
Вариант 10
Дан файл. "Разрезать" исходный файл на несколько, каждый из которых содержит n строк, где n задается через аргументы функции main.
Вариант 11
Дан файл. Определить количество символов в файле и вывести на экран слово, стоящее посередине файла.
/* ФУНКЦИИ ВВОДА И ВЫВОДА ДЛЯ КОНСОЛЬНОГО ТЕРМИНАЛА
ТЕКСТОВАЯ ГРАФИКА (IN_CON)
Функции ввода/вывода для консольного терминала выделены в отдельную группу, потому что они используют специфические особенности компьютера IBM/PC - наличие видеоадаптера.
Консоль (ее роль выполняют клавиатура и дисплей) не требует "открытия" перед использованием функций ввода/вывода и "закрытия" по окончании работы. Прототипы функций ввода/вывода для консольного терминала, а также ряд функций, обеспечивающий текстовую графику, описаны в заголовочном файле conio.h.
Почти все функции, описанные в conio.h, работают с текущим (созданным последним) текстовым окном. По умолчанию текстовое окно имеет размеры 80х25 ( по размеру
экрана дисплея). Координаты левого верхнего угла (1,1). Ось X проходит слева направо, а ось Y - сверху вниз. Однако, текстовое окно может быть создано произвольного размера и находиться в любом месте экрана дисплея.
Создание текстового окна
void window(int left, int top, int right, int bottom);
Функция формирует текстовое окно в виде прямоугольника, противоположные по диагонали вершины которого (начиная с левого верхнего) имеют координаты (left,top) и (right,bottom). Координаты отсчитываются относительно окна, прянятого по умолчанию.
Очищение текстового окна
void clrscr(void); - очищается текущее текстовое окно, курсор помещается в левый верхний угол.
Курсор в текстовом окне
void gotoxy(int x, int y); - перемещение текстового курсора на позицию x,y относительно текущего текстового окна, за выход за пределы окна ответственен программист.
int wherex(void); - вычисляется горизонтальная
int wherey(void); и вертикальная координата курсора относи тельно текущего текстового окна.
void _setcursortype(int cur_t); - установить вид курсора в текущем окне. В качестве аргумента использовать макро, объявленные в conio.h:
_NOCURSOR (значение 0) - нет курсора в окне
_SOLIDCURSOR (значение 1) - курсор в виде прямоугольника
_NORMALCURSOR (значение 2) - курсор обычного вида.
Строки в текстовом окне
void clreol(void); - замена пробелами тех знаков в строке, которые расположены между курсором и концом строки в текущем текстовом окне.
void delline(void); - удаление из текущего текстового окна строки, на которую указывает курсор. Нижние строки перемещаются вверх.
void insline(void); - вставка строки в текущем текстовом окне под строкой, на которую указывает курсор. Нижняя строка удаляется.
Перемещение текстового окна
int gettext(int left, int top, int right, int bottom, void *destin);
Функция переносит текст с экрана, находящегося в прямоугольнике с координатами противоположных по диагонали вершин, на- чиная с левой верхней, (left,top) и (right,bottom) в область памяти (буфер), указанную аргументом destin. Координаты относительно текстового окна по умолчанию.
Возврат при ошибке: 0.
int puttext(int left, int top, int right, int bottom, void *source);
Функция, обратная gettext, размещает сохраненный текст из буфера в выбранном прямоугольнике. Координаты относительно текстового окна по умолчанию.
Возврат при ошибке: 0.
int movetext(int left, int top, int right, int bottom, int destleft, int desttop);
Функция копирует текст из прямоугольника, определенного координатами (left,top) и (right,bottom), в такое место экрана, чтобы левый верхний угол имел координаты (destleft,desttop).
Возврат при ошибке: 0.
Цвет в текстовом окне
void textbackground(int newcolor); - цвет фона (темные цвета).
void textcolor(int newcolor); - цвет символов (любой цвет).
В качестве аргумента использовать макро, объявленные в conio.h: темные тона: BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, LIGHTGRAY; светлые тона: DARKGRAY, LIGHTBLUE, LIGHTGREEN, LIGHTCYAN, LIGHTRED, LIGHTMAGENTA,
YELLOW, WHITE; BLINK - признак мерцания. Например: RED+BLINK - красный мерцающий.
void textattr(int newattr); - изменение цвета символа, фона, мерцания.
(как формируется байт атрибута см. лаб.раб. 8).
Интенсивность цвета в текстовом окне
void highvideo(void); - максимальная яркость символов
void lowvideo(void); - минимальная яркость символов
void normvideo(void); - обычная яркость символов
Условия отображения текста на экране
void gettextinfo(struct text_info *r);
В структуре (шаблон описан в conio.h) хранится информация, характеризующая текущие условия отображения текстов, а именно: координаты углов текстового окна, текущее и принятое по умолчанию значение цвета, фона и мерцания, текущий режим вывода символов, вертикальный и горизонтальный размер экрана, текущие координаты курсора.
Ввод пароля
char * getpass(const char *prompt); - ввод с терминала пароля без эхо-печати. Аргумент - строка-приглашение к вводу, результат - указатель на строку, место под которую выделяет машина, содержащую пароль (8 символов).
Ввод/вывод текста в текстовом окне
Все нижеприведенные функции аналогичны соответствующим функциям ввода/вывода в стандартный поток ввода/вывода за следующим исключением: функция cputs не переводит курсор в начало следующей строки; вместо символа конца строки '\n' используются "\r\n". Все функции работают с текущим текстовым окном. Ввод/вывод производится с того места окна, на которое указывает курсор.
char * cgets(char *str); - ввод строки из окна
int cputs( char *str); - вывод строки в окно
int cscanf(const char *format, ...); - форматный ввод
int cprintf(const char *format, ...); - форматный вывод
int getch(void); - ввод символа без буферизации и отображения
int getche(void); ввод символа без буферизации с отображением
int putch(int c); - вывод символа в окно
int ungetch(int ch); - возвращается символ в буфер клавиатуры
int kbhit(void) - возвращает 0, если не нажата клавиша клавиа-
туры, иначе возвращает значение, отличное от 0.
Пример.
В текстовом окне выводятся пункты меню. Выбор пункта меню производится по номеру, при этом текст пункта меню выделяется цветом. Выбор может производиться несколько раз до тех пор, пока не нажата клавиша ввода. При нажатии клавиши ввода программа выдает сообщение и заканчивает работу. В программе есть недостаток: не контролируется правильность ввода номера пункта меню. Подумайте, как его устранить.
*/
#include<conio.h>
void invers(int,int);
char *menu[]={ "первый пункт",
"второй пункт",
"третий пункт",
"выход",
"выбор пункта меню" ,
"по номеру"};
void main (void)
{
int i;
/* номера текущего и предыдущего выбора пункта меню */
int nomer_tek, nomer_pred=1;
textbackground(WHITE); /* цвет фона окна */
textcolor(BLACK); /* цвет текста окна */
clrscr();
_setcursortype(_NOCURSOR); /* удаление курсора из окна */
textbackground(BLUE); /* цвет фона окна */
window(27,9,53,15); /* создание окна */
clrscr();
for(i=0; i<6; i++) /* ввод пунктов меню в окне */
{
gotoxy(3,i+1);
cputs(menu[i]);
}
while((nomer_tek=getch())!=13) /* выбор пункта меню */
{ /* пока не нажата кл. ввода */
nomer_tek -='0'; /* выбранный номер */
/* восстановление цвета текста в предыдущем выборе */
invers(BLACK,nomer_pred); /* выделение цветом выбранной строки меню */
invers(RED,nomer_tek);
nomer_pred=nomer_tek;
}
clrscr();
gotoxy(3,3);
cputs("Дальше думайте сами!");
}
/* в строке окна с номером nomer меняется цвет символов на color */
void invers(int color, int nomer)
{
textcolor(color);
gotoxy(3, nomer);
cputs(menu[nomer-1]);
return;
}
/* ЗАДАНИЕ
Составить программу, использующую в качестве интерфейса с пользователем простейшее меню. Программа начинает выполняться при вводе правильного пароля. В начале программы в текстовом окне выводятся пункты меню на заданную тему. Предпоследний пункт - "выход", а последний -"выбор пункта по номеру", если ввод пункта меню ожидается или был сделан верно, или "ошибка", если номер пункта меню введен неверно. Курсора в окне нет. Выбор пункта меню производится по номеру. При вводе существующего номера пункта меню соответствующая строка выделяется указанным образом. Выбор пункта меню производится пока не нажата клавиша ввода (возможно, несколько раз). После нажатия клавиши ввода окно распахивается на весь экран, очищается и выводится результат выполнения пункта меню, выбранного последним. После нажатия любой клавиши экран очищается и появляется первоначальная картинка меню. Дальнейший выбор пункта меню и действие по нему продолжаются,
пока не выбран пункт "выход". Далее приводятся пункты меню и способ выделения выбранной строки.
Вариант 1
Выбор игр:
1. Колобок
2. Принцесса в замке
3. Каратэ
Выбранный пункт меню появляется в другом окне.
Вариант 2
Могу начертить:
1. Треугольник
2. Прямоугольник
3. Круг
Меняется цвет фона и цвет символов выбранного пункта меню.
Вариант 3
Напечатаю названия сортов:
1. Яблок
2. Груш
3. Цветов
Появляется курсор в конце выбранной строки пункта меню в виде прямоугольника.
Вариант 4
Напечатаю список любимых команд:
1. Хоккей
2. Баскетбол
3. Футбол
Символы выбранного пункта меню выделяется более ярко.
Вариант 5
Для двух чисел вычисляю:
1. Сумму
2. Разность
3. Произведение
4. Частное
Символы выбранного пункта меню выделяется менее ярко.
Вариант 6
Выведу названия:
1. Рыб
2. Птиц
3. Млекопитающихся
Символы выбранного пункта меню мерцает.
Вариант 7
Выведу:
1. По номеру дня недели - название
2. По названию дня недели - номер
Меняется цвет фона выбранного пункта меню.
Вариант 8
Выведу десять случайных чисел:
1. В пределах 10
2. В пределах 100
3. В пределах 1000
В конце строки выбранного пункта меню появляется символ >.
Вариант 9
Выведу результаты по плаванию:
1. Лучший
2. Второй
3. В порядке возрастания
4. В порядке убывания
Меняется цвет символов выбранного пункта меню. В качестве исходного данного задается произвольный массив с результатами по плаванию.
Вариант 10
Меню кафе Джо:
1. Тушеные улитки по-французски 1.99
2. Суп с колбасой 0.88
3. Запеканка из голубей 1.10
4. Пюре с фрикадельками 0.99
5. Мороженое 0.60
6. Пицца с арахисом 0.87
7. Жареный хлеб 0.40
8. Молочный коктейль 0.58
ИТОГО:
При выборе блюда строка исчезает, а сумма итого увеличивается на величину указанной цены.
*/
/* ЛАБОРАТОРНАЯ РАБОТА N8 (VID_MEM)
ПРЯМОЙ ДОСТУП К ВИДЕОПАМЯТИ
РАБОТА В ТЕКСТОВОМ РЕЖИМЕ
Работа видеоадаптеров
Существуют три основных типа адаптеров: монохромный, цветной графический (CGA) и усовершенствованный графический (EGA). Адаптеры могут иметь несколько режимов работы; мы будем иметь в виду три режима, использующие 80-символьный текст: режим 2 или 3 (для CGA, EGA) ( режим 7 (для монохромного адаптера). Текст в этих режимах выводится в 80 столбцов и 25 строк.
Адаптер дисплея персонального компьютера обладает достаточной памятью для хранения информации, изображенной на экране.
Имеется три способа доступа к видеоадаптеру: через прерывания DOS (самый медленный), через процедуры BIOS, прямой доступ к видеопамяти (самый быстрый, но требующий большей работы от программиста).
Средствами языка Си возможно получить доступ непосредственно к этой памяти для ввода-вывода информации.
Прямой доступ к видеопамяти
Каждый символ, изображенный на экране, требует два байта видеопамяти: первый байт содержит символ, второй - его атрибуты.
Байт атрибутов для цветного монитора определен следующим образом:
1. номера битов в байте: 7 6 5 4 3 2 1 0
2. роль битов: 0 - голубой символ
1 - зеленый символ
2 - красный символ
3 - интенсивность изображения символа
4 - голубой фон
5 - зеленый фон
6 - красный фон
7 - мерцание символа
3. значения битов: 0 - атрибут выключен, 1 - включен. Значение байта атрибута 0x7 воспроизводит белый символ на черном фоне, значение 0х70 - черный символ на белом фоне.
Для записи и хранения информации, изображенной на экране с размерами 80х25, требуется не менее 4000 байтов памяти - страница видеопамяти. В зависимости от памяти адаптер может сохранять информацию на нескольких страницах видеопамяти, но активной
может быть только одна из них - информация именно активной страницы видеопамяти изображается на экране. По умолчанию активна нулевая страница видеопамяти. Изменить номер активной видеостраницы можно, например, с помощью функции системного прерывания int86.
Адреса нулевой страницы видеопамяти для монохромного монитора 0хВ0000000, для цветного монитора - 0хВ8000000.
Изображение символа на странице видеопамяти
Чтение и запись в видеопамять производится с помощью использования дальних указателей на видеопамять ( явно, с помощью ключевого слова far, или используя модель памяти, где все указатели по умолчанию дальние). Для определения адреса отдельного символа, изображенного на соответствующей видеостранице, используется формула адрес = адрес_видеостраницы + y*160 + x*2, где x - горизонтальная, а y - вертикальная координаты символа на экране. При выбранном режиме работы 0<= x <80, 0<= y <25.
Адрес атрибута этого же символа на единицу больше.
Пример 1. C помощью прямого доступа к нулевой видеостранице создать на экране приятный фон.
*/
#include <stdio.h>
