Новые книги

Вы собираетесь приобрести ноутбук или только что купили его? Причем для вас это первый компьютер? Тогда данная книга – то, что вам нужно. Прочитав ее, вы узнаете, как правильно выбрать ноутбук. Вы застрахуете себя от покупки бракованного товара и не потеряете деньги, приобретя компьютер по завышенной цене. В книге рассказано о типах современных ноутбуков, об их возможностях, а также о расширении потенциала компьютера за счет подключаемых устройств и аксессуаров. Автор описывает такие важнейшие моменты, как установка операционной системы и работа в ней, интеграция ноутбука в локальную сеть и подключение к Интернету с помощью беспроводных технологий, использование различных программ и обеспечение безопасности. Видеокурс, который прилагается к книге, сделает вашу работу на ноутбуке гораздо эффективнее.
Несколько слов об особенностях JavaScript, другими словами - что я знал об этом языке до начала его изучения. Первое и главное: JS код легко интегрируется в HTML разметку и является де факто стандартом для интернет браузеров. Из этого следует, что если вы совершенно не знаете HTML - JS, вероятнее всего, будет для вас бесполезна. В данном опусе я постараюсь разжевать всё максимально детально, но надо иметь в виду, что HTML и JS идут бок о бок, дополняя, а не заменяя друг друга. Для тех, кто сталкивался раньше с Delphi программированием или чем-то подобным можно, в первом приближении, привести такую аналогию: HTML - это форма, а JS - сам код программы.

Другая важная особенность языка - высокая интерактивность. Процитирую фразу, которую мне многократно доводилось слышать: "JavaScript - это событийно ориентированный язык программирования". Что это значит? Это означает, что вы можете написать кусок кода, который выполнится когда пользователь нажмёт на кнопку, можете написать кусок кода, который выполнится когда вы только подведёте к ней курсор мышки. Для Java Script и то и другое - события и она умеет на них реагировать.

Отличительная особенность языка и кода на нём - то, что результат можно увидеть имея лишь один из современных браузеров. То есть вам не нужно ставить и настраивать какие-то компиляторы, среды программирования и так далее. Для запуска любого из приведённых ниже примеров - достаточно набрать текст в любом редакторе (блокноте, например), изменить расширение на html и открыть при помощи браузера. Всё.

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

8.18.

Напишите функцию для "экранного" редактирования вводимой строки в режиме CBREAK. Напишите аналогичную функцию на curses-е. В curses-ной версии надо уметь отрабатывать: забой (удаление символа перед курсором), отмену всей строки, смещение влево/вправо по строке, удаление символа над курсором, вставку пробела над курсором, замену символа, вставку символа, перерисовку экрана. Учтите, что параллельно с изменением картинки в окне, вы должны вносить изменения в некоторый массив (строку), которая и будет содержать результат. Эта строка должна быть аргументом функции редактирования.

Забой можно упрощенно эмулировать как

    addstr( "\b \b" );
или
    addch( '\b' ); delch();
Недостатком этих способов является некорректное поведение в начале строки (при x==0).

Исправьте это!

8.19.

На curses-е напишите функцию редактирования текста в окне. Функция должна возвращать массив строк с обрезанными концевыми пробелами. Вариант: возвращать одну строку, в которой строки окна разделяются символами '\n'.

8.20.

Напишите функцию, рисующую прямую линию из точки (x1,y1) в (x2,y2). Указание: используйте алгоритм Брезенхема (минимального отклонения). Ответ: пусть функция putpixel(x,y,color) рисует точку в координатах (x,y) цветом color.

    void line(int x1, int y1,   int x2, int y2,
              int color){
        int dx, dy, i1, i2, i, kx, ky;
        register int d; /* "отклонение" */
        register int x, y;
        short /* boolean */ l;
        dy = y2 - y1; dx = x2 - x1;
        if( !dx && !dy ){
                putpixel(x1,y1, color); return;
        }
        kx = 1; /* шаг по x */
        ky = 1; /* шаг по y */
        /* Выбор тактовой оси */
        if( dx < 0 ){ dx = -dx; kx = -1; } /* Y */
        else if( dx == 0 )      kx = 0;    /* X */
        if( dy < 0 ){ dy = -dy; ky = -1; }
        if( dx < dy ){ l = 0; d = dx; dx = dy; dy = d; }
        else           l = 1;
        i1 = dy + dy; d = i1 - dx; i2 = d - dx;
        x = x1; y = y1;
        for( i=0; i < dx; i++ ){
             putpixel( x, y, color );
             if( l ) x += kx; /* шаг по такт. оси   */
             else    y += ky;
             if( d < 0 ) /* горизонтальный шаг      */
                 d += i1;
             else{       /* диагональный шаг        */
                 d += i2;
                 if( l ) y += ky; /* прирост высоты */
                 else    x += kx;
             }
        }
        putpixel(x, y, color);  /* последняя точка  */
    }

8.21.

Составьте программу, которая строит график функции sin(x) на отрезке от 0 до 2*пи. Учтите такие вещи: соседние точки графика следует соединять отрезком прямой, чтобы график выглядел непрерывным; не забывайте приводить double к int, т.к. координаты пикселов* - целые числа.

8.22.

Напишите функцию, которая заполняет в массиве байт count бит подряд, начиная с x-ого бита от левого края массива:
        байт 0      |          байт 1
    7 6 5 4 3 2 1 0 | 7 6  5  4  3  2  1  0 : биты в байте
    0 1 2 3 4 5 6 7 | 8 9 10 11 12 13 14 15 : x
        ==========================
            x=2, count=11

Такой алгоритм используется в растровой машинной графике для рисования горизонтальных прямых линий (тогда массив - это видеопамять компьютера, каждый бит соответствует пикселу на экране).

