ОЗВУЧИВАНИЕ ФИЛЬМА

Озвучивание фильма не связано непосредственно с обеспечением его интерактивности, однако на практике чаще всего звуковое сопровождение делают «управляемым» со стороны посетителя сайта. Это и понятно — ведь интересы и предпочтения посетителя должны быть для Web-дизайнера превыше всего. Не хочет он разделить с вами радость общения с музыкой (или какими-то другими звуками) — и не надо. Поэтому прежде, чем приступить к озвучиванию фильма, поместите в него кнопку с названием «Отключить звук» (или аналогичным). Процедура создания такой кнопки ничем не отличается от рассмотренной в подразделе «Назначение действий кнопке». Действие, которое следует связать с кнопкой, входит в раздел Actions и называется Stop All Sounds (Отключить все звуки).

Flash поддерживает несколько способов подключения звукового сопровождения. Вы можете использовать либо непрерывное звуковое сопровождение, не зависящее от временной диаграммы фильма, либо синхронизировать анимацию и звуковую дорожку. Разрешается назначать звуки кнопкам, кадрам и клипам, подобно тому, как этим элементам назначаются другие действия.

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

Flash не располагает средствами создания звуков, но позволяет импортировать звуковые файлы в различных форматах (в том числе WAV и МРЗ) и затем корректировать параметры звука в соответствии с требованиями фильма.

Чтобы добавить звук к фильму, необходимо выполнить следующие действия:

  1. Импортируйте в фильм один или несколько звуковых файлов; для этого в меню File выберите команду Import, а с помощью стандартного окна Windows – требуемый файл; в результате содержимое файла будет автоматически добавлено в библиотеку фильма в качестве специального символа.
  2. Добавьте во временную диаграмму фильма новый слой, который будет использоваться в качестве звукового (использование Отдельного звукового слоя облегчает тестирование и модификацию фильма); разрешается создавать несколько звуковых слоев, и каждый из них будет работать подобно отдельному звуковому каналу; это означает, что при воспроизведении фильма звуки на разных слоях, совпадающие во времени, воспроизводятся одновременно.
  3. Выберите в звуковом слое кадр, с которого вы хотите начать воспроизведение звука; если данный кадр не является ключевым, выполните для него команду Insert -> Keyframe.
  4. Щелкните в ячейке первого озвучиваемого кадра и в панели инспектора свойств выберите в раскрывающемся списке Sound (Звук) требуемый звуковой символ; на панели появятся (или станут доступны) элементы управления, используемые для установки параметров звука, а также его исходные параметры: ширина полосы частот, моно/стерео, разрядность, длительность, занимаемый объем памяти.
  5. Если это требуется, с помощью указанных элементов интерфейса скорректируйте параметры звука (подробнее о том, как это сделать, будет сказано ниже).
  6. В раскрывающемся списке  Sync (от Synchronization — синхронизация) выберите способ синхронизации звука:

    • Event – звук синхронизируется посредством привязки его к определенным событиям фильма; звук, управляемый событием, воспроизводится с момента перехода к соответствующему ключевому кадру, и продолжается независимо от временной диаграммы, даже если фильм будет остановлен (если, конечно, звук достаточно продолжителен);
    • Start — вариант аналогичен предыдущему, за исключением того, что при очередном наступлении заданного события начинается воспроизведение нового экземпляра звука, даже если воспроизведение предыдущего еще не закончено;
    • Stop — прекращается воспроизведение указанного звука;
    • Stream — потоковый звук; Flash обеспечивает «насильственную» синхронизацию анимации и потокового звука: например, если кадры анимации не успевают воспроизводиться на Web-странице с той же скоростью, что и потоковый звук, Flash-плеер пропускает некоторые кадры; воспроизведение потокового звука всегда прекращается при завершении анимации; кроме того, потоковый звук никогда не продолжается дольше, чем воспроизводятся связанные с ним кадры анимации.
  7. Установите длительность звучания; она определяется как число повторений звука; это число следует ввести в поле Loops (Циклы); например, если 3-секундный звук должен быть слышен в течение 30 секунд, следует ввести в поле Loops число 10.

