История создания датчика движения: Первый прибор для обнаружения движения был изобретен немецким физиком Генрихом Герцем...
Механическое удерживание земляных масс: Механическое удерживание земляных масс на склоне обеспечивают контрфорсными сооружениями различных конструкций...
Топ:
Оценка эффективности инструментов коммуникационной политики: Внешние коммуникации - обмен информацией между организацией и её внешней средой...
Когда производится ограждение поезда, остановившегося на перегоне: Во всех случаях немедленно должно быть ограждено место препятствия для движения поездов на смежном пути двухпутного...
Теоретическая значимость работы: Описание теоретической значимости (ценности) результатов исследования должно присутствовать во введении...
Интересное:
Подходы к решению темы фильма: Существует три основных типа исторического фильма, имеющих между собой много общего...
Средства для ингаляционного наркоза: Наркоз наступает в результате вдыхания (ингаляции) средств, которое осуществляют или с помощью маски...
Инженерная защита территорий, зданий и сооружений от опасных геологических процессов: Изучение оползневых явлений, оценка устойчивости склонов и проектирование противооползневых сооружений — актуальнейшие задачи, стоящие перед отечественными...
Дисциплины:
2017-07-09 | 281 |
5.00
из
|
Заказать работу |
|
|
#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 */
…
int RNAGE_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)
|
|
Папиллярные узоры пальцев рук - маркер спортивных способностей: дерматоглифические признаки формируются на 3-5 месяце беременности, не изменяются в течение жизни...
Механическое удерживание земляных масс: Механическое удерживание земляных масс на склоне обеспечивают контрфорсными сооружениями различных конструкций...
Таксономические единицы (категории) растений: Каждая система классификации состоит из определённых соподчиненных друг другу...
Поперечные профили набережных и береговой полосы: На городских территориях берегоукрепление проектируют с учетом технических и экономических требований, но особое значение придают эстетическим...
© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!