Ответ (причем мы заполняем биты не просто единицами, а "узором" pattern):

    void horizLine(char *addr,int x,int count,char pattern){
      static char masks[8] = {
           0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01 };
      /* индекс в этом массиве равен числу 0-битов слева */
      register i;
      char mask;
      short lbits, rbits; /* число битов слева и справа */
      short onebyte;      /* единственный байт ? */
      addr += x/8;        /* в байте 8 бит */
      mask = masks[ lbits = x & 7 ];   /* x % 8 */
      if( count >= (rbits = 8 - lbits)){
          count -= rbits; onebyte = 0;
      }else{
          mask &= ~masks[ lbits = (x+count) & 7 ];
          onebyte = 1;
      }
    /* Первый байт */
      *addr = (*addr & ~mask) | (pattern & mask);
      addr++;
      /* Для pattern==0xFF можно просто
       *     *addr++ |= mask;
       * поскольку (a &~m)|(0xFF & m) = (a &~m) | m =
       *   (a|m) & (~m|m) = (a|m) & 0xFF = a | m
       * Почему здесь нельзя написать *addr++ = (*addr...) ?
       * Потому, что ++ может быть сделан ДО вычисления
       * правой части присваивания!
       */
      if(onebyte) return;
    /* Средние байты */
      for(i = count/8; i > 0; --i)
          *addr++ = pattern;  /* mask==0xFF */
    /* Последний байт */
      if((lbits = count & 7) == 0) return;
      /* последний байт был полным */
      mask = ~masks[lbits];
      *addr = (*addr & ~mask) | (pattern & mask);
    }
Заметим, что для быстродействия подобные алгоритмы обычно пишутся на ассемблере.

8.23.

Напишите при помощи curses-а "электронные часы", отображающие текущее время большими цифрами (например, размером 8x8 обычных символов) каждые 5 секунд. Используйте alarm(), pause().

8.24.

Составьте программу, реализующую простой диалоговый интерфейс, основанный на меню. Меню хранятся в текстовых файлах вида:

            файл menu2_12
    ----------------------------------------------    ЗАГОЛОВОК_МЕНЮ
    +команда_выполняемая_при_входе_в_меню
    -команда_выполняемая_при_выходе_из_меню
    альтернатива_1
            команда1_1
            команда1_2
    альтернатива_2
            команда2_1
            команда2_2  #комментарий
            команда2_3
    альтернатива_3
           >menu2_2     #это переход в другое меню
    альтернатива_4
           >>menu3_7    #хранимое в файле menu3_7
    ...
            ...
    ----------------------------------------------

Программа должна обеспечивать: возврат к предыдущему меню по клавише Esc (для этого следует хранить "историю" вызовов меню друг из друга, например в виде "полного имени меню":

    .rootmenu.menu1_2.menu2_4.menu3_1

где menuI_J - имена файлов с меню), обеспечить выход из программы по клавишам 'q' и ESC, выдачу подсказки по F1, выдачу полного имени меню по F2. Вызов меню при помощи > означает замещение текущего меню новым, что соответствует замене последней компоненты в полном имени меню. Вызов >> означает вызов меню как функции, т.е. после выбора в новом меню и выполнения нужных действий автоматически должно быть выдано то меню, из которого произошел вызов (такой вызов соответствует удлинению полного имени, а возврат из вызова - отсечению последней компоненты). Этот вызов может быть показан на экране как появление нового "выскакивающего" окна поверх окна с предыдущим меню (окно возникает чуть сдвинутым - скажем, на y=1 и x=-2), а возврат - как исчезновение этого окна. Заголовок меню должен высвечиваться в верхней строке меню:

               |------------------       |--ЗАГОЛОВОК_МЕНЮ---- |
            |  альтернатива_1   | |
            |  альтернатива_2   | |
            | *альтернатива_3   | |
            |  альтернатива_4   |-       --------------------

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

Усложните функцию выбора в меню так, чтобы альтернативы можно было выбирать по первой букве при помощи нажатия кнопки с этой буквой (в любом регистре):

            Compile
            Edit
            Run program

8.25.

Напишите на curses-е функцию, реализующую выбор в меню - прямоугольной таблице:

            слово1   слово4   слово7
            слово2  *слово5   слово8
            слово3   слово6

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

8.26.

Используя библиотеку curses, напишите программу, реализующую клеточный автомат Конвея "Жизнь". Правила: есть прямоугольное поле (вообще говоря бесконечное, но принято в конечной модели замыкать края в кольцо), в котором живут "клетки" некоторого организма. Каждая имеет 8 соседних полей. Следующее поколение "клеток" образуется по таким правилам:

  • если "клетка" имеет 2 или 3 соседей - она выживает.
  • если "клетка" имеет меньше 2 или больше 3 соседей - она погибает.
  • в пустом поле, имеющем ровно 3х живых соседей, рождается новая "клетка".

Предусмотрите: редактирование поля, случайное заполнение поля, останов при смерти всех "клеток", останов при стабилизации колонии.

8.27.

При помощи curses-а напишите экранный редактор кодов доступа к файлу (в форме rwxrwxrwx). Расширьте программу, позволяя редактировать коды доступа у группы файлов, изображая имена файлов и коды доступа в виде таблицы:

НАЗВАНИЕ КОДЫ ДОСТУПА
файл1 rwxrw-r-
файл3 rwxrwxr-
файл2 rw-r-xr-x

Имена файлов задавайте как аргументы для main(). Указание: используйте для получения текущих кодов доступа системный вызов stat(), а для их изменения - системный вызов chmod().

* Пиксел (pixel, pel) - picture element, в машинной графике - точка растра на экране.

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

Назад | Содержание | Вперед