Непосредственно после выбора в списке Sound одного из звуковых символов его амплитудная характеристика отображается на временной диаграмме.

Обратите внимание, что изображение звука на временной диаграмме масштабируется в соответствии с установленной частотой кадров фильма. Например, при частоте кадров, равной 12, звук длительностью в 2 секунды займет 6 кадров на диаграмме.

Вы можете связывать звуки с различными состояниями символа кнопки. Поскольку звуки сохраняются вместе с символом кнопки, Они будут работать для всех ее экземпляров.

Чтобы добавить звук кнопке, выполните следующие действия:

  1. Выберите символ кнопки в окне библиотеки и перетащите его на стол.
  2. На временной диаграмме кнопки добавьте звуковой слой.
  3. В этом слое создайте ключевой кадр, соответствующий тому состоянию кнопки, которое вы хотите озвучить.
  4. Щелкните правой кнопкой мыши в созданном ключевом кадре и с помощью элементов управления, имеющихся на панели инспектора свойств кадра, установите параметры звука, как было описано выше.

Для озвучивания других состояний кнопки необходимо повторить описанную выше процедуру.

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

Замечание

Чтобы проверить работу озвученной кнопки, не забудьте перейти в режим тестирования кнопки, выбрав в меню Control команду Enable Simple Buttons.

Публикация фильма

Основным форматом Flash-фильма, который обеспечивает его просмотр с помощью Flash-плеера (либо автономно, либо через окно Web-броузера), является формат SWF. Это единственный формат, который поддерживает все интерактивные возможности фильма. Тем не менее, во многих случаях при размещении Flash-фильма на сервере SWF-файл должен быть дополнен и другими файлами. Прежде всего это файл HTML-документа, посредством которого производится загрузка SWF-файла в броузер: сначала в броузер загружается HTML-файл, содержащий вызов Flash-плеера, а тот, в свою очередь, уже открывает SWF-файл. Кроме того, необходимо предусмотреть ситуацию, когда у посетителей вашего файла отсутствует Flash-плеер. В этом случае полноценный фильм можно заменить последовательностью изображений в графических форматах, поддерживаемых броузером посетителя (например, JPEG, PNG или анимированным GIF).

Чтобы создать все файлы, необходимые для размещения фильма на Web-сервере, достаточно единственной команды Publish (Опубликовать), входящей в меню File. Она обеспечивает конвертирование исходного FLA-файла не только в формат SWF, но и в альтернативные графические форматы. Кроме того, с помощью этой команды генерируется и HTML-документ, предназначенный для запуска фильма с заданными параметрами.

Если вы достаточно хорошо знакомы с HTML, то предварительно можете скорректировать шаблон, на основе которого выполняется генерация HTML-документа. Для редактирования шаблона требуется использовать внешний (по отношению к Flash) HTML-редактор.

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

Оптимизация и тестирование фильма

Для Flash-фильма, как и для любого другого Web-ресурса, является актуальной задача сокращения времени его загрузки броузером, а самый надежный способ ее решения — уменьшение размера SWF-файла.

В процессе экспорта фильма Flash выполняет некоторые операции, направленные на сокращение его размера. В частности, при наличии повторяющихся фигур Flash оставляет только одну копию; если в фильме присутствуют вложенные группы, Flash преобразует их в отдельные. Однако зачастую этого оказывается недостаточно для достижения требуемого результата. Поэтому перед публикацией фильма целесообразно вручную выполнить некоторые дополнительные преобразования элементов фильма.

Чтобы сократить размер фильма в целом:

  • все элементы, используемые в фильме более одного раза, пре-образуйте в символы соответствующего типа; например, повторяющиеся анимированные последовательности следует преобразовать в клип;
  • ограничьте изменяемую область в каждом ключевом кадре; сделайте так, чтобы действие происходило на минимальной площади стола;
  • избегайте анимирования растровых элементов; используйте растровые изображения только в качестве фона или статических элементов;
  • для представления звука применяйте формат МРЗ, где это возможно.

