Скалярное произведение векторов.Выше была определена функция Scalar_Product() для вычисления скалярного произведения векторов, в которой параметрами являлись массивы. Следующая программа использует эту функцию:
В начале программы с помощью #defineвведена препроцессорная константа MAX_INDEX. Далее определены массивы, у которых пределы изменения индексов заданы на препроцессорном уровне. Именно эти пределы проверяются после ввода размерности векторов (n). В теле функции main( ) приведен прототип функции Scalar_Product(). Обратите внимание, что в прототипе отсутствуют имена формальных параметров. Тот факт, что два параметра являются одномерными массивами, отображен спецификацией float[].
Результаты выполнения программы:
Другая попытка выполнить программу:
Диаметр множества точек.Как еще один пример использования функций с массивами в качестве параметров рассмотрим программу определения диаметра множества точек в многомерном евклидовом пространстве. Напомним, что диаметром называется максимальное расстояние между точками множества, а расстояние в евклидовом пространстве между точками х={ xt } ; y={yi} i=l,...,n, определяется как
Введем ограничения на размерность пространства: N_MAX<=10 и количество точек K_МАХ<=100. Текст программы может быть таким:
В программе особый интерес представляет обращение к функции distance( ), где в качестве фактических параметров используются индексированные элементы a[i], a[m]. Каждый из них по определению есть одномерный массив из n элементов, что и учитывается в теле функции. Для задания размеров массива а[ ][] и предельных значений переменных k и n используются препроцессорные константы K_МАХ и N_MAX. Их нельзя определить как переменные, т.е. ошибочной будет последовательность:
При определении массивов их размеры можно задавать только с помощью константных выражений.
В предыдущих главах мы познакомились с некоторыми базовыми понятиями и основными средствами (может быть, не самыми эффективными) программирования языка Си. Начиная с данной главы, начнем подробное изучение тех особенностей и возможностей, которыми Си отличается от других языков программирования и которые принесли ему заслуженную популярность и любовь профессиональных программистов.
Несколько нетрадиционно для пособий по языку Си начнем дальнейшее изложение материала о возможностях препроцессора. Это позволит в следующих главах продемонстрировать эффективность препроцессорных средств и их применимость при решении разнородных задач. Откладывать, как часто принято, изучение препроцессора на конец курса по языку Си, по нашему мнению, не совсем удачно. Даже в начальных (вступительных) главах 1 и 2 пришлось затронуть некоторые важные вопросы препроцессорной обработки. Введены константы, определяемые директивой #define,проиллюстрированы некоторые правила включения в программу текстов заголовочных файлов для связи со стандартной библиотекой компилятора. Этих сведений вполне достаточно, чтобы программировать на языке Си, вводить с помощью #defineсобственные обозначения констант и не испытывать затруднений в использовании стандартных библиотек.
К сожалению, именно на таком уровне использования препроцессора остаются многие программисты, не обратившие внимания на другие возможности препроцессорной обработки текста программы. А возможности препроцессора весьма интересные, особенно в областях макрообработки и условной компиляции. Введя в этой главе препроцессорные средства, мы сможем в следующих главах показать способы и возможности их применения при решении задач разных классов.
Прежде чем перейти к изложению материала, отметим, что препроцессор обрабатывает почти любые тексты, а не только тексты программ на языке Си. Обработка программ - это основная задача препроцессора, однако он может преобразовывать произвольные тексты, и этой возможностью программисту не следует пренебрегать в своей работе.
Итак, на входе препроцессора - текст с препроцессорными директивами, на выходе препроцессора - текст без препроцессорных директив (см. рис. 1.1).