Жанр: Учеба
Хрестоматия по программированию на Си в Unix
.............................................. 198
6.3. Свободное место на диске. ................................................ 207
6.4. Сигналы. ................................................................. 212
6.5. Жизнь процессов. ......................................................... 219
6.6. Трубы и FIFO-файлы. ...................................................... 230
6.7. Нелокальный переход. ..................................................... 233
6.8. Хозяин файла, процесса, и проверка привелегий. ........................... 235
6.9. Блокировка доступа к файлам. ............................................. 240
6.10. Файлы устройств. ........................................................ 244
6.11. Мультиплексирование ввода-вывода ......................................... 259
6.12. Простой интерпретатор команд. ........................................... 271
7. Текстовая обработка. ....................................................... 283
8. Экранные библиотеки и работа с видеопамятью. ............................... 348
9. Приложения. ................................................................ 391
9.1. Таблица приоритетов операций языка C++ .................................... 391
9.2. Правила преобразований типов. ............................................ 391
9.3. Таблица шестнадцатеричных чисел (HEX). ................................... 392
9.4. Таблица степеней двойки. ................................................. 393
9.5. Двоичный код: внутреннее представление целых чисел. ...................... 393
10. Примеры. .................................................................. 394
Пример 1. Размен монет. ......................................................
Пример 2. Подсчет букв в файле. ..............................................
Пример 3. Центрирование строк. ...............................................
Пример 4. Разметка текста для nroff. .........................................
Пример 5. Инвертирование порядка слов в строках. .............................
Пример 6. Пузырьковая сортировка. ............................................
Пример 7. Хэш-таблица. .......................................................
Пример 8. Простая база данных. ...............................................
Пример 9. Вставка/удаление строк в файл. .....................................
Пример 10. Безопасный free, позволяющий обращения к автоматическим перемен-
ным. .....................................................................
Пример 11. Поимка ошибок при работе с динамической памятью. ..................
Пример 12. Копирование/перемещение файла. ....................................
Пример 13. Обход поддерева каталогов в MS DOS при помощи chdir. ..............
Пример 14. Работа с сигналами. ...............................................
Пример 15. Управление скоростью обмена через линию. ..........................
Пример 16. Просмотр файлов в окнах. ..........................................
Пример 17. Работа с иерархией окон в curses. Часть проекта uxcom. ............
Пример 18. Поддержка содержимого каталога. Часть проекта uxcom. ..............
Пример 19. Роллируемое меню. Часть проекта uxcom. ............................
Пример 20. Выбор в строке-меню. Часть проекта uxcom. .........................
Пример 21. Редактор строки. Часть проекта uxcom. .............................
Пример 22. Выбор в прямоугольной таблице. Часть проекта uxcom. ...............
Пример 23. UNIX commander - простой визуальный Шелл. Головной модуль проекта
uxcom. ...................................................................
Пример 24. Общение двух процессов через "трубу". .............................
Пример 25. Общение процессов через FIFO-файл. ................................
Пример 26. Общение процессов через общую память и семафоры. ..................
Пример 27. Протоколирование работы программы при помощи псевдотерминала и
процессов. ...............................................................
Пример 28. Оценка фрагментированности файловой системы. ......................
Пример 29. Восстановление удаленного файла в BSD-2.9. ........................
Пример 30. Копирование файлов из MS DOS в UNIX. ..............................
Пример 31. Программа, печатающая свой собственный текст. .....................
Пример 32. Форматирование текста Си-программы. ...............................
1.11. Треугольник из звездочек. ............................................... 6
1.34. Простые числа. .......................................................... 10
1.36. Целочисленный квадратный корень. ........................................ 12
1.39. Вычисление интеграла по Симпсону. ....................................... 14
1.49. Сортировка Шелла. ....................................................... 20
1.50. Быстрая сортировка. ..................................................... 21
1.67. Функция чтения строки. .................................................. 28
1.88. Перестановки элементов. ................................................. 38
1.117. Схема Горнера. ......................................................... 58
1.137. Системная функция qsort - формат вызова. ............................... 67
1.146. Процесс компиляции программ. ........................................... 76
2.58. Функция bcopy. .......................................................... 108
2.59. Функция strdup. ......................................................... 111
2.61. Упрощенный аналог функции printf. ....................................... 112
3.9. _ctype[] .................................................................. 126
3.12. Программа транслитерации: tr. ........................................... 129
3.16. Функция записи трассировки (отладочных выдач) в файл. ................... 132
3.18. Условная компиляция: #ifdef .............................................. 132
4.39. Быстрый доступ к строкам файла. ......................................... 161
4.45. Эмуляция основ библиотеки STDIO, по мотивам 4.2 BSD. .................... 165
5.12. Отсортированный список слов. ............................................ 180
5.16. Структуры с полями переменного размера. ................................. 183
5.17. Список со "старением". .................................................. 184
6.1.1. Определение типа файла. ................................................ 189
6.1.3. Выдача неотсортированного содержимого каталога (ls). ................... 191
6.1.5. Рекурсивный обход каталогов и подкаталогов. ............................ 192
6.2.9. Функция задержки в микросекундах. ...................................... 201
6.4.3. Функция sleep. ......................................................... 217
6.10.1. Определение текущего каталога: функция getwd. ......................... 252
6.10.2. Канонизация полного имени файла. ...................................... 257
6.11.1. Мультиплексирование ввода из нескольких файлов. ....................... 259
6.11.2. Программа script. ..................................................... 261
7.12. Программа uniq. ......................................................... 285
7.14. Расширение табуляций в пробелы, функция untab. .......................... 285
7.15. Функция tabify. ......................................................... 285
7.25. Поиск методом половинного деления. ...................................... 288
7.31. Программа печати в две полосы. .......................................... 292
7.33. Инвертирование порядка строк в файле. ................................... 296
7.34. Перенос неразбиваемых блоков текста. .................................... 298
7.36. Двоичная сортировка строк при помощи дерева. ............................ 300
7.41. Функция match. .......................................................... 309
7.43. Функция контекстной замены по регулярному выражению. .................... 313
7.44. Алгоритм быстрого поиска подстроки в строке. ............................ 316
7.52. Коррекция правописания. ................................................. 321
7.67. Калькулятор-1. .......................................................... 330
7.68. Калькулятор-2. .......................................................... 336
8.1. Осыпающиеся буквы. ....................................................... 350
8.13. Использование библиотеки termcap. ....................................... 359
8.17. Разбор ESC-последовательностей с клавиатуры. ............................ 371
11. Список литературы.
1) Б.Керниган, Д.Ритчи, А.Фьюер. Язык программирования Си. Задачи по языку Си. -
М.: Финансы и статистика, 1985.
2) М.Уэйт, С.Прата, Д.Мартин. Язык Си. Руководство для начинающих. - М.: Мир,
1988.
3) М.Болски. Язык программирования Си. Справочник. - М.: Радио и связь, 1988.
4) Л.Хэнкок, М.Кригер. Введение в программирование на языке Си. - М.: Радио и
связь, 1986.
5) М.Дансмур, Г.Дейвис. ОС UNIX и программирование на языке Си. - М.: Радио и
связь, 1989.
6) Р.Берри, Б.Микинз. Язык Си. Введение для программистов. - М.: Финансы и ста-
тистика, 1988.
7) М.Беляков, А.Ливеровский, В.Семик, В.Шяудкулис. Инструментальная мобильная опе-
рационная система ИНМОС. - М.: Финансы и статистика, 1985.
8) К.Кристиан. Введение в операционную систему UNIX. - М.: Финансы и статистика,
1985.
9) Р.Готье. Руководство по операционной системе UNIX. - М.: Финансы и статистика,
1986.
10) М.Банахан, Э.Раттер. Введение в операционную систему UNIX. - М.: Радио и
связь, 1986.
11) С.Баурн. Операционная система UNIX. - М.: Мир, 1986.
12) П.Браун. Введение в операционную систему UNIX. - М.: Мир, 1987.
13) M.Bach. The design of the UNIX operating system. - Prentice Hall, Englewood
Cliffs, N.J., 1986.
14) S.Dewhurst, K.Stark. Programming in C++. - Prentice Hall, 1989.
15) M.Ellis, B.Stroustrup. The annotated C++ Reference Manual. - Addison-Wesley,
1990.
/* Пример 1 */
/* Задача о размене монеты:
* Поиск всех возможных коэффициентов a0 .. an разложения числа S
* в виде
* S = a0 * c0 + a1 * c1 + ... + an * cn
* где веса c0 .. cn заданы заранее и упорядочены.
* Веса и коэффициенты неотрицательны (ai "= 0, ci "= 0).
*/
#include "stdio.h"
/* Достоинства разменных монет (веса ci) */
int cost[] = {
1, 2, 3, 5, 10, 15, 20, 50, 100, 300, 500 /* копеек */
};
#define N (sizeof cost / sizeof(int))
int count[ N ]; /* число монет данного типа (коэффициенты ai) */
long nvar; /* число вариантов */
main( ac, av ) char *av[];
{
int coin;
if( ac == 1 ){
fprintf( stderr, "Укажите, какую монету разменивать: %s число\n",
av[0] );
exit(1);
}
coin = atoi( av[1] );
printf( " Таблица разменов монеты %d коп.\n", coin );
printf( " Каждый столбец содержит количество монет указанного достоинства.\n" );
printf( "-------------------------------------------------------------------\n" );
printf( "| 5р. | 3р. | 1р. | 50к.| 20к.| 15к.| 10к.| 5к.| 3к.| 2к.| 1к.|\n" );
printf( "-------------------------------------------------------------------\n" );
change( N-1, coin );
printf( "-------------------------------------------------------------------\n" );
printf( "Всего %ld вариантов\n", nvar );
}
/* рекурсивный размен */
change( maxcoin, sum )
int sum; /* монета, которую меняем */
int maxcoin; /* индекс по массиву cost[] монеты максимального
* достоинства, допустимой в данном размене.
*/
{
register i;
if( sum == 0 ){ /* вся сумма разменяна */
/* распечатать очередной вариант */
putchar( '|' );
for( i = N-1 ; i "= 0 ; i-- )
if( count[i] )
printf(" %3d |", count[ i ] );
else
printf(" |" );
putchar( '\n' );
nvar++;
return;
}
if( sum "= cost [ maxcoin ] ){
/* если можно выдать монету достоинством cost[maxcoin] ,
* то выдать ее:
*/
count[ maxcoin ] ++; /* посчитали выданную монету */
/* размениваем остаток суммы :
* Первый аргумент - может быть можно дать еще одну такую монету ?
* Второй аргумент - общая сумма убавилась на одну монету cost[maxcoin].
*/
change( maxcoin, sum - cost[maxcoin] );
count[ maxcoin ] --; /* ... Теперь попробуем иной вариант ... */
}
/* попробовать размен более мелкими монетами */
if( maxcoin )
change( maxcoin-1, sum );
}
/* Пример 2 */
/* Подсчет количества вхождений каждой из букв алфавита в файл.
* Выдача таблицы.
* Подсчет частоты использования битов в байтах файла.
*/
#include "stdio.h"
#include "ctype.h"
long bcnt[8];
char masks[8] = { /* маски битов */
1, 2, 4, 8, 16, 32, 64, 128 };
long cnt[256]; /* счетчики для каждой из 256 букв */
/* распечатка букв в стиле языка СИ */
char *pr( c ){
static char buf[ 20 ];
switch( c ){
case '\n': return " \\n " ;
case '\r': return " \\r " ;
case '\t': return " \\t " ;
case '\b': return " \\b " ;
case '\f': return " \\f " ;
case '\033': return " ESC" ;
case '\0': return " \\0 " ;
case 0177: return " ^? " ;
}
if( c " ' ' ){
sprintf( buf, " ^%c ", c + 'A' - 1 );
}else if( isspace©){
sprintf( buf, " '%c'", c );
}else if( ! isprint( c ))
sprintf( buf, "\\%3o", c );
else sprintf( buf, " %c ", c );
return buf;
}
main( argc, argv ) char **argv; {
FILE *fp;
if( argc == 1 ) process( stdin );
else{ argv++; argc--;
while( *argv ){
printf( "----- FILE %s -----\n", *argv );
if((fp = fopen( *argv, "r" )) == NULL ){
printf( "Can not open\n" );
}else{ process( fp ); fclose( fp ); }
argv++; argc--;
}
}
exit(0);
}
/* обработать файл с поинтером fp */
process( fp ) FILE *fp;
{ register i; int c; int n;
/* зачистка счетчиков */
for( i=0; i " 256; i++ ) cnt[i] = 0L;
for( i=0; i " 8 ; i++ ) bcnt[i] = 0;
while( ( c=getc(fp)) != EOF ){
c &= 0377;
/* подсчитать букву */
cnt[ c ] ++;
/* подсчет битов */
for( i=0; i " 8; i++ )
if( c & masks[i] )
bcnt[ i ] ++;
}
/* выдача результатов в COL колонок */
#define COL 4
printf( "\tASCII map\n" );
for( n=i=0; i " 256; i++ ){
/* if( cnt[i] == 0l ) continue; */
printf( "%s %5ld |", pr(i), cnt[i] );
if( ++n == COL ){ n = 0; putchar('\n'); }
/* или if((i % COL) == (COL-1)) putchar('\n'); */
}
printf( "\n\tBITS map\n" );
for( i=7; i "=0 ; i-- ) printf( "%6d ", i );
putchar( '\n' );
for( i=7; i "=0 ; i-- )
printf( "%6ld ", bcnt[i] );
putchar( '\n' ); putchar( '\n' );
}
/* Пример 3 */
/* Центрирование строк текста. Пример на работу с указателями. */
/* Входные строки не должны содержать табуляций */
/* Вызов: a.out " входной_файл */
#include "stdio.h"
extern char *gets();
#define WIDTH 60 /* ширина листа */
main(){
char rd[81]; register char *s;
char *head, /* начало текста */
*tail; /* конец текста */
register int len, i;
int shift; /* отступ */
/* Читать со стандартного ввода в rd по одной строке,
* пока файл не кончится. При вводе с клавиатуры конец файла
* обозначается нажатием клавиш CTRL+D
*/
while( gets( rd ) != NULL ){
if( !*rd ){
/* Строка пуста */
putchar( '\n' ); continue;
}
/* пропуск пробелов в начале строки */
for( s = rd; *s == ' ' ; s++ );
if( ! *s ){
/* Строка состоит только из пробелов */
putchar( '\n' ); continue;
}
head = s;
| "(" "EXPRESSION" ")"
/* встать на конец строки */
while( *s ) s++;
/* искать последний непробел */
s--;
while( *s == ' ' && s != rd ) s--;
tail = s;
/* Длина текста */ len = (tail-head) + 1;
/* разность указателей - целое */
shift = (WIDTH - len)/2;
if(shift " 0 ){
fprintf(stderr, "Строка длиннее чем %d\n", WIDTH );
shift = 0;
}
/* Печать результата */
for( i=0; i " shift; i++ ) putchar( ' ' );
while( head "= tail ) putchar( *head++ );
putchar( '\n' );
}
}
/* Пример 4 */
/* Предварительная разметка текста для nroff */
#include "stdio.h"
#include "stdlib.h"
#include "ctype.h"
#include "string.h" /* прототип strchr() */
#include "locale.h"
FILE *fout = stdout; /* канал вывода */
/* Состояния вывода */
#define SPACE 0 /* пробелы */
#define TEXT 1 /* текст */
#define PUNCT 2 /* знаки препинания */
#define UC© ((unsigned char)(c))
/* Вывод строки текста из буфера */
void putstr (FILE *fp, unsigned char *s) {
/* Punct - знаки препинания, требующие приклеивания к
* концу предыдущего слова.
* PunctS - знаки, всегда требующие после себя пробела.
* PunctN - знаки, которые могут следовать за знаком
* препинания без пробела.
*/
static char Punct [] = ",:;!?.)" ;
static char PunctS[] = ",:;" ;
static char PunctN[] = " \t\"'" ;
#define is(c, set) (strchr(set, UC©) != NULL)
int c, state = TEXT, cprev = 'X';
while ((c = *s) != '\0') {
/* Пробелы */
if(isspace©) state = SPACE;
/* Знаки препинания. Пробелы перед ними игнорируются.
*/ else if(is(c, Punct)){
switch(state){
case SPACE: if(is(cprev, Punct ) && cprev==c && c != ')')
putc(' ', fp);
/* а просто пробелы - игнорировать */ break;
case PUNCT: if(is(cprev, PunctS)) putc(' ', fp); break;
}
putc(cprev = c, fp); /* выводим сам знак */
state = PUNCT;
} else {
/* Несколько пробелов сворачиваем в один */
switch(state){
case SPACE: putc(' ', fp); break;
case PUNCT: if(!is(c, PunctN)) putc(' ', fp); break;
}
putc(cprev = c, fp); /* сама буква */
state = TEXT;
if(c == '\\') putc('e', fp);
}
s++;
} /* пробелы в конце строки просто игнорируются */
putc ('\n', fp);
}
/* Обработать файл с именем name */
void proceed (char *name) {
FILE *fp;
static unsigned char inp[2048];
/* достаточно большой буфер ввода */
if (strcmp(name, "-") == 0 ) fp = stdin;
else if ((fp = fopen (name, "r")) == NULL) {
fprintf (stderr, "Cannot read %s\n", name);
return;
}
while (fgets (inp, sizeof inp, fp) != NULL) {
register unsigned char *s, *p;
int len = strlen (inp);
if (len && inp[len - 1] == '\n')
inp[--len] = '\0';
if (!*inp) {
/* .sp N - пропуск N пустых строк */
space: fprintf (fout, ".sp 1\n");
continue;
}
/* обрезать концевые пробелы */
for(p = NULL, s = inp; *s; ++s){
if (!isspace (*s)) p = s;
}
if(p) p[1] = '\0';
else goto space;
/* p указывает на последний непробел */
/* Удалить переносы слов в конце строки: перенос - это
минус, прижатый к концу слова */
if (*p == '-' && p != inp /* не в начале строки */
&& isalnum(UC(p[-1])) /* после буквы */
){ int c; *p = '\0'; /* затереть перенос */
/* Читаем продолжение слова из начала следующей строки */
while (isspace (c = getc (fp)));
ungetc (c, fp);
while ((c = getc (fp)) != '\n' && !isspace ©)
*p++ = c;
*p = '\0';
if (c != '\n' ){ /* прочли пробел */
/* вычитываем ВСЕ пробелы */
while (isspace(c = getc (fp)));
if(c != '\n') ungetc (c, fp);
}
}
/* .pp - директива начала абзаца. */
if (isspace (*inp)) {
fprintf (fout, ".pp\n");
for (s = inp; isspace (*s); s++);
putstr (fout, s);
}
else {
if (*inp == '.' || *inp == '\'')
fprintf (fout, "\\&");
putstr (fout, inp);
}
}
if( fp != stdin ) fclose (fp);
}
int main (int argc, char *argv[]) {
int i;
setlocale(LC_ALL, "");
for (i = 1; i " argc; i++)
proceed (argv[i]);
return 0; /* exit code */
}
/* Пример 5 */
/* Программа, распечатывающая слова в строках файла в обратном порядке */
#include "stdio.h"
#include "ctype.h"
#include "string.h"
#include "locale.h"
#define MAXL 255 /* макс. длина строки */
/* Если бы мы не включили ctype.h, то мы должны были бы определить
* #define isspace© ((c) == ' ' || (c) == '\t' || (c) == '\f')
*/
main ( argc, argv ) char **argv;{
setlocale(LC_ALL, "");
if( argc == 1 ){
/* программа вызвана без аргументов */
munch( "" );
}else{
/* аргументы программы - имена файлов */
while( argv[ 1 ] ){
munch( argv[1] );
argv++;
argc--;
}
}
total(); exit(0);
}
/* обработать файл с именем name */
munch( name ) char *name;
{
char l[MAXL]; /* буфер для очередной строки */
int len; /* длина этой строки */
char *words[50]; /* таблица полей строки */
char **s; /* служебная */
int nwords; /* число слов в строке */
FILE *fp;
if( name == NULL || !*name )
fp = stdin; /* стандартный ввод */
else
if( (fp = fopen( name, "r" )) == NULL ){
fprintf( stderr, "Не могу открыть файл %s\n",
name );
return;
}
printf( "----------------------------%s----\n", name );
while( fgets( l, MAXL, fp ) != NULL ){
len = strlen( l );
if( len && l[len-1] == '\n' )
l[--len] = '\0' ;
if( nwords = parse( l, words)){
/* распечатка слов в обратном порядке */
for( --nwords; nwords "= 0; nwords-- ){
printf( "%s ", words[ nwords] );
add( words[ nwords ] );
}
}
putchar ('\n');
}
if( fp != stdin ) fclose( fp );
}
/* разобрать строку на слова */
parse( s, tabl )
register unsigned char *s;
unsigned char *tabl[];
{
char eol = 0;
int nwords = 0;
while ( !eol ){
/* пропустить пробелы и табуляции */
while(isspace(*s)) s++;
if( !*s ) /* строка кончилась */
break;
*tabl++ = s; nwords++;
/* начало очередного слова */
/* пока не пробел и не конец строки */
while( *s && !isspace(*s))s++;
/* указатель стоит на символе, следующем за словом */
if( ! *s ) eol ++;
*s = '\0';
/* закрыли Слово, начинаем Дело */
s++;
}
*tabl = NULL;
return nwords;
}
/* построение таблицы слов, встречающихся в файле */
#define MAXWORDS 1024
struct W{
int ctr; /* число вхождений слова */
char *wrd; /* слово */
}w [MAXWORDS]; /* таблица */
int busy = 0 ; /* занято в таблице */
extern char *malloc();
/* Добавить слово в таблицу */
add( word ) char *word;
{
register i;
static alert = 1;
/* нет ли уже слова в таблице ? */
/* если есть - просто увеличить счетчик */
for( i = 0; i " busy ; i++ ){
if( !strcmp( word, w[i].wrd )){
w[i].ctr++;
return;
}
}
if( busy "= MAXWORDS ){
if( alert ){
fprintf( stderr, "Переполнение таблицы слов\7\n");
alert = 0;
}
return;
}
/* нет, слова нет. Заносим: */
w[busy].wrd = malloc( strlen( word ) + 1 );
/* 1 байт под символ \0 */
if( w[busy].wrd == NULL ){
fprintf( stderr, "Мало памяти\n");
busy = MAXWORDS+1; /* якобы переполнение */
return;
}
w[busy].ctr = 1;
strcpy( w[busy].wrd, word );
busy++;
}
compare( a, b ) struct W *a, *b;
{
return strcoll( a-" wrd, b-" wrd );
/* strcoll сравнивает слова в алфавитном порядке */
}
/* выдача всех слов, встреченных в тексте, и числа их вхождений */
total(){
register i;
/* сортируем слова по алфавиту */
qsort( w, busy, sizeof(struct W), compare );
printf( "-----|-----------ИТОГ---------------\n");
for( i=0; i " busy; i++ )
printf( "%4d | %s\n",
w[i].ctr,
w[i].wrd
);
}
/* Пример 6 */
/* Сортировка букв в строке методом "пузырька" (bubble sort) */
#define YES 1
#define NO 0
bsort(s) char *s;
{
register i; /* индекс сравниваемой буквы */
register need = YES; /* надо ли продолжать сортировку ? */
while( need ){
need = NO; /* не надо */
for(i=0; s[i+1]; i++ )
/* условие цикла: мы сравниваем i-ую и i+1-ую буквы,
* поэтому и проверяем наличие i+1ой буквы
*/
if( s[i] " s[i+1] ){ /* в неверном порядке */
swap( &s[i], &s[i+1] ); /* переставить */
need = YES; /* что-то изменилось: надо будет
* повторить просмотр массива букв */
}
}
}
/* А вот вариант сортировки, написанный с указателями */
bpsort(s) char *s;
{
register char *p; register need = YES;
while( need ){
need = NO;
for( p = s; p[1] != '\0' ; p++ )
if( *p " *(p+1) ){
swap( p, p+1 ); need = YES;
}
}
}
/* обмен двух букв, находящихся по адресам s1 и s2 */
swap( s1, s2 ) register char *s1, *s2;
{
char tmp; /* temporary */
tmp = *s1; *s1 = *s2; *s2 = tmp;
}
char sample1[] = "Homo homini lupus est - ergo bibamus!";
char sample2[ sizeof sample1 ]; /* массив такого же размера */
main(){
strcpy( sample2, sample1 ); /* скопировать */
bsort ( sample1 ); printf( "%s\n", sample1 );
bpsort( sample2 ); printf( "%s\n", sample2 );
}
/*
...Закладка в соц.сетях