Главная · Поиск книг · Поступления книг · 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 ... 56 57 58 59 60 61 62  63 64 65 66 67 68 69 ... 87
                                     * на наличие лишних букв
                                     */
                                    if(i==1) max = 4;
                            }
                    }
            }
            return total;
    }

А. Богатырев, 1992-95                  - 327 -                              Си в UNIX

    void main(){
            uchar inpbuf[BUFSIZ];
            int n;
            uchar *reply, **ptr;

            setlocale(LC_ALL, "");
            for(ptr = words; *ptr; ptr++)
                    printf("#\t%s\n", *ptr);

            do{
                    printf("> "); fflush(stdout);
                    if(gets((char *)inpbuf) == NULL) break;

                    switch(spellmatch(inpbuf, words, &reply)){
                    case -1:
                            printf("Нет такого слова\n"); break;
                    case 0:
                            printf("Слово '%s'\n", reply); break;
                    default:
                            printf("Неоднозначно\n");
                    }
            } while(1);
    }

7.53.  Пока я сам писал эту программу, я  сделал  две  ошибки,  которые  должны  быть
весьма характерны для новичков. Про них надо бы говорить раньше, в главе про строки и
в самой первой главе, но тут они пришлись как раз к месту.  Вопрос: что печатает сле-
дующая программа?

    #include 

    char *strings[] = {
            "Первая строка"
            "Вторая строка"
            "Третяя строка",
            "Четвертая строка",
            NULL
    };

    void main(){
            char **p;
            for(p=strings;*p;++p)
                    printf("%s\n", *p);
    }

А печатает она вот что:

    Первая строкаВторая строкаТретяя строка
    Четвертая строка

Дело в том, что ANSI компилятор Си склеивает строки:

            "начало строки"     "и ее конец"

если они разделены пробелами в смысле isspace, в том числе и пустыми строками.   А  в
нашем объявлении массива строк strings мы потеряли несколько разделительных запятых!
     Вторая ошибка касается того, что можно забыть поставить слово break в  операторе
switch, и долго после этого гадать о непредсказуемом поведении любого поступающего на
вход значения.  Дело просто: пробегаются все случаи, управление проваливается из case
в  следующий case, и так много раз подряд!  Это и есть причина того, что в предыдущем

А. Богатырев, 1992-95                  - 328 -                              Си в UNIX

примере все case оформлены нетривиальным макросом Bcase.

7.54.  Составьте программу кодировки и раскодировки файлов по заданному ключу (строке
символов).

7.55.  Составьте программу, которая запрашивает анкетные данные типа фамилии,  имени,
отчества,  даты рождения и формирует файл.  Программа должна отлавливать ошибки ввода
несимвольной и нецифровой информации, выхода составляющих даты рождения за допустимые
границы с выдачей сообщений об ошибках. Программа должна давать возможность корректи-
ровать вводимые данные. Все данные об одном человеке записываются в одну строку файла
через  пробел.   Вот  возможный  пример  части  диалога (ответы пользователя выделены
жирно):

    Введите месяц рождения [1-12]: 14  <<ENTER>>
    *** Неправильный номер месяца (14).
    Введите месяц рождения [1-12]: март  <<ENTER>>
    *** Номер месяца содержит букву 'м'.
    Введите месяц рождения [1-12]: <<ENTER>>
    Вы хотите закончить ввод ? n
    Введите месяц рождения [1-12]: 11  <<ENTER>>
            Ноябрь
    Введите дату рождения  [1-30]: _

В таких программах обычно ответ пользователя вводится как строка:

    printf("Введите месяц рождения [1-12]: ");
    fflush(stdout); gets(input_string);

затем (если надо) отбрасываются лишние пробелы в начале и в конце строки, затем  вве-
денный  текст  input_string  анализируется на допустимость символов (нет ли  в нем не
цифр?), затем строка преобразуется к нужному типу (например, при помощи функции  atoi
переводится в целое) и проверяется допустимость полученного значения, и.т.д.
     Вводимую информацию сначала заносите в структуру; затем  записывайте  содержимое
