Главная · Поиск книг · Поступления книг · Top 40 · Форумы · Ссылки · Читатели

Настройка текста
Перенос строк


    Прохождения игр    
Demon's Souls |#13| Storm King
Demon's Souls |#11| Мaneater part 2
Demon's Souls |#10| Мaneater (part 1)
Demon's Souls |#9| Heart of surprises

Другие игры...


liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня
Rambler's Top100
Образование - Богатырев А. Весь текст 1009.15 Kb

Хрестоматия по программированию на Си в Unix

Предыдущая страница Следующая страница
1 ... 71 72 73 74 75 76 77  78 79 80 81 82 83 84 ... 87
struct data{
        short b_key;            /* ключ */
        char  b_val[VLEN];      /* строка-значение */
};

char  BASEF[] = ".base" ;       /* имя файла базы */
FILE *fbase;                    /* pointer на базу */
struct data tmp;                /* вспомогательная переменная */

void
initBase (void){
        /* fopen: r  read  (чтение)
         *        w  write (запись), файл пересоздается.
         * (создается, если не было, если был - опустошается).
         *        r+ чтение и запись (файл уже существует).
         *        w+ чтение и запись (создается пустой файл).
         *        a  append (запись в конец файла), создать если нет:
         *           имеется в виду, что КАЖДАЯ операция записи сначала
         *           ставит указатель записи на конец файла.
         * В MS DOS нетекстовый файл НЕОБХОДИМО открывать как
         *        rb wb rb+ wb+ ab+  иначе ничего не будет работать.
         */
        if(( fbase = fopen( BASEF, "r+" )) == NULL ){
                if(( fbase = fopen( BASEF, "w+" )) == NULL ){
                     fprintf( stderr, "Не могу открыть базу данных %s\n",
                              BASEF );
                     exit(1);
                }
                fprintf( stderr, "База создана\n" );
        }
}

void
closeBase (void){
        fclose( fbase );
}
/* Учтите, что если вы записываете в файл структуры, то в файле
не будет разделения на строки - файл НЕТЕКСТОВЫЙ! Поэтому и
читать такой файл можно только структурами: read(), fread()
(но не scanf-ом и не fgets-ом)
 */

/* Поиск по ключу .
   Выдать (-1), если записи с данным ключом нет,
   иначе   - номер слота, где содержится запись с данным ключом.
 */
int
bget (int key)
{
        int n;

        /* последовательно просмотреть весь файл */
        rewind( fbase );
        /* в начало файла. Равно fseek(fbase, 0L, 0); */

        n = 0 ;
        /* int    сколько_элементов_массива_действительно_считано =
         * fread( адрес_массива_куда_считывать,
         *        размер_одного_элемента_массива,
         *        сколько_элементов_считывать_в_массив, канал );
         * Заметьте, что количество данных задается НЕ в байтах,
         * а в 'штуках'
         */
        while( fread( &tmp, sizeof( tmp ), 1, fbase ) == 1 ){
                if( tmp.b_key == key )
                        return n;
                n++;
        }
        return (-1);    /* не найдено */
}

/* модифицировать запись с индексом ind */
void
bmod (
    int ind,
    int key,       /* новый ключ */
    char *val      /* новое значение */
)
{
        struct data new;

        fseek( fbase, (long) sizeof( struct data ) * ind, 0 );
        new.b_key = key;
        strncpy( new.b_val, val, VLEN );
        /* int    сколько_элементов_массива_действительно_записано =
         * fwrite( адрес_массива_который_записывать,
         *         размер_одного_элемента_массива,
         *         сколько_элементов_массива_записывать, канал );
         */
        if( fwrite( &new, sizeof new , 1, fbase ) != 1 )
            fprintf( stderr, "Ошибка записи.\n" );
}

/* удаление записи по ключу */
int
bdel (int key){
        int ind = bget( key );
        if( ind == -1 )
                return (-1);        /* записи с таким ключом нет */
        bmod( ind, KEY_FREE, "" );  /* записать признак свободного места */
        return 0;
}

