Скалярное произведение векторов.

Скалярное произведение векторов. - student2.ru

#include <stdio.h>

#define MAX_INDEX 5

/* определение функции scalar */

/* скалярное произведение n-мерных векторов */

/* n - размерность пространства векторов */

/* a[], b[] -массивы координат векторов */

float Scalar_Product(int n, float a[], float b[])

{

int i=0; /* параметр цикла */

double z=0; /* формируемая сумма */

for (i=0, z=0.0; i< n; i++)

z+=a[i]*b[i];

return z; /* возвращаемый результат */

}

void main()

{

int n=0, i;

float x[MAX_INDEX], y[MAX_INDEX];

printf("\n n=");

scanf("%d", &n);

if(n < 1 || n > MAX_INDEX)

{

printf("\n error ");

return; /* аварийное завершение */

}

printf("input %d x: ", n);

for (i=0; i<n; i++)

scanf("%f", &x[i]);

printf("input %d y: ", n);

for (i=0; i<n; i++)

scanf("%f", &y[i]);

printf("\n result= %7.3f", Scalar_Product(n, x, y));

}

Результаты выполнения программы:

n=2

input 2 x: 1 3.1

input 2 y: 1 2.1

result = 7.510

6.6. Переключатели

Основным средством для организации мультиветвления служит оператор-переключатель, формат которого имеет вид:

switch

{

case константа1: операторы_1;

case константа2; операторы_2;

default операторы;

}

switch – идентифицирует собственно оператор-переключатель. Служебное слово case с последующей константой является в некотором смысле меткой. Константы могут быть целыми или символьными и все должны быть различными (чтобы метки были различными).

default – обозначает отдельную метку. При выполнении оператора вычисляется выражение, записанное после switch, и его значение последовательно сравнивается с константами, которые помещены вслед за case. При первом же совпадении выполняются операторы, помеченные данной меткой. Если выполненные операторы не предусматривают какого-либо перехода (т.е. среди них нет ни goto, ни return ни exit), то далее выполняются операторы всех следующих вариантов, пока не появится оператор перехода или не закончится переключатель.

Операторы вслед за default выполняются, если значение выражения в скобках после switch не совпало ни с одной константой после case. Метка default может в переключателе отсутствовать. В этом случае при несовпадении значения выражения с константами переключатель не выполняет никаких действий. Операторы, помеченные меткой default, не обязательно находятся в конце (после других вариантов переключателя).

Пример. Вывод на экран название цифры.

#include <stdio.h>

void main()