Чтобы минимизировать размер графических элементов и линий: D группируйте элементы, где это возможно;

  • помещайте элементы, которые изменяются в ходе анимации, в отдельные слои;
  • используйте возможности Flash по оптимизации числа кривых;
  • по возможности ограничивайте число специальных типов линий (штриховых, точечных и т. д.); имейте в виду, что линии, нарисованные с помощью инструмента Pencil, занимают в памяти меньше места, чем созданные с помощью инструмента Brush.

Чтобы минимизировать затраты на хранение текстовой информации:

  • ограничьте число используемых шрифтов и стилей; помните, что применение внедренных шрифтов увеличивает размер фильма;
  • при установке параметров внедренного шрифта включайте только те типы символов, которые действительно использованы в тексте.

Чтобы сократить объем памяти на хранение цветовой палитры:

  • используйте инспектор свойств для изменения цвета различных экземпляров одного символа;
  • используйте панель Color Mix, чтобы согласовать палитру фильма с палитрой броузера;
  • ограничьте применение градиентных заливок: такая заливка занимает приблизительно на 50 байт больше, чем однотонная заливка; прозрачные заливки также лучше использовать как можно реже, поскольку они могут замедлить воспроизведение фильма.

Чтобы выявить фрагменты фильма, которые замедляют его загрузку, вы можете протестировать его отдельные сцены или весь фильм, используя команды Test Scene или Test Movie. Если при загрузке SWF-файла требуемые данные не были получены к моменту перехода на следующий кадр, воспроизведение фильма приостанавливается.

В составе Flash имеется специальная утилита, которая позволяет получить в графическом виде профиль времени загрузки кадров фильма — Bandwidth Profiler (Профилировщик полосы частот). Чтобы получить с его помощью график загрузки фильма, необходимо выполнить следующие действия:

  1. В меню Control выберите команду Test Scene или Test Movie; при этом Flash конвертирует фильм в SWF-файл, откроет его в окне плеера и начнет воспроизведение.
  2. В окне плеера откройте меню Debug (Отладка) и выберите в нем предполагаемую скорость модемного соединения; возможны либо фиксированные значения (14.4, 28.8 и 56 Кб/с), либо устанавливаемые пользователем; чтобы установить собственные значения скорости соединения, следует выбрать пункт Customize (Настройка).
  3. В меню Control окна плеера выберите команду Stop, чтобы приостановить воспроизведение фильма.
  4. В меню View окна плеера выберите команду Bandwidth Profiler; при этом окно плеера окажется разделено по горизонтали на два подокна: в верхнем отображаются результаты профилирования, а в нижнем — содержание фильма (рис. 12.1); вы можете изменять размеры подокон, перемещая мышью полосу разделения.

Оценка параметров загрузки фильма возможна в трех режимах:

  • Streaming Graph (Непрерывный график);
  • Show streaming (Показать процесс загрузки);
  • Frame by Frame Graph (Покадровый график).
  • параметры фильма (Movie) — размер окна, частота смены кадров, размер SWF-файла, длительность воспроизведения, длительность загрузки до начала воспроизведения;
  • условия тестирования (Settings) — выбранная вами скорость загрузки страниц сайта через модемное соединение;
  • текущее состояние загрузки (State) — номер последнего загруженного кадра, его размер, относительный (в процентах) и абсолютный (в байтах) размер загруженной части фильма.

В правой части окна представлена гистограмма распределения объема фильма по кадрам; для повышения наглядности цвет кадров чередуется. Линией красного цвета обозначен критический размер кадра: кадр большего размера вызывает задержку воспроизведения фильма.

Состав отображаемой информации и вид графика можно изменить с помощью следующих двух команд из меню View.

  • Show streaming — при выборе данного режима на шкале кадров отображается в реальном времени диаграмма загрузки кадров (рис. 12.3);
  • Frame by Frame Graph — в данном режиме на графике отображаются только те кадры, которые превышают критический уровень; как правило, такими кадрами являются ключевые кадры; данный режим является альтернативным режиму Streaming Graph.