/* Служебная процедура дописи к концу файла */
void
bappend (int key, char *val)
{
                struct data new;

                /* встать на конец файла */
                fseek( fbase, 0L, 2 );

                /* и записать новую структуру в конец */
                new.b_key = key;
                strncpy( new.b_val, val, VLEN );
                fwrite( &new, sizeof( struct data ) , 1, fbase );
}

/* добавление новой записи. Если запись с таким ключом уже есть -
   выдать ошибку
 */
int
bput (int key, char *val)
{
        int i = bget( key );
        if( i != -1 )
                return (-1);    /* запись уже есть */

        /* найти свободное место */
        i = bget( KEY_FREE );
        if( i == -1 ) {         /* нет свободных мест */
                bappend( key, val );
                return 0;
        }
        /* иначе свободное место найдено.
         * Заменяем дырку на полезную информацию */
        bmod( i, key, val );
}

/* распечатать всю базу данных подряд */
void
bprint (void){
        int n;
        int here = 0;

        rewind( fbase );
        n = 0;
        printf( "-номер--ключ-------значение-----------------\n" );
        while( fread( &tmp, sizeof tmp, 1, fbase ) == 1 ){
                if( tmp.b_key == KEY_FREE ){
                        n++;
                        continue;
                }
                printf( "#%-2d| %6d\t| %s\n", n, tmp.b_key, tmp.b_val );
                here ++; n++;
        }
        printf( "--------------------------------------------\n" );
        printf( "Длина базы:%d Занято:%d\n\n", n, here );
}

/* замена поля val у записи с ключом key */
int
bchange (int key, char *val)
{
        int ind;

        ind = bget( key );
        if( ind == -1 ){
                /* запись с таким ключом не существует */
                /* Добавить как новую запись */
                bput( key, val );
                return 0;
        }
        bmod( ind, key, val );
        return 1;
}

/* Аналогичная функция, но использующая другой способ.
 * Кроме того, если такой ключ отсутствует - ничего не делается
 */
int
bchg (int key, char *val)
{
        struct data d;

        rewind( fbase );        /* в начало файла */
        while( fread( &d, sizeof d, 1, fbase ) == 1 ){
                /* поиск ключа */
                if( d.b_key == key ){
                        /* вернуться назад от текущей позиции */
                        fseek( fbase, - (long) sizeof d, 1 );
                        /* не годится   (long)-sizeof d !!! */

                        d.b_key = key;
                        strncpy( d.b_val, val, VLEN );
                        fwrite( &d, sizeof d, 1, fbase );

                        /* между fread и fwrite должен быть
                         * хоть один fseek. (магическое заклинание!)
                         */
                        fseek( fbase, 0L, 1);  /* никуда не сдвигаться */
                        return 0;              /* сделано */
                }
        }
        return (-1);    /* такого ключа не было */
}

/* Пример */
void
main (void){
        int i;

        initBase();
        bprint();
        bdel( 8 );

        printf( "Создаем базу данных\n" );
        bput( 1, "строка 1" );
        bput( 2, "строка 2" );
        bput( 3, "строка 3" );
        bput( 4, "строка 4" );
        bprint();

        printf( "Удаляем записи с ключами 1 и 3\n" );
        bdel( 1 );
        bdel( 3 );
        bprint();

        printf( "Добавляем записи 5, 6 и 7\n" );
        bput( 5, "строка 5" );
        bput( 6, "строка 6" );
        bput( 7, "строка 7" );
        bprint();

        printf( "Заменяем строку в записи с ключом 2\n" );
        bchange( 2, "новая строка 2" );
        bprint();

        printf( "Заменяем строку в записи с ключом 4\n" );
        bchg( 4, "новая строка 4" );
        bprint();

        printf( "Заменяем строку в записи с ключом 6 и ключ 6 на 8\n" );
        i = bget( 6 );
        printf( "Сейчас запись с ключом 6 содержит \"%s\"\n",
                tmp.b_val );
        bmod( i, 8, "Новая строка 6/8" );
        bprint();

        closeBase();
}

        /*      Пример 9       */
/* Вставка/удаление строк в файл */
#include 