{

int i, j = 1;

while(j)

{

printf("\n цифра: ");

if(scanf("%d", &i) == 0)

{

printf(" это не цифра! \n");

return;

}

printf("\t\t");

switch(i)

{

case 1:

printf("%d - один \n ", i);

break;

case 2:

printf("%d - два \n ", 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;

default:

printf("%d - нуль \n ", i);

break;

} /* конец переключателя */

} /* конец цикла */

}

Контрольные вопросы.

1. Назначение препроцессорных директив.

2. Структура программы на языке Си.

3. Синтаксис условного оператора.

4. Применение оператора перехода.

5. Синтаксис оператора цикла с предусловием.

6. Синтаксис оператора цикла с постусловием.

7. Синтаксис оператора параметрического цикла.

8. Использование оператора break.

9. Применение оператора continue.

10. Назначение прототипа функции.

11. Как осуществить обращение к функции.

12. Применение переключателя в языке Си.

Глава 7. Препроцессорные средства

Препроцессор обрабатывает почти любые тексты, а не только тексты программ на языке Си.

Стадии и команды препроцессорной обработки

Стадии препроцессорной обработки.Препроцессорная обработка включает несколько стадий, выполняемых последовательно. Конкретная реализация может объединять несколько стадий, но результат должен быть таким, как если бы они выполнялись в следующем порядке:

§ все системно-зависимые обозначения (например, системно-зависимый индикатор конца строки) перекодируются в стандартные коды;

§ каждая пара из символов «\» и «конец строки» вместе с пробелами между ними убираются, и тем самым следующая строка исходного текста присоединяется к строке, в которой находилась эта пара символов;

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

§ выполняются директивы препроцессора и производятся макроподстановки;

§ эскейп-последовательности в символьных константах и символьных строках, например: “\n” или “xF2”, заменяются на их эквиваленты (на соответствующие числовые коды);

§ смежные символьные строки (строковые константы) конкатенируются, т.е. соединяются в одну строку;

§ каждая препроцессорная лексема преобразуется в текст на языке Си.

К предпроцессорным лексемам препроцессора относятся символьные константы, имена включаемых файлов, идентификаторы, знаки операций, препроцессорные числа, знаки препинания, строковые константы (строки) и любые символы, отличные от пробела.

На стадии обработки директив препроцессора возможны следующие действия:

§ замена идентификаторов заранее подготовленными последовательностями символов;

§ включение в программу текстов из указанных файлов;

§ исключение из программы отдельных частей ее текста (условная компиляция);

§ макроподстановка, т.е. замена обозначения параметризованным текстом, формируемым препроцессором с учетом конкретных параметров (аргументов).

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

Обобщенный формат директивы препроцессора:

#имя_директивы лексемы_препроцессора

Перед символом “#” и после него в директиве разрешаются пробелы. Пробелы также разрешены перед лексемами_препроцессора, между ними и после них. Окончанием препроцессорной директивы служит конец текстовой строки (при наличии символа «\», обозначающего перенос строки, окончанием препроцессорной директивы будет признак конца следующей строки текста).

Определены следующие препроцессорные директивы:

#define - определение макроса или препроцессорного идентификатора;

#include - включение текста из файла;

#undef - отмена определения макроса или идентификатора (препроцессорного);

#if - проверка условия-выражения;

#ifdef - проверка определенности идентификатора;

#ifndef - проверка неопределенности идентификатора;

#else - начало альтернативной ветви для #if

#endif - окончание условной директивы #if;

#elif - составная директива #else/#if;

#line - смена номера следующей ниже строки;

#error - формирование текста сообщения об ошибке трансляции;

#pragma - действия, предусмотренные реализацией;

# - пустая директива.

Кроме препроцессорных директив имеются три препроцессорные операции.

defined - проверка истинности операнда;

## - конкатенация препроцессорных лексем;

# - преобразование операнда в строку символов.

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

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

Директива #undef отменяет действие директивы #define, которая определила до этого имя препроцессорного идентификатора.

Директива #if и ее модификации #ifdef, #ifndef совместно с директивами #else, #endif, #elif позволяет организовать условную обработку текста программы. При использовании этих средств компилируется не весь текст, а только те его части, которые выделены с помощью перечисленных директив.

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

Директива #error позволяет задать текст диагностического сообщения, которое выводится при возникновении ошибок.

Директива #pragma вызывает действия, зависящие от реализации, т.е. запланированные авторами компилятора.

7.1. Замены в тексте

Директива #define.

#define идентификатор строка_замещения

Директива может размещаться в любом месте обрабатываемого текста, а ее действие в обычном случае распространяется от точки размещения до конца текста. Директива, во0первых, определяет идентификатор как препроцессорный. В результате работы препроцессора вхождения идентификатора, определенного командой #define, в тексте программы заменяются строкой замещения, окончанием которой обычно служит признак конца той «физической» строки, где размещена команда #define. символы пробелов, помещенные в начале и в конце строки замещения, в подстановке не используются. Например:

Исходный текст

#define begin {

#define end }

void nain ()

begin

операторы

end

Результат препроцессорной обработки

void main()

{

оператор

}

В данном случае программист решил использовать в качестве операторных скобок идентификаторы begin, end. До компиляции препроцессор заменяет все вхождения этих идентификаторов стандартными скобками { и }. Соответствующие указания программист дал препроцессору с помощью директив #define.

Цепочка подстановки.Если в строке замещения команды #define в качестве отдельной лексемы встречается препроцессорный идентификатор, ранее определенный другой директивой #define, то выполняется цепочка последовательных подстановок. В качестве примера рассмотрим, как можно определить диапазон (RANGE) возможных значений любой целой переменной типа int в следующей программе:

#include <limits.h>

#define RANGE ((INT_MAX) – (INT_MIN) + 1)

….

/* RANGE – диапазон значений для int */

intRNAGE_T = RANGE/8;

Препроцессор последовательно, строку за строкой, просматривает текст и, обнаружив директиву #include <limits.h>, вставляет текст из файла limits.h. Там определены константы INT_MAX (предельное максимальное значение целых величин), INT_MIN. Тем самым программа принимает, например, такой вид:

#define INT_MAX 32767

#define INT_MIN –32768

#define RANGE ((INT_MAX - (INT_MIN) + 1)

/* RANGE – диапазон значений для int */

int RANGE_T = RANGE / 8;

Директива #include исчезла из программы, но ее заменил соответствующий текст.

Обнаружив в тексте (добытом из файла limits.h) директивы #define … препроцессор выполняет соответствующие подстановки, и программа принимает вид:

#define RANGE ((32767) – (-32768) + 1)

/* RANGE – диапазон значений для int */

int RANGE_T = RANGE / 8;

Подстановки изменили строку замещения препроцессорного идентификатора RANGE в директиве #define, размещенной ниже, чем текст, включенный из файла limits.h. «Продвигаясь» по тексту программы, препроцессор встречает препроцессорный идентификатор RANGE и выполняет подстановку. Текст программы приобретает вид:

/* RANGE – диапазон значений для int */

int RANGE_T = ((32767) – (-32768) + 1) / 8;

Теперь все директивы #define удалены из текста. Получен текст, пригодный для компиляции, т.е. создана «единица трансляции».

Если строка_замещения оказывается слишком длинной, ее можно продолжить в следующей строке текста. Для этого в конце продолжаемой строки помещается символ “\”. В ходе одной из стадий препроцессорной обработки этот символ вместе с последующим символом конца строки будет удален из текста программы.

Если в программе нужно часто печатать или выводить на экран значения какой-либо переменной и, кроме того, снабжать эту печать одни и тем же пояснительным текстом, то удобно ввести сокращенное обозначение оператора печати, например:

#define PK printf(“\n Номер элемента=%d. “, N);

После этой директивы использование в программе оператора PK; будет эквивалентно (по результату) оператору из строки замещения.

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

#define M 18

/* идентификатор М определен как 18 */

#define М ‘C’

/* М определен как символьная константа ‘С’ */

#define M “C”

/* М определен как символьная строка */

/* с двумя элементам ‘C’ и ‘\0’ */

При таких сменах значений препроцессорного идентификатора компилятор выдает предупреждение.

Чтобы этого не было, следует отменять замены с помощью команды

#undef идентификатор

Например:

#define M 16

#undef M

#define M ‘C’

#undef M

#define M “C”

7.2. Включение текстов из файлов

Для включения текста из файла используется команда #define, имеющая три формы записи:

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

#include “имя_файла”

#include имя_макроса

где имя_макроса – это введенный директивой #define препроцессорный идентификатор либо макрос, при замене которого после конечного числа подстановок будет получена последовательность символов < имя_файла> либо “имя_файла”.

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

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

Кроме такого в некоторой степени стандартного файла, каким является stdio.h, в заголовок программы могут быть включены любые другие файлы (стандартные или подготовленные специально).

Имена, определенные в стандартных заголовочных файлах, являются зарезервированными именами:

assert.h - диагностика программ

ctype.h - преобразование и проверка символов

errno.h - проверка ошибок

float.h - работа с вещественными данными

limits.h - предельные значения целочисленных данных

locate.h - поддержка национальной среды

math.h - математические вычисления

setjump.h - возможности нелокальных переходов

signal.h - обработка исключительных ситуаций

stdarg.h - поддержка переменного числа параметров

stddef.h - дополнительные определения

stdio.h - средства ввода-вывода

stdlib.h - функция общего назначения (работа с памятью)

string.h - работа со строками символов

time.h - определение дат и времени

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

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

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

7.3. Макроподстановки средствами препроцессора

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

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

#define REAL long double

вводит название (имя) REAL для типа long double. Далее в тексте программы можно определять конкретные объекты, используя REAL в качестве обозначения их типа (long double)

REAL x, array [6];

Пример макроопределения:

#define max(a, b) (a < b ? b : a)

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

max (X, Y)

заменяется выражением:

(X < Y ? Y : X)

Наши рекомендации