Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лаб по С и С++ / lc++teor.doc
Скачиваний:
70
Добавлен:
17.03.2015
Размер:
147.46 Кб
Скачать

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. ввод/вывод через порт.

Для пользователя файл, открытый на верхнем уровне, представляется как последовательность считываемых или записываемых байтов. Чтобы отразить эту особенность, используется понятие "поток" (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

/* ЛАБОРАТОРНАЯ РАБОТА 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);

}

*/

/* ЛАБОРАТОРНАЯ РАБОТА 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>

Соседние файлы в папке Лаб по С и С++