Кроме того, щелкнув мышью на конкретном кадре в графической части окна, вы можете получить информацию о нем в текстовой части окна

Если требуется протестировать ранее созданный SWF-файл, следует открыть его с помощью команды Open (Открыть), входящей в меню File.

2.1.1. Методы организации и хранения линейных списков

Линейный список – это конечная последовательность однотипных элементов (узлов), возможно, с повторениями. Количество элементов в последовательности называется длиной списка, причем длина в процессе работы программы может изменяться.

Линейный список F, состоящий из элементов D1,D2,…,Dn, записывают в виде последовательности значений заключенной в угловые скобки F=.

Например, F1=<2,3,1>,F2=<7,7,7,2,1,12>, F3=<>. Длина списков F1, F2, F3 равна соответственно 3,6,0.

При работе со списками на практике чаще всего приходится выполнять следующие операции:

- найти элемент с заданным свойством;

- определить первый элемент в линейном списке;

- вставить дополнительный элемент до или после указанного узла;

- исключить определенный элемент из списка;

- упорядочить узлы линейного списка в определенном порядке.

В реальных языках программирования нет какой-либо структуры данных для представления линейного списка так, чтобы все указанные операции над ним выполнялись в одинаковой степени эффективно. Поэтому при работе с линейными списками важным является представление используемых в программе линейных списков таким образом, чтобы была обеспечена максимальная эффективность и по времени выполнения программы, и по объему требуемой памяти.

Методы хранения линейных списков разделяются на методы последовательного и связанного хранения. Рассмотрим простейшие варианты этих методов для списка с целыми значениями F=<7,10>.

При последовательном хранении элементы линейного списка размещаются в массиве d фиксированных размеров, например, 100, и длина списка указывается в переменной l, т.е. в программе необходимо иметь объявления вида

              float d[100];   int l;

Размер массива 100 ограничивает максимальные размеры линейного списка. Список F в массиве d формируется так:

               d[0]=7; d[1]=10; l=2;

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

Описание структуры и указателя в этом случае может имееть вид:

       typedef struct snd   /* структура элемента хранения   */
       { float  val;        /* элемент списка                */
        struct snd *n ;     /* указатель на элемент хранения */
       } DL;
       DL *p;               /* указатель текущего элемента   */
       DL *dl;              /* указатель на начало списка    */

Для выделения памяти под элементы хранения необходимо пользоваться функцией malloc(sizeof(DL)) или calloc(l,sizeof(DL)). Формирование списка в связанном хранении может осуществляется операторами:

       p=malloc(sizeof(DL));
       p->val=10;   p->n=NULL;
       dl=malloc(sizeof(DL));
       dl->val=7;   dl->n=p;

В последнем элементе хранения (конец списка) указатель на соседний элемент имеет значение NULL.

2.1.2. Операции со списками при последовательном хранении

При выборе метода хранения линейного списка следует учитывать, какие операции будут выполняться и с какой частотой, время их выполнения и объем памяти, требуемый для хранения списка.

Пусть имеется линейный список с целыми значениями и для его хранения используется массив d (с числом элементов 100), а количество элементов в списке указывается переменной l. Реализация указанных ранее операций над списком представляется следующими фрагментами программ которые используют объявления:

          float d[100];
          int i,j,l;
     1) печать значения первого элемента (узла)
        if (i<0 || i>l) printf("\n нет элемента");
        else printf("d[%d]=%f ",i,d[i]);
     2) удаление элемента, следующего за i-тым  узлом
        if (i>=l) printf("\n нет следующего ");
        l--;
        for (j=i+1;j<="1" узла i-того соседей обоих печать
     3) d[j]="d[j+1];">=l) printf("\n нет соседа");
        else printf("\n %d  %d",d[i-1],d[i+1]);
     4) добавление нового элемента new за i-тым узлом
        if (i==l || i>l) printf("\n нельзя добавить");
        else
        {    for (j=l; j>i+1; j--) d[j+1]=d[j];
             d[i+1]=new; l++;
        }
     5) частичное упорядочение списка с элементами  К1,К2,...,Кl  в
     список K1',K2',...,Ks,K1,Kt",...,Kt", s+t+1=l так, чтобы K1'= K1.
     { int t=1;
       float aux;
       for (i=2; i<=l; i++) if (d[i]=2; j--) d[j]=d[j-1];
               t++;
               d[i]=aux;
            }
     }

