В языке Си для 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 */
int x, n1, n2;
float y;
printf("Введите строку до 20 символов\n");
scanf("%[Computer]%s", str_b, str_c);
printf("str_b = %s, str_c = %s\n", str_b, str_c);
y = 12.345678;
n1 = 8;
n2 = 3;
x = 0x100;
printf("y = %*.*f\n", n1, n2, y);
|
printf("x(16) = %#x, x(16) = %x, x(10) = %i\n", x, x, x);
}
Результаты работы программы имеют следующий вид:
Введите строку до 20 символов
Comp-1-2-3-4-5<Enter>
str_b = Comp, str_c = -1-2-3-4-5
у = 12.346
x(16) = 0x100, x(16) = 100, x(10) = 256
Здесь пользователем введена строка 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
на весь экран */
if ((col == (LEFT + line)) || (col == (RIGHT - line)))
putch(SYM);
else putch(SPACE);
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; /* Подсчитывается каждый символ */
/* После одного или нескольких пробелов подсчитывается слово */
if ((temp == ' ') && (t == 1)) continue;
if (temp == ' ') { t = 1; ++words; }
else t = 0;
}
if (t == 1) --words;
else ++words;
printf ("\n Слов: %d; символов: %d\n", words, symbols);
}
void main(void)
{
puts("Для завершения программы нажмите <ESC> в начале строки");
puts("Строка не должна начинаться с пробела и с нажатия клавиши"
"<Enter>");
puts("Строка не должна завершаться пробелом");
while (getche()!= ESC) CountOfLines();
putch('\b');
putch(' ');
putch('\b');
}
Результаты работы этой программы:
Для завершения программы нажмите <ESC> в начале строки
Строка не должна начинаться с пробела и с нажатия клавиши <Enter>
Строка не должна завершаться пробелом
Mouse Keyboard <Enter>
Слов: 2 символов: 14
<ESC>
Следующая группа программ демонстрирует работу с файлами. Она позволяет организовать в файле на диске телефонный справочник и выполняет следующие функции:
- занесение фамилии абонента и номера телефона в справочник;
- поиск в справочнике номера телефона по фамилии абонента;
- удаление из справочника фамилии абонента и номера его телефона.
Ниже приведен текст головной программы main.c:
// Пример 6
//---------------------------------------------------------
// Головная программа для работы с телефонным справочником
//---------------------------------------------------------
#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
//--------------------------------------------------------
//Определения глобальных переменных и символьных значений
//--------------------------------------------------------
#include <stdio.h>
#include <process.h>
#include <string.h>
#define MAX_NAME 20 //Максимальное число символов в фамилии
#define MAX_NUMBER 10 //Максимальное число цифр в телеф. номере
char Name[MAX_NAME]; //Массив фамилий
char Number[MAX_NUMBER]; //Массив для телефонного номера
char File[ ] = "A:\\tel\\tel_num.txt"; //Имя файла справочника
int Count; //Число фамилий в справочнике
FILE *F_tel; //Логическое имя файла справочника
Файл my.h, в частности, определяет, что телефонный справочник будет организован в каталоге tel диска A:. Поэтому необходимо перед запуском программы main.exe создать этот подкаталог либо использовать другой подкаталог. В последнем случае необходимо изменить строку:
char File[ ] = "A:\\tel\\tel_num.txt";
которая задает имя файла с телефонным справочником (tel_num.txt).
Модуль findt.c, текст которого приведен ниже, содержит функцию Find() для поиска строки str в файле tel_num.txt.
//Модуль findt.c
//----------------------------------------------------------
//Функция Find() для поиска строки str в файле tel_num.txt
//----------------------------------------------------------
void Find(char *str)
{
int i;
//Если файл невозможно открыть для чтения, то программа
//завершаетработу
if ((F_tel = fopen(File, "r")) == NULL)
{
fprintf(stderr, "\"%s\": невозможно открыть\n", File);
exit(1);
}
//Чтение числа записей (Count) в файле
if (fread(&Count, sizeof(int), 1, F_tel)!= 1)
{
fprintf(stderr, "\"%s\": ошибкачтения\n", File);
exit(1);
}
//В цикле for осуществляется поиск нужной записи
for (i = 1; i < Count; i++)
{
fread(Name, 1, MAX_NAME, F_tel); //Чтениеимени
fread(Number, 1, MAX_NUMBER, F_tel); //Чтениеномера
if (ferror(F_tel)) //Проверка отсутствия ошибки
{
fprintf(stderr, "\"%s\": ошибка чтения\n'', File);
exit(1);
}
if (strcmp(str, Name) == 0) //Если имя совпадает
//с введенным, то фамилия
//и найденный номер
//выводятся на экран
{
printf("Фамилия: %s\n", Name);
printf("Номертелефона: %s\n", Number);
fclose(F_tel);
return;
}
}
//Если результат поиска отрицательный, то выводится
//следующее сообщение
fprintf(stderr,"\"%s\": запись в файле отсутствует\n", File);
fclose(F_tel);
return;
}
Модуль choicet.c содержит функцию Choice(), позволяющую проверить есть ли заданная строка в файле tel_num.txt.
// Модуль choicet.c
//----------------------------------------------------------------------
//Функция Choice(), проверяющая есть ли строка str в файле tel_num.txt
//----------------------------------------------------------------------
int Choice(char *str)
{
int i;
char temp[MAX_NAME + MAX_NUMBER];
if ((F_tel = fopen(File, "r")) == NULL)
return 1; //Строки str нет в файле
if (fread(&Count, sizeof(int), 1, F_tel)!= 1)
{
fprintf(stderr, "\"%s\": ошибкачтения\n", File);
exit(1);
}
for (i = 0; i < Count; i++)
{
fread(temp, 1, MAX_NAME + MAX_NUMBER, F_tel);
if (ferror(F_tel))
{
fprintf(stderr, "\"%s\": ошибкачтения\n", File);
exit(1);
}
if (strcmp(str, temp) == 0)
{
fclose(F_tel);
return 0; //Строка str есть в файле
}
}
fclose(F_tel);
return 1; //Строки str нет в файле
}
Модуль addt.c содержит функцию Add(), которая добавляет заданную строку в файл tel_num.txt.
//Модуль addt.c
//-------------------------------------------------------
//Функция Add() добавляет строку str в файл tel_num.txt
//-------------------------------------------------------
void Create(void) //Создает файл, если он не существует
{
if ((F_tel = fopen(File, "wb+")) == NULL)
{
fprintf(stderr, "\%s\": невозможнооткрыть\n", File);
exit(1);
}
Count = 0;
if (! fwrite(&Count, sizeof(Count), 1, F_tel))
{
fprintf(stderr, "\"%s\": ошибказаписи\n", File);
exit(1);
}
}
void Add(char *s) //Добавляет запись в файл
{
char str[MAX_NAME], sn[MAX_NUMBER]; //Временныемассивы
int i;
for (i = 0; i < MAX_NAME; i++)
str[i] = ' '; //Пробелы в str
strcpy(str, s); //Копирование строки в str
if ((F_tel = fopen(File, "rb+")) = = NULL)
Create(); //Создаем файл, если он не
//существует
else if (fread(&Count, sizeof(Count), 1, F_tel)!= 1)
{
fprintf(stderr, "\"%s\": ошибкачтения\n", File);
exit(1);
}
printf("Номер телефона: "); //Запрашивается и вводится номер
if (gets(Number) == NULL || *Number == '\0')
{
fclose(F_tel);
return; //Возврат, если номер не введен
}
//Установка указателя в файле на первую свободную запись
if (fseek(F_tel, (long)((MAX_NAME+MAX_NUMBER)*Count), SEEK_CUR)!=0)
{
fprintf(stderr, "\"%s\": ошибкапоиска\n", File);
exit(1);
}
fwrite(str, 1, MAX_NAME, F_tel); //Записьвфайлфамилии
for (i = 0; i < MAX_NUMBER; i++)
sn[i] = ' '; //Пробелы в sn[ ]
strcpy(sn, Number); //Копирование сроки Number в строку sn
fwrite(sn, 1, MAX_NUMBER, F_tel); //Запись в файл номера
if (ferror(F_tel)) //Проверка наличия ошибки
{
fprintf(stderr, "\"%s\": ошибказаписи\n", File);
exit(1);
}
//Установка указателя в файле на первый байт
if (fseek(F_tel, 0L, SEEK_SET)!= 0)
{
fprintf(stderr, "\"%s\": ошибкапозиционирования\n", File);
exit(1);
}
++Count; //Увеличение числа записей на единицу
//Запись Count вфайл
if (fwrite(&Count, sizeof(int), 1,F_tel)!= 1)
{
fprintf(stderr, "\"%s\": ошибказаписи\n", File);
exit(1);
}
fclose(F_tel);
return;
}
Модуль subt.c содержит функцию Sub(), которая удаляет заданную строку из файла tel_num.txt.
//Модуль subt.c
//------------------------------------------------------------
//Функция Sub() удаляет заданную строку из файла tel_num.txt
//------------------------------------------------------------
void Sub(char *str)
{
int i, j;
char temp[MAX_NAME + MAX_NUMBER]; //Временныймассив
if ((F_tel = fopen(File, "r+")) == NULL)
{
fprintf(stderr, "\"%s\": невозможнооткрыть\n", File);
exit(1);
}
if (fread(&Count, sizeof(int), 1, F_tel)!= 1)
{
fprintf(stderr, "\"%s\": ошибкачтения\n", File);
exit(1);
}
//В цикле осуществляется поиск удаляемой строки в файле
for (i = 0; i < Count; i++)
{
fread(temp, 1, MAX_NAME + MAX_NUMBER, F_tel);
if (ferror(F_tel))
{
fprintf(stderr, "\"%s\": ошибкачтения\n", File);
exit(1);
}
if (strcmp(str, temp) == 0) //Еслисроканайдена
{
for (j = i; j < Count; j++) //онаудаляется
{
fread(temp, 1, MAX_NAME + MAX_NUMBER, F_tel);
fseek(F_tel, (long)(j*(MAX_NAME+MAX_NUMBER)+2L), SEEK_SET);
fwrite(temp, 1, MAX_NAME + MAX_NUMBER, F_tel);
fseek(F_tel, (long)((j+2)*(MAX_NAME+MAX_NUMBER)+2L), SEEK_SET);
if (ferror(F_tel))
{
fprintf(stderr, "\"%s\": ошибкачтения\n", File);
exit(1);
}
}
--Count; //При удалении строки декремент Count
fseek(F_tel, 0L, SEEK_SET); //Установка указателя
//Запись уменьшенного значения Count в файл
if (fwrite(&Count, sizeof(Count), 1, F_tel)!= 1)
{
fprintf(stderr, "\"%s\": ошибказаписи\n", File);
exit(1);
}
fclose(F_tel);
puts("Запись удалена из файла");
return;
}
}
fprintf(stderr, "\"%s\": отсутствует в базе данных\n", File);
fclose(F_tel);
}
Ниже приводится возможный сценарий работы с программой main.
main + Петров<Enter>
Номер телефона: 77-17-89<Enter>
main + Иванов<Enter>
Номер телефона: 52-98-02<Enter>
main Иванов<Enter>
Фамилия: Иванов
Номер телефона: 52-98-02
main - Петров<Enter>
Запись удалена из файла
main Петров<Enter>
"tel_num.txt": запись в файле отсутствует
Последняя программа showt.c позволяет вывести на экран содержимое телефонного справочника.
//Программа showt.c
//-------------------------------------------------
//Выводит на экран все записи из файла tel_num.txt
//-------------------------------------------------
#include "my.h"
void Show(void)
{
int i;
//Если файл невозможно открыть для чтения, то завершение работы программы
if ((F_tel = fopen(File, "r")) == NULL)
{
fprintf(stderr, "\"%s\": невозможнооткрыть\n",File);
exit(1);
}
//Чтение числа записей (Count) в файле
if(fread(&Count, sizeof(int), 1, F_tel)!= 1)
{
fprintf(stderr, "\"%s\": ошибкачтения\n", File);
exit(1);
}
//В цикле осуществляется вывод всех записей
for (i=0; i < Count; i++)
{
fread(Name, 1, MAX_NAME, F_tel); //Читаетсяимя
fread(Number, 1, MAX_NUMBER, F_tel); //Читаетсяномер
if (ferror(F_tel)) //Проверяется отсутствие ошибки
{
fprintf(stderr, "\"%s\": ошибка чтения\n'', File);
exit(1);
}
printf("Фамилия: %s; номертелефона: %s\n", Name, Number);
}
fclose(F_tel);
}
void main(void)
{
Show();
}
ЛИТЕРАТУРА
- Скляров В.А. Программирование на языках Си и Си++.- М.: Высшая школа, 1996.
- Березин Б.И., Березин С.Б. Начальный курс С и С++.- М.: ДИАЛОГ-МИФИ, 1999.
- Керниган Б., Ритчи Д. Язык программирования Си.- М.: Финансы и статистика, 1992.
- Подбельский В.В., Фомин С.С. Программирование на языке Си. Учеб. пособие.- М.: Финансы и статистика, 2000.
- Павловская Т.А. C/C++, Программирование на языке высокого уровня.- СПб.: Питер, 2005.
- Касаткин А.И. Профессиональное программирование на языке Си. Системное программирование.- Минск: Высшая школа, 1993.
- Касаткин А.И. Профессиональное программирование на языке Си. Управление ресурсами.- Минск: Высшая школа, 1993.
- Касаткин А.И., Вальвачев А.Н. Профессиональное программирование на языке Си. От Turbo C к Borland C++.- Минск: Высшая школа, 1995.
(c) Курсков С.Ю., составление, 2006-2012