книги / Программирование на языке Си
..pdf122' |
Программирование на языке Си |
файле stdlib.h, который включается в начало текста программы препроцессорной директивой.
Пример результатов выполнения программы:
Сторона а=2.О Сторона Ь=3.О Сторона с=4.О
Площадь треугольника: 2.904737
Скалярное произведение векторов. Выше была определена функция Scalar_Product() для вычисления скалярного произве дения векторов, в которой параметрами являлись массивы. Следующая программа использует эту функцию:
/* Скалярное произведение векторов */ #include <stdio.h>
#define MAX_INDEX 5 void main( )
{
/* Прототип функции: */
float Scalar_Product(int, float[ ], float[ ]); int n,i;
float x[MAX_INDEX] ,y[MAX_INDEX] ; printf("\n Размерность векторов n= "); scanf("%d",&n);
if(n < 1 || n >MAX_INDEX)
{
printf("\n Ошибка в данных!"); return; /* Аварийное завершение */
)
printf("Введите %d координ. х: ",п); for (i=0; i<n; i++)
scanf("%f",&x[i]); printf("Введите %d координ. у: ",n); for (i=0; i<n; i++)
scanf("%f",&y[i]); printf("\n Результат: %7.3f", Scalar_Product(n,x ,у ));
)
/* Определение функции scalar: */
float Scalar_Product(int n, float a[],float b[]) /* Скалярное произведение n-мерных векторов */
Глава 2. Введение в программирование на языке Си |
123 |
|||
/* |
п - размерность пространства векторов */ |
|||
/* |
а[ ],Ь[ |
] - массивы координат векторов */ |
||
{ int i ; |
|
/* Параметр цикла */ |
||
|
double z; |
/* |
Формируемая сумма |
*/ |
|
for (i=0,z=0.0; |
i < n; i++) |
|
|
|
z += a[i]*b[i]; |
|
||
) |
return z; |
/* Возвращаемый результат |
*/ |
|
|
|
|
|
В начале программы с помощью ^define введена препроцессорная константа MAX_INDEX. Далее определены массивы, у которых пределы изменения индексов заданы на препроцессорном уровне. Именно эти пределы проверяются после ввода размерности векторов (п). В теле функции m ain() приведен прототип функции Scalar_Product(). Обратите внимание, что в прототипе отсутствуют имена формальных параметров. Тот факт, что два параметра являются одномерными массивами, отображен спецификацией float[].
Результаты выполнения программы:
Размерность векторов п=2 Введите 2 координ. х : 1 3.1 Введите 2 координ. у : 1 2.1 Результат: 7.510
Другая попытка выполнить программу:
Размерность векторов п=0 Ошибка в данных!
Диаметр множества точек. Как еще один пример использо вания функций с массивами в качестве параметров рассмотрим программу определения диаметра множества точек в многомер ном евклидовом пространстве. Напомним, что диаметром назы вается максимальное расстояние между точками множества, а расстояние в евклидовом пространстве между точками дс={ г, } ;
У ={у ( } i=l,...,n, определяется как
124 |
Программирование на языке Си |
|
Введем |
ограничения на размерность |
пространства: |
N_MAX<=10 и количество точек К_МАХ<=100. Текст про граммы может быть таким:
#±nclude <stdio.h>
#include <math.h> /* для функции sqrt( ) */ /* Функция для вычисления
расстояния между двумя точками */
float distance(float х[ ], float у[ ], int n)
{
int i ;
float r,s=0.0; for(i=0;i<n;i++)
{
r=y[i]-x[i]; s+=r*r;
}
s=sqrt(s); return s;
}
#define K_MAX 100 #define N_MAX 10 void main( )
{
float dist, dist_max,d;
int i , j , ijnax, m_max, n , k , m ; float a[K_MAX][N_MAX];
/* a[][] - Массив фиксированных размеров */ while(1)
{
printf("\n Количество точек k="); scanf("%d", &k);
printf("Размерность пространства n="); scanf("%d", &n);
if(k>0 && k<=K_MAX && n>0 && n<=N_MAX) break; printf("ОШИБКА В ДАННЫХ!");
}
for(i=0;i<k;i++)
{/* Никл ввода координат точек */ printf("Введите %d координ. "
"точки %d:\n",n,i+l); for(j=0;j<n;j++)
/* Цикл ввода координат одной точки */
Глава 2. Введение в программирование на языке Си |
125 |
scanf("%f",&a[i][j]);
}
dist_max=0.0; i_max=0;
m_max=0; for(i=0;i<k-l;i++)
{/* Цикл сравнения точек */ for(m=i+l;m<k;m++)
{
dist=distance(a[i],a[m],n); if(dist>dist_max)
{
dist_max=dist; i_max=i;
m_max=m;
}
>
} /* Конец цикла no i */ printf("Результат:\nflnaMeTp=%f",dist_max); printf("\n Номера точек : %d,%d",
i_max+l,m_max+l);
}
Результаты выполнения программы:
Количество |
точек к=4 |
п=3 |
|||
Размерность |
пространства |
||||
Введите |
3 |
координ. точки 1: |
|||
1 |
1 |
1 |
|
|
|
Введите |
3 |
координ .- точки 2: |
|||
-1 |
-1 |
|
|
-1 |
|
Введите |
3 |
координ. точки 3: |
|||
2 |
2 |
3 |
|
2 |
4: |
Введите |
координ. точки |
||||
- 2 |
- 2 |
|
|
- 2 |
|
Результат: Диаметр = 6.928203 Номера точек: 3, 4
В программе особый интерес представляет обращение к функции distance( ), где в качестве фактических параметров ис пользуются индексированные элементы a[i], а[ш]. Каждый из них по определению есть одномерный массив из п элементов,
126 |
Программирование на языке Си |
что и учитывается в теле функции. Для задания размеров масси ва а[ ][] и предельных значений переменных к и п используются препроцессорные константы К_МАХ и N_MAX. Их нельзя оп ределить как переменные, т.е. ошибочной будет последователь ность:
int К_МАХ=100; N_MAX=10; float а[К MAX][N_MAX];
При определении массивов их размеры можно задавать толь ко с помощью константных выражений.
2.6. П ереклю чатели
Основным средством для организации мультиветвления слу жит оператор-переключатель, формат которого имеет вид:
switch{выражение)
{case константа!: операторы_1; case константа2: операторы_2;
default: операторы,-
}
В этом операторе используются три служебных слова: switch, case, default. Первое из них идентифицирует собственно оператор-переключатель. Служебное слово case с последующей константой является в некотором смысле меткой. Константы могут быть целыми или символьными и все должны быть раз личными (чтобы метки были различимы). Служебное слово default также обозначает отдельную метку. При выполнении оператора (рис. 2.6, а) вычисляется выражение, записанное по сле switch, и его значение последовательно сравнивается с кон стантами, которые помещены вслед за case. При первом же совпадении выполняются операторы, помеченные данной мет кой. Если выполненные операторы не предусматривают какоголибо перехода (т.е. среди них нет ни goto, ни return, ни exit( ), ни break), то далее выполняются операторы всех следующих
Глава 2. Введение в программирование на языке Си |
127 |
вариантов, пока не появится оператор перехода или не закон чится переключатель.
Операторы вслед за default выполняются, если значение вы ражения в скобках после switch не совпало ни с одной констан той после case. Метка default может в переключателе отсутствовать. В этом случае при несовпадений значения выра жения с константами переключатель не выполняет никаких дей ствий. Операторы, помеченные меткой default, не обязательно находятся в конце (после других вариантов переключателя). Уточним, что default и "case константа" не являются метками в обычном смысле. К ним, например, нельзя перейти с помощью оператора goto.
На рис. 2.6 приведены схемы переключателя (рис. 2.6, а) и оператора альтернативного выбора или селектора (рис. 2.6 , б), отсутствующего в языке Си.
Рис. 2.6. Переключатель (а) и альтернативный выбор (б): а - если выражение равно МК, то выполняются операторы
Sк , Sк+1- . S„,S;
б - если выражение равно LK, то выполняются только операторы S
128 |
Программирование на языке Си |
На рис. 2.7 изображена схема альтернативного выбора, реа лизованная при помощи переключателя и дополнительных опе раторов, введенных в Sb S2, ..., Sn .
Рис. 2.7. Альтернативный выбор с использованием переключателя. В число операторов каждой группы Sfc добавлен оператор
выхода из переключателя
Для иллюстрации работы переключателя рассмотрим про грамму, которая читает любую десятичную цифру и выводит на экран ее название:
Глава 2. Введение в программирование на языке Си |
129 |
#include <stdio.h> void main( )
{
int i; while(1)
{
printf("\n Введите десятичную цифру: "); scanf("%d",&i);
printf("\t\t"); switch( i )
{
case 1: printf("%d -один \n",i); break;
case 2: printf("%d - два \ц” ,i); break;
case 3: printf("%d - три \n",i); break;
case 4: printf("%d - четыре \n",i); break; .
case 5: printf("%d - пять \n",i); break;
case 6: printf("%d - шесть \n",i); break;
case 7: printf("%d - семь \n",i); break;
case 8: printf("%d - восемь \n",i); break;
case 9: printf("%d - девять \n",i); break;
case 0: printf("%d - нуль \n",i); break;
default: printf("%d - это не цифра! \n",i); return;
}/* Конец переключателя */
}/* Конец цикла */
}
Пример результатов выполнения программы:
Введите десятичную цифру: 3
3 - три Введите десятичную цифру: 8
8 - восемь
g - S ’24
130 |
Программирование на языке Си |
Введите десятичную цифру: |
-7 |
-7 - это |
не цифра! |
Программа прекращает выполнение, как только будет введен символ, отличный от цифры. Завершение программы обеспечи вает оператор return; который в данном случае передает управ ление операционной системе, так как выполняет выход из функции m ain().
Переключатель вместе с набором операторов break реализу ет в этой программе альтернативный выбор (см. рис. 2.7). Если удалить все операторы break, то работа переключателя в этой программе будет соответствовать схеме рис. 2.6, а.
Несколько "меток" case с разными значениями констант мо гут помечать один оператор внутри переключателя, что позво ляет еще больше разнообразить схемы построения операторов switch.
Глава 3
ПРЕПРОЦЕССОРНЫЕ СРЕДСТВА
В предыдущих главах мы познакомились с некоторыми базо выми понятиями и основными средствами (может быть, не са мыми эффективными) программирования языка Си. Начиная с данной главы, начнем подробное изучение тех особенностей и возможностей, которыми Си отличается от других языков про граммирования и которые принесли ему заслуженную популяр ность и любовь профессиональных программистов.
Несколько нетрадиционно для пособий по языку Си начнем дальнейшее изложение материала с возможностей препроцессо ра. Это позволит в следующих главах продемонстрировать эф фективность препроцессорных средств и их применимость при решении разнородных задач. Откладывать, как часто принято, изучение препроцессора на конец курса по языку Си, по нашему мнению, не совсем удачно. Даже в начальных (вступительных) главах 1 и 2 пришлось затронуть некоторые важные вопросы препроцессорной обработки. Введены константы, определяемые директивой ^define, проиллюстрированы некоторые правила включения в программу текстов заголовочных файлов для связи со стандартной библиотекой компилятора. Этих сведений впол не достаточно, чтобы программировать на языке Си, вводить с помощью ^define собственные обозначения констант и не ис пытывать затруднений в использовании стандартных библиотек.
К сожалению, именно на таком уровне использования пре процессора остаются многие программисты, не обратившие внимания на другие возможности препроцессорной обработки текста программы. А возможности препроцессора весьма инте ресные, особенно в областях макрообработки и условной ком пиляции. Введя в этой главе препроцессорные средства, мы сможем в следующих главах показать способы и возможности их применения при решении задач разных классов.
Прежде чем перейти к изложению материала, отметим, что препроцессор обрабатывает почти любые тексты, а не только тексты программ на языке Си. Обработка программ - это основ-
9