полей структуры в файл в текстовом виде (используйте функцию fprintf, а не fwrite).

7.56.  Составьте программу, осуществляющую выборку информации из файла,  сформирован-
ного в предыдущей задаче, и ее распечатку в табличном виде.  Выборка должна осуществ-
ляться по значению любого заданного поля (т.е. вы выбираете поле, задаете его  значе-
ние  и получаете те строки, в которых значение указанного поля совпадает с заказанным
вами значением).  Усложнение: используйте функцию сравнения строки с регулярным выра-
жением  для выборки по шаблону поля (т.е. отбираются только те строки, в которых зна-
чение заданного поля удовлетворяет шаблону).  Для чтения  файла  используйте  fscanf,
либо  fgets  и затем sscanf. Второй способ лучше тем, что позволяет проверить по шаб-
лону значение любого поля - не только текстового, но и числового: так 1234 (строка  -
изображение числа) удовлетворяет шаблону "12*".

7.57.  Составьте вариант программы подсчета служебных слов языка Си,  не  учитывающий
появление этих слов, заключенных в кавычки.

7.58.  Составьте программу удаления из программы на языке Си всех комментариев. Обра-
тите  внимание на особые случаи со строками в кавычках и символьными константами; так
строка

    char s[] = "/*";

не является началом комментария!  Комментарии записывайте в отдельный файл.

7.59.  Составьте программу выдачи перекрестных ссылок, т.е.  программу, которая выво-
дит  список  всех идентификаторов переменных, используемых в программе, и для каждого
из идентификаторов выводит список номеров строк, в которые он входит.

А. Богатырев, 1992-95                  - 329 -                              Си в UNIX