1.7.4. Массивы указателей

В языке СИ элементы массивов могут иметь любой тип, и, в частности, могут быть указателями на любой тип. Рассмотрим несколько примеров с использованием указателей.

Следующие объявления переменных

     int a[]={10,11,12,13,14,};
     int *p[]={a, a+1, a+2, a+2, a+3, a+4};
     int **pp=p;

При выполнении операции pp-p получим нулевое значение, так как ссылки pp и p равны и указывают на начальный элемент массива указателей, связанного с указателем p ( на элемент p[0]).

Результатом выполнения вычитания pp-p будет 2, так как значение pp есть адрес третьего элемента массива p. Ссылка *pp-a тоже дает значение 2, так как обращение *pp есть адрес третьего элемента массива a, а обращение a есть адрес начального элемента массива a. При обращении с помощью ссылки **pp получим 12 – это значение третьего элемента массива a. Ссылка *pp++ даст значение четвертого элемента массива p т.е. адрес четвертого элемента массива a.

Если считать, что pp=p, то обращение *++pp это значение первого элемента массива a (т.е. значение 11), операция ++*pp изменит содержимое указателя p[0], таким образом, что он станет равным значению адреса элемента a[1].

Сложные обращения раскрываются изнутри. Например обращение *(++(*pp)) можно разбить на следующие действия: *pp дает значение начального элемента массива p[0], далее это значение инкременируется ++(*p) в результате чего указатель p[0] станет равен значению адреса элемента a[1], и последнее действие это выборка значения по полученному адресу, т.е. значение 11.

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

     int a[3][3]={  { 11,12,13 },
                    { 21,22,23 },
                    { 31,32,33 }   };
     int *pa[3]={ a,a[1],a[2] };
     int *p=a[0];

Согласно этой схеме доступ к элементу a[0][0] получить по указателям a, p, pa при помощи следующих ссылок: a[0][0], *a, **a[0], *p, **pa, *p[0].

Рассмотрим теперь пример с использованием строк символов. Объявления переменных

     char *c[]={ "abs", "dx", "yes", "no" };
     char **cp[]={ c+3, c+2 , c+1 , c };
     char ***cpp=cp;

1.7.5. Динамическое размещение массивов

При динамическом распределении памяти для массивов следует описать соответствующий указатель и присваивать ему значение при помощи функции calloc. Одномерный массив a[10] из элементов типа float можно создать следующим образом

      float *a;
      a=(float*)(calloc(10,sizeof(float));

Для создания двумерного массива вначале нужно распределить память для массива указателей на одномерные массивы, а затем распределять память для одномерных массивов. Пусть, например, требуется создать массив a[n][m], это можно сделать при помощи следующего фрагмента программы:

   #include
   main ()
       {  double **a;
          int n,m,i;
          scanf("%d %d",&n,&m);
          a=(double **)calloc(m,sizeof(double *));
          for (i=0; i<=m; i++)
a[i]="(double" *)calloc(n,sizeof(double));
. . . . . . . . . . . . }

Аналогичным образом можно распределить память и для трехмерного массива размером n,m,l. Следует только помнить, что ненужную для дальнейшего выполнения программы память следует освобождать при помощи функции free.

  
   #include 

   main ()
       {  long ***a;
          int n,m,l,i,j;
          scanf("%d %d %d",&n,&m,&l);
          /* --------  распределение памяти -------- */
          a=(long ***)calloc(m,sizeof(long **));
          for (i=0; i<=m; i++)
{ a[i]="(long" **)calloc(n,sizeof(long *));
for (j="0;" i<="l;" j++)
a[i][j]="(long" *)calloc(l,sizeof(long)); }
 . . . . . . . . . . . . /* освобождение памяти */