#define INSERT_BEFORE 1         /* Вставить строку перед указанной */
#define INSERT_AFTER  2         /* Вставить строку после указанной */
#define DELETE        3         /* Удалить строку  */
#define REPLACE       4         /* Заменить строку */

/* К каждой строке linenum должно относиться не более 1 операции !!! */
struct lineop {
    char    op;                 /* Операция                     */
    long    linenum;            /* Номер строки в файле (с 0)   */
    char   *str;                /* Строка (или NULL для DELETE) */
};

long lineno;                          /* номер текущей строки */
int fileChange (char *name,           /* имя файла */
                struct lineop ops[],  /* задание   */
                int nops              /* число элементов в массиве ops[] */
){
    FILE     *fin, *fout;
    static   char   TMPNAME[] = "  ?  ";
    char     buffer[BUFSIZ];
    register i;
    struct   lineop tmpop;

    if ((fin = fopen (name, "r")) == NULL)
         return (-1);
    if ((fout = fopen (TMPNAME, "w")) == NULL) {
         fclose (fin); return (-1);
    }
    lineno = 0L;
    while (fgets (buffer, BUFSIZ, fin) != NULL) {
        if( nops ) for (i = 0; i < nops; i++)
            if (lineno == ops[i].linenum) {
                switch (ops[i].op) {
                    case DELETE: /* удалить */
                        break;
                    case INSERT_BEFORE: /* вставить перед */
                        fprintf (fout, "%s\n", ops[i].str);
                        fputs (buffer, fout);
                        break;
                    case INSERT_AFTER: /* вставить после */
                        fputs (buffer, fout);
                        fprintf (fout, "%s\n", ops[i].str);
                        break;
                    case REPLACE: /* заменить */
                        fprintf (fout, "%s\n", ops[i].str);
                        break;
                }
           /* переставить выполненную операцию в конец массива и забыть */
                tmpop = ops[nops-1]; ops[nops-1] = ops[i]; ops[i] = tmpop;
                nops--; goto next;
            }
    /* иначе строка не числится в массиве ops[] : скопировать */
        fputs (buffer, fout);
next:
        lineno++;
    }
    fclose (fin); fclose (fout); rename (TMPNAME, name);
    return nops;  /* число несделанных операций (0 - все сделано) */
}

struct lineop myops[] = {
        { DELETE,         2L,     NULL                 },
        { INSERT_BEFORE,  0L,     "inserted before 0"  },
        { INSERT_BEFORE,  10L,    "inserted before 10" },
        { INSERT_AFTER,   5L,     "inserted after 5"   },
        { DELETE,         6L,     NULL                 },
        { INSERT_AFTER,   8L,     "inserted after 8"   },
        { INSERT_AFTER,   12L,    "inserted after 12"  },
        { REPLACE,        3L,     "3 replaced"         }
};

void main( void ){
  int n;
  n = fileChange( "aFile", myops, sizeof(myops)/sizeof(struct lineop));
  printf( "Строк в файле: %ld; осталось операций: %d\n", lineno, n);
}
/*
исходный файл            получившийся файл
line 0                   inserted before 0
line 1                   line 0
line 2                   line 1
line 3                   3 replaced
line 4                   line 4
line 5                   line 5
line 6                   inserted after 5
line 7                   line 7
line 8                   line 8
line 9                   inserted after 8
line 10                  line 9
                         inserted before 10
                         line 10
                Строк в файле: 11; осталось операций: 1
*/

        /* Пример 10 */

/* Проблема: позволить делать вызов free(ptr)
 * на данные, не отводившиеся malloc()-ом.
 * Решение: вести список всех данных,
 * отведенных malloc()ом.
 * Возможно также отслеживание диапазона адресов,
 * но последнее является машинно-зависимым решением.
 *
 * При большом количестве файлов эта программа - неплохой тест
 * производительности машины!
 */
#include 
#include 
#include 

typedef struct _cell {
        void *addr;
Предыдущая страница Следующая страница
1 ... 71 72 73 74 75 76 77  78 79 80 81 82 83 84 ... 87
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 

Реклама