В языке Си для IBM-совместимых персональных компьютеров обращение к регистрам микропроцессора Intel 8086 осуществляется с помощью специальных объектов, называемых псевдопеременными. Полный список псевдопеременных включает 21 элемент: _АХ, _ВХ, _СХ, _DX, _CS, _DS, _SS, _ES, _SP, _ВР, _DI, _SI, _AL, _AH, _BL, _ВH, _CL, _СН, _DL, _DH, _FLAGS. Их имена образуются из имен регистров с префиксом _ (например, переменная _AX связана с регистром AX). Первые двенадцать псевдопеременных и последняя имеют тип unsigned int, а оставшиеся восемь - unsigned char. Присвоение значения какой-либо переменной, например _АХ, вызывает занесение этого значения в регистр АХ. Получение значения переменной, например _ВХ, эквивалентно получению значения из регистра ВХ.
РАЗДЕЛ 7. ПРИМЕРЫ
Рассмотрим примеры программ, в которых используются различные конструкции языка Си. Первый из них демонстрирует использование управляющих символов n в функциях printf( ) и scanf( ).
/* Пример 1 */
#include <stdio.h>
void main(void)
{
int x, n1, n2;
printf("Введите целое число от -32768 до 32767\n");
scanf("%d%n", &x, &n1);
printf("x = %d%n\n", x, &n2);
printf("n1 = %d, n2 = %d\n", n1, n2);
}
Результаты работы этой программы имеют вид:
Введите целое число от -32768 до 32767
234<Enter>
x = 234
n1 = 3, n2 = 7
Значение n1 определяет число введенных цифр, а n2 - число выведенных символов в строке x = 234 (с пробелами).
Следующий пример показывает использование спецификаций %[], а также символов * и #.
/* Пример 2 */
#include <stdio.h>
void main(void)
{
char str_b[21], str_c[21]; /* Последний элемент резервируем под \0 */
Здесь пользователем введена строка Comp-1-2-3-4-5. Из нее только четыре символа (Comp) совпадают с первыми символами, заданными в квадратных скобках рассматриваемой спецификации [Computer]. Поэтому только эти четыре символа попадут в первую строку, а оставшиеся символы (1-2-3-4-5) попадут во вторую строку. Число n1 определяет минимальную ширину поля для вывода, а число n2 = 3 - количество цифр после запятой. В результате число 12.345678 будет смещено относительно левой границы, и после запятой будут выведены три цифры. Шестнадцатеричное число 0х100 выведено функцией printf( ) с префиксом 0x, без префикса 0x и в десятичной форме.
Третья программа демонстрирует использование условного оператора if...else и оператора for для организации цикла.
/* Пример 3 */
#include <conio.h>
#define SYM 'X' /* Выводимый символ */
#define SPACE ' ' /* Определение пробела */
#define LF 10 /* Перевод строки */
#define CR 13 /* Возврат каретки */
#define LEFT 24 /* Левая граница символа */
#define RIGHT 51 /* Правая граница символа */
#define BOTTOM 25 /* Нижняя граница символа */
void main(void)
{
int col, line; /* col - номер колонки для вывода символа */
/* line - номер линям для вывода символа */
clrscr( );
for (line = 1; line <= BOTTOM; line++) /* Вывод пробелов до левой
границы символа */
{
for (col = 1; col < LEFT; col++) putch(SPACE);
for(col = LEFT + 1; col < RIGHT; col++) /* Вывод символа X
putch(LF); /* Возврат каретки и перевод строки после */
putch(CR); /* вывода каждой линии символа */
}
getch( ); /* Ожидание нажатия клавиши */
}
После ее запуска на весь экран будет выведен символ X.
Новая библиотечная функция clrscr( ) имеет следующий прототип:
void clrscr (void);
Она выполняет очистку экрана и объявлена в заголовочном файле conio.h.
Четвертая программа демонстрирует использование рекурсивной функции для вычисления факториала. (Отметим, что определение функции factorial( ) может находиться и после функции main( ), но в этом случае функция factorial( ) должна быть объявлена перед функцией main( ), т.е. до main( ) необходимо поместить строку: long factorial(int);.)
/* Пример 4 */
#include <stdio.h>
#include <values.h>
#include <process.h>
long factorial(int value) /* Рекурсивная функция */
{
long result = 1;
if (value != 0)
{
result = factorial(value - 1);
/* Проверка возможности вычисления факториала */
if (result > MAXLONG / (value + 1))
{
fprintf(stderr, "Очень большое число\n");
getch( ); /* Ожидание нажатия клавиши */
exit (1);
}
result *= value;
}
return(result);
}
/* Рекурсивное вычисление факториала числа value */
void main(void)
{
int value; /* Факториал этого значения вычисляется */
long result; /* Переменная для результата */
puts("Факториал какого числа?");
scanf("%d", &value);
result = factorial(value);
printf("Результат: %ld\n", result);
getch( ); /* Ожидание нажатия клавиши */
}
Результаты работы этой программы:
Факториал какого числа? 10<Enter>
Результат: 362880
Пятая программа подсчитывает число символов и слов во вводимых строках (новые символы и слова суммируются с предыдущими; пробелы входят в число введенных символов).
/* Пример 5 */
#include <stdio.h>
#include <conio.h>
#define ESC 27 /* 27 - ASCII-код клавиши ESC */
void CountOfLines(void)
{
/* Статические переменные будут сохранять старые значения при каждом
новом вызове функции CountOfLines */
static int words = 0, symbols = 0; /* words-число слов,
symbols-число символов */
char temp, t = 0; /* Временные переменные */
++symbols;
/* Число символов и слов выдается после нажатия клавиши <Enter> */
while ((temp = getche( )) != '\r' )
{
++symbols; /* Подсчитывается каждый символ */
/* После одного или нескольких пробелов подсчитывается слово */
puts("Для завершения программы нажмите <ESC> в начале строки");
puts("Строка не должна начинаться с пробела и с нажатия клавиши"
"<Enter>");
puts("Строка не должна завершаться пробелом");
while (getche( ) != ESC) CountOfLines();
putch('\b');
putch(' ');
putch('\b');
}
Результаты работы этой программы:
Для завершения программы нажмите <ESC> в начале строки
Строка не должна начинаться с пробела и с нажатия клавиши <Enter>
Строка не должна завершаться пробелом
Mouse Keyboard <Enter>
Слов: 2 символов: 14
<ESC>
Следующая группа программ демонстрирует работу с файлами. Она позволяет организовать в файле на диске телефонный справочник и выполняет следующие функции:
занесение фамилии абонента и номера телефона в справочник;
поиск в справочнике номера телефона по фамилии абонента;
удаление из справочника фамилии абонента и номера его телефона.
#include "A:\my.h" //Заголовочный файл с глобальными
//переменными и константами
#include "A:\findt.c" //Поиск строки str в файле
#include "A:\choicet.c" //Проверка наличия строки в файле
#include "A:\addt.c" //Добавление строки в файл
#include "A:\subt.c" //Удаление строки из файла
void main(int argc, char *argv[ ])
{
if (argc == 3)
if (*argv[1] == '+') //Добавить запись
{
if (Choice(argv[2]) == 0) //Нет ли такой
//записи в файле?
{
puts("Эта фамилия есть в справочнике");
exit(1);
}
Add(argv[2]); //Добавление записи
}
else if (*argv[1] == '-') Sub(argv[2]); //Удалить запись
else puts("Ошибочное значение аргумента");
else if (argc == 2) Find(argv[1]); //Поиск записи
else puts("Ошибочное число аргументов");
}
С помощью директив #include в головную программу включаются файлы: my.h, findt.c, choicet.c, addt.c и subt.c. Считается, что все они находятся в корневом каталоге диска A:. Если это не так, то необходимо изменить соответствующие директивы #include. В файле my.h определены глобальные переменные и некоторые символьные значения.
Файл my.h, в частности, определяет, что телефонный справочник будет организован в каталоге tel диска A:. Поэтому необходимо перед запуском программы main.exe создать этот подкаталог либо использовать другой подкаталог. В последнем случае необходимо изменить строку:
char File[ ] = "A:\\tel\\tel_num.txt";
которая задает имя файла с телефонным справочником (tel_num.txt).
Модуль findt.c, текст которого приведен ниже, содержит функцию Find( ) для поиска строки str в файле tel_num.txt.