for (i="0;" i<="m;" i++) { for (j="0;" j<="l;" j++)
free (a[i][j]); free (a[i]); } free (a); }

Рассмотрим еще один интересный пример, в котором память для массивов распределяется в вызываемой функции, а используется в вызывающей. В таком случае в вызываемую функцию требуется передавать указатели, которым будут присвоены адреса выделяемой для массивов памяти.

     Пример:
   #include 

   main()
   {   int vvod(double ***, long **);
       double **a;     /*  указатель для массива  a[n][m]   */
       long *b;        /*  указатель для массива  b[n]      */
       vvod (&a,&b);
        ..   /* в функцию vvod передаются адреса указателей, */
        ..   /* а не их значения                             */
        ..
    }
    int vvod(double ***a, long **b)
    {   int n,m,i,j;
        scanf (" %d %d ",&n,&m);
        *a=(double **)calloc(n,sizeof(double *));
        *b=(long *)calloc(n,sizeof(long));
        for (i=0; i<=n; i++)
*a[i]="(double" *)calloc(m,sizeof(double)); ..... }

Отметим также то обстоятельство, что указатель на массив не обязательно должен показывать на начальный элемент некоторого массива. Он может быть сдвинут так, что начальный элемент будет иметь индекс отличный от нуля, причем он может быть как положительным так и отрицательным.

Пример:

   
    #include 

    int main()
    {  float *q, **b;
       int i, j, k, n, m;
       scanf("%d %d",&n,&m);
       q=(float *)calloc(m,sizeof(float));
    /* сейчас указатель q показывает на начало массива    */
       q[0]=22.3;
       q-=5;
    /* теперь начальный элемент массива имеет индекс 5,   */
    /* а конечный элемент индекс n-5                      */
       q[5]=1.5;
    /* сдвиг индекса не приводит к перераспределению      */
    /* массива в памяти и изменится начальный элемент     */
       q[6]=2.5;   /*  -  это второй элемент              */
       q[7]=3.5;   /*  -  это третий элемент              */
       q+=5;
    /* теперь начальный элемент вновь имеет индекс 0,     */
    /* а значения элементов q[0], q[1], q[2] равны        */
    /* соответственно 1.5, 2.5, 3.5                       */
       q+=2;
    /* теперь начальный элемент имеет индекс -2,          */
    /* следующий -1, затем 0 и т.д. по порядку            */
       q[-2]=8.2;
       q[-1]=4.5;
       q-=2;
    /* возвращаем начальную индексацию, три первых        */
    /* элемента массива q[0], q[1], q[2], имеют           */
    /* значения 8.2, 4.5, 3.5                             */
       q--;
    /* вновь изменим индексацию .                         */
    /* Для освобождения области памяти в которой размещен */
    /* массив q используется функция free(q), но поскольку */
    /* значение указателя q смещено, то выполнение     */
    /* функции free(q) приведет к непредсказуемым последствиям. */
    /* Для правильного выполнения этой функции    */
    /* указатель q должен быть возвращен в первоначальное */
    /* положение                                          */
       free(++q);
    /* Рассмотрим возможность изменения индексации и      */
    /* освобождения памяти для двумерного массива         */
       b=(float **)calloc(m,sizeof(float *));
       for (i=0; i < m; i++)
           b[i]=(float *)calloc(n,sizeof(float));
    /* После распределения памяти начальным элементом      */
    /* массива будет элемент b[0][0]                       */
    /* Выполним сдвиг индексов так, чтобы начальным        */
    /* элементом стал элемент b[1][1]                      */
       for (i=0; i < m ; i++) --b[i];
       b--;
    /* Теперь присвоим каждому элементу массива сумму его  */
    /* индексов                                            */
       for (i=1; i<=m; i++) for (j="1;" j<="n;" j++)
b[i][j]="(float)(i+j);" /* Обратите внимание на начальные значения
счетчиков */ /* циклов i и j, он начинаются с 1 а не с 0 */ /*
Возвратимся к прежней индексации */
for (i="1;" i<="m;" i++) ++b[i]; b++;
 /* Выполним освобождение памяти */
for (i="0;" i < m; i++) free(b[i]); free(b); ... ... return 0; }