7.60.  Разработайте простую версию препроцессора для обработки  операторов  #include.
В  качестве  прототипа такой программы можно рассматривать такую (она понимает дирек-
тивы вида #include имяфайла - без <> или "").

    #include 
    #include 
    #include 

    char KEYWORD[] = "#include ";   /* with a trailing space char */

    void process(char *name, char *from){
            FILE *fp;
            char buf[4096];

            if((fp = fopen(name, "r")) == NULL){
                    fprintf(stderr, "%s: cannot read \"%s\", %s\n",
                                     from, name, strerror(errno));
                    return;
            }
            while(fgets(buf, sizeof buf, fp) != NULL){
                    if(!strncmp(buf, KEYWORD, sizeof KEYWORD - 1)){
                            char *s;

                            if((s = strchr(buf, '\n')) != NULL) *s = '\0';
                            fprintf(stderr, "%s: including %s\n",
                                             name, s = buf + sizeof KEYWORD - 1);
                            process(s, name);
                    } else  fputs(buf, stdout);
            }
            fclose(fp);
    }
    int main(int ac, char *av[]){
            int i;

            for(i=1; i < ac; i++)
                    process(av[i], "MAIN");
            return 0;
    }

7.61.  Разработайте простую версию препроцессора для  обработки  операторов  #define.
Сначала реализуйте макросы без аргументов.  Напишите обработчик макросов вида

    #macro имя(аргу,менты)
      тело макроса - можно несколько строк
    #endm

7.62.  Напишите программу, обрабатывающую определения #ifdef, #else, #endif.  Учтите,
что эти директивы могут быть вложенными:

    #ifdef    A
    # ifdef   B
       ...             /*  defined(A) && defined(B) */
    # endif /*B*/
       ...             /*  defined(A) */
    #else   /*not A*/
       ...             /* !defined(A) */
    # ifdef   C
       ...             /* !defined(A) && defined(C) */
    # endif /*C*/

А. Богатырев, 1992-95                  - 330 -                              Си в UNIX

    #endif  /*A*/

7.63.  Составьте программу моделирования простейшего калькулятора, который  считывает
в  каждой строчке по одному числу (возможно со знаком) или по одной операции сложения
или умножения, осуществляет операцию и выдает результат.

7.64.  Составьте программу-калькулятор, которая производит операции сложения, вычита-
ния,  умножения, деления; операнды и знак арифметической операции являются строковыми
аргументами функции main.

7.65.  Составьте программу, вычисляющую  значение  командной  строки,  представляющей
собой  обратную  польскую  запись  арифметического  выражения.  Например, 20 10 5 + *
вычисляется как 20 * (10 + 5) .

7.66.  Составьте функции работы со стеком:
-    добавление в стек
-    удаление вершины стека (с возвратом удаленного значения)
Используйте два варианта: стек-массив и стек-список.

7.67.  Составьте программу, которая использует функции работы со стеком для  перевода
арифметических выражений языка Си в обратную польскую запись.

    /*#!/bin/cc $* -lm
     * Калькулятор. Иллюстрация алгоритма превращения выражений
     * в польскую запись по методу приоритетов.
     */

    #include 
    #include  /* extern double atof();            */
    #include    /* extern double sin(),  ...        */
    #include   /* isdigit(), isalpha(), ...        */
    #include  /* jmp_buf                          */

    jmp_buf AGAIN;             /* контрольная точка */
    err(n){ longjmp(AGAIN,n);} /* прыгнуть в контрольную точку */

А. Богатырев, 1992-95                  - 331 -                              Си в UNIX

    /* ВЫЧИСЛИТЕЛЬ --------------------------------------- */
    /* Если вместо помещения операндов в стек stk[] просто
     * печатать операнды, а вместо выполнения операций над
     * стеком просто печатать операции, мы получим "польскую"
     * запись выражения:
     *      a+b       ->      a b +
     *      (a+b)*c   ->      a b + c *
     *      a + b*c   ->      a b c * +
     */
    /* стек вычислений */
    #define MAXDEPTH 20 /* глубина стеков */
    int sp;             /* указатель стека (stack pointer) */
    double stk[MAXDEPTH];

    double dpush(d) double d; /* занести число в стек */
    {
       if( sp == MAXDEPTH ){ printf("Стек операндов полон\n");err(1);}
       else return( stk[sp++] = d );
    }

    double dpop(){            /* взять вершину стека */
       if( !sp ){ printf("Стек операндов пуст\n"); err(2); }
       else return stk[--sp];
    }

    static double r,p; /* вспомогательные регистры */
    void add()    { dpush( dpop() + dpop()); }
    void mult()   { dpush( dpop() * dpop()); }
    void sub()    { r = dpop(); dpush( dpop() - r); }
    void divide() { r = dpop();
      if(r == 0.0){ printf("Деление на 0\n"); err(3); }
      dpush( dpop() / r );
    }
    void pwr() { r = dpop(); dpush( pow( dpop(), r )); }
    void dup() { dpush( dpush( dpop())); }
    void xchg(){ r = dpop(); p = dpop(); dpush(r); dpush(p); }
    void neg() { dpush( - dpop()); }
    void dsin(){ dpush( sin( dpop())); }
    void dcos(){ dpush( cos( dpop())); }
    void dexp(){ dpush( exp( dpop())); }
    void dlog(){ dpush( log( dpop())); }
    void dsqrt(){ dpush( sqrt( dpop())); }
    void dsqr(){ dup(); mult(); }
    /* M_PI и M_E определены в  */
    void pi()  { dpush( M_PI /* число пи */ ); }
    void e()   { dpush( M_E  /* число e  */ ); }
    void prn() { printf("%g\n", dpush( dpop())); }
    void printstk(){
      if( !sp ){ printf("Стек операндов пуст\n"); err(4);}
      while(sp) printf("%g ", dpop());
      putchar('\n');
    }

А. Богатырев, 1992-95                  - 332 -                              Си в UNIX

    /* КОМПИЛЯТОР ---------------------------------------- */
    /* номера лексем */
    #define END        (-3)         /* = */
Предыдущая страница Следующая страница
1 ... 56 57 58 59 60 61 62  63 64 65 66 67 68 69 ... 87
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 

Реклама