В качестве последнего примера рассмотрим динамическое распределение памяти для массива указателей на функции, имеющие один входной параметр типа double и возвращающие значение типа double.

Пример:

  
   #include 

   #include 

    double cos(double);
    double sin(double);
    double tan(double);
   int main()
   { double (*(*masfun))(double);
     double x=0.5, y;
     int i;
     masfun=(double(*(*))(double))
              calloc(3,sizeof(double(*(*))(double)));
     masfun[0]=cos;
     masfun[1]=sin;
     masfun[2]=tan;
     for (i=0; i<3; i++);
{ y="masfun[i](x);" printf("\n x="%g" y="%g",x,y);" } return 0; }

1.8. Директивы Препроцессора

Директивы препроцессора представляют собой инструкции, записанные в тексте программы на СИ, и выполняемые до трансляции программы. Директивы препроцессора позволяют изменить текст программы, например, заменить некоторые лексемы в тексте, вставить текст из другого файла, запретить трансляцию части текста и т.п. Все директивы препроцессора начинаются со знака #. После директив препроцессора точка с запятой не ставятся.

1.8.1. Директива #include

Директива #include включает в текст программы содержимое указанного файла. Эта директива имеет две формы:

              #include "имя файла"
              #include <имя файла>

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

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

Директива #include широко используется для включения в программу так называемых заголовочных файлов, содержащих прототипы библиотечных функций, и поэтому большинство программ на СИ начинаются с этой директивы.

2.1.3. Операции со списками при связном хранении

При простом связанном хранении каждый элемент списка представляет собой структуру nd, состоящую из двух элементов: val – предназначен для хранения элемента списка, n – для указателя на структуру, содержащую следующий элемент списка. На первый элемент списка указывает указатель dl. Для всех операций над списком используется описание:

        typedef struct nd
          {  float val;
             struct nd * n;  }  ND;
        int i,j;
        ND * dl, * r, * p;

Для реализации операций могут использоваться следующие фрагменты программ:

1) печать значения i-го элемента

        r=dl;j=1;
        while(r!=NULL && j++n ;
        if (r==NULL) printf("\n нет узла %d ",i);
        else printf("\n элемент %d равен %f ",i,r->val);

2) печать обоих соседей узла(элемента), определяемого указателем p
if((r=p->n)==NULL) printf("\n нет соседа справа");
        else  printf("\n  сосед  справа  %f",  r->val);
        if(dl==p) printf("\n нет соседа слева" );
        else { r=dl;
               while( r->n!=p ) r=r->n;
               printf("\n левый сосед %f", r->val);
             }

3) удаление элемента, следующего за узлом, на который указывает р

if ((r=p->n)==NULL) printf("\n  нет  следующего");
        p->n=r->n; free(r->n);

4) вставка нового узла со значением new за элементом,

r=malloc(1,sizeof(ND));
        r->n=p->n;   r->val=new;   p->n=r;

5) частичное упорядочение списка в последовательность значений ,
s+t+1=l, так что K1'=K1; после упорядочения указатель v указывает
на элемент K1'

определенным указателем р

ND *v;
        float k1;
        k1=dl->val;
        r=dl;
        while( r->n!=NULL )
        { v=r->n;
           if (v->valn=v->n;
               v->n=dl;
               dl=v;
             }
            else r=v;
        }

Количество действий, требуемых для выполнения указанных операций
над списком в связанном хранении, оценивается соотношениями:
для операций 1 и 2 - Q=l; для операций 3 и 4 - Q=1;
для операции 5 - Q=l.