Организация циклов с помощью оператора do - while 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Организация циклов с помощью оператора do - while



В общем виде этот оператор можно записать следующим образом:

do
оператор;
while(выражение);

Выполняется "оператор", а затем вычисляется "выражение2". Если оно истинно, то снова выполняется "оператор" и.т.д. Если "выражение" становится ложным, циклический процесс заканчивается. Это так называемый цикл с постусловием: условие завершения цикла проверяется не в его начале. как это имеет место в операторах while и for, а в конце, уже после прохода по телу цика. Как следствие, тело цикла обязательно выполняется по крацней мере один раз. Этот тип цикла встречается нечасто, но иногда бывает полезен. Составим, например, функцию length(s), которая вычисляет длину строки s с учетом завершающегося нуля. Известно, что число символов в строке не меньше единицы, если учитывать этот нулеврй символ. Поэтому естественно предположить, что мы бедм проходить по телу цикла по крайней мере один раз. Значит, можно использовать цикл do - while (пример 4.8).

Пример 4.8

/*длина строки*/ length(s) char s[] { int i,l; i=l=0; do i++; while(s[l++]!='\0'); return(i); } #include stdio.h main() { printf("%d\n",length("")); printf("%d\n",length("мама")); }

Операторы break и continue

Часто при вознекновении некоторого события удобно иметь возможность досрочно завершить цикл. Используемый для этой цели оператор break (разрыв) вызывает немедленный выход из циклов, организуемых с помощью операторов for, while, do-while, а также прекращение оператора switch. Приведенная ниже программа обеспечивает поиск в заданном иассиве элемента, равного g (пример 4.9). В случае обнаружения такого элемента оператор break прекращает дальнейшее выполнение цикла. Так как параметр i сохраняет значение после выхода из цикла, то дальнейший анализ его значения (if(i==n)) позволяет судить об удачном (i<=n) илинеудачном (i==n) поиске. В случае вложенных циклов оператор break немедленно прекращает выполнение самого внутреннего из объемлющих его циклов.

Пример 4.9

/*линейный поиск*/ #include <stdio.h> int a[]={1,2,3,33,5,6,0,8}; int n=8; main() { int i,g=33; for(i=0;i<n;i++) if(a[i]==g) break; if(i==n) printf("%d ненайден\n",g); else printf("%d на%d месте \n"g,i); }

На примере 5.0 приведена программа, которая ведет подсчет числа различных элементов в массиве. Каждый очередной элемент a[i] сравнивается с последующими элементами массива. Если он не совпадает ни с одним из этих элементов, в счетчик k добавляется еденица. В противном случае внутренний цикл прерывается оператором break и начинается новая итерация внешнего цикла.

Пример 5.0

/*число разных элементов*/ #include <stdio.h> main() { static a[]={7,3,7,4,3,6}; int i,j,m,k=1;m=6; for(i=0;i<m-1;i++) { for(j=i+1;j<m;j++) if(a[i]==a[j]) break; if(j==m) k++; } printf("%d разныхэлем. \n", k); }

Оператор continue тоже предназначен для прерывания циклического процесса, организуемого операторами for, while, do-while. Но в отличае от оператора break, он не прекращает дальнейшее выполнение цикла, а только немедленно переходит к следующей интерации того цикла, в теле которого он оказался. Он как бы имитирует безусловный переход на конечный оператор цикла, но не за ее пределы самого цикла. Программа на примере 5.1 использует оператор continue для пропуска отрицательных элементов массива, суммируя только положительные.

Пример 5.1

#include <stdio.h> main() { static int a[]={1,2,-3,4,-5,6}; int i,n,s; n=6; s=0; for(i=0; i<n; i++) { if(a[i]<=0) continue; /*пропуск0*/ s+=a[i]; } printf("сумма= %d \n",s); }

Переключатель

Мы уже напоминали о том, что использовать для многозадачного ветвления в программе вложенные операторы if-then-else Если глубина вложенности этих операторов свыше трех, то конструкция теряет ясность. Более наглядным и понятным в данной ситуации выглядит оператор switch (переключатель), специально предназначенный для принятия одного из многих решений. Чаще всего этот оператор выглядит следующим образом:

switch(целое выражение) { case константа1: оператор1; case константа2: оператор2;......... case константаn: операторn; default: оператор; }

При выполнении этого оператора вычисляется выражение, стоящее в скобках после ключевого слова switch, которое должно быть целым. Оно, в частности, может быть и символьным значением (в языке Си символьные значения автоматически расширяются до целых значений). Эта целая величина используется в качестве критерия для выбора одного из возможных вариантов. Ее значение сравнивается с константой операторов case. Вместо целой или литерной константы в операторе case может стоять дае некоторое константное выражение. Значения таких констант (выражений) должны быть различными в разных операторах case. При несовпадении выполняется переход к следующему case и сравнивается его константа. В случае совпадения " константы_i" выполняется "оператор_i", а также все последующие операторы case и default. Если не было ни одного совпадения и имеется оператор default,то выполняется стоящий за ним оператор. Если же оператора default не было, выполнение программы продолжится с оператора, следующего за структурой switch. Таким образом, при каждом выполнении оператора просматриваются все метки case. Рассмотрим следующую программу (пример 5.2)

Пример 5.2

/*проверка switch*/ #include <stdio.h> main() { int k=2; switch(k) { case 0; printf("выбор 0\n"); case 1; printf("выбор 1\n"); case 2; printf("выбор 2\n"); case 3; printf("выбор 3\n"); default: printf("default\n"); } }

Как видите, происходит то, о чем мы говорили: выполняется альтернатива, соответствующая k=2 и все последующие операторы case, а также выриант default. Чтобы обеспечить выбор одного из многих вариантов (что и требуется чаще всего), используют обычно оператор braek, который вызывает немедленный выход из оператора switch (пример 5.3) Для этой цели можно применять и оператор return, а continue можно применять лишь в случае, когда сам оператор switch находится внутри цикла. Тогда continue вызывает немедленный переход к следующей интеракции, без рассмотрения оставшихся case.

Пример 5.3

/*проверка switch*/ #include <stdio.h> main() { int k=2; switch(k) { case 0; printf("выбор 0\n"); break; case 1; printf("выбор 1\n"); break; case 2; printf("выбор 2\n"); break; case 3; printf("выбор 3\n"); break; default: printf("default\n"); } }

Указатели

Указатель -это переменная, значением которой является адресс другой переменной. Так как указатель может ссылаться на переменные разных типов, с указателем в языке Си связывается тип того объекта, на который он ссылается. Для описания указателей используется операция косвенной адресации *. Например, указатель целого типа uk описывается так: int *uk. Унарная операция &, примененная к некоторой переменной, показывает, что нам нужен адресс этой переменной, а не ее текущее значение. Если переменная uk объявлена как указатель, то оператор присваивания uk=&x означает: " взять адресс переменной x и присвоить его значение переменной-указателю uk ".

Унарная операция *. примененная к указателю, обеспечивает доступ к содержимому ячейки памяти, на которую ссылается указатель. Например, *uk можно описать словами как " то, что содержится по адресу, на который указывает uk ". Указатели могут использоваться в выражениях. Если. например, переменная uk указывает на целое x, то *uk может во всех случаях использоваться вместо x; так, *uk+1 увеличивает x на единицу, а *uk=0 равносильно x=0. Два оператора присваивания uk=&x;y=*uk; выполняет то же самое, что и один оператор y=x. Польза от применения указателей в таких ситуациях, мягко выражаясь, невелика.

Наиболее полно их преимущества при обработке массивов и, в частности, символьных строк. Указатели и массивы тесно связаны друг с другом. Прежде чем рассмотреть эту связь подробно, заметим, что если uk - некоторый указатель, то uk++ увеличивает его значение и он теперь указывает на следющий, соседний адресуемый объект. Значение uk используется в выражении, а затем увеличивается. Аналогично определяются операции uk--, ++uk, --uk. В общем случае указатель uk можно скаладывать с целым числом i. Оператор uk+=i передвигает ссылку на i элементов относительно текущего значения. Эти конструкции подчиняются правилам адресной арифметики.

А теперь вернемся к массивам. Пусть имеется описание int a[5]; Оно определяет массив размером 5 элементов, т.е. пять последовательно расположенных ячеек памяти a[0], a[1], a[2], a[3], a[4]. Адресс i -го элемента массива равен сумме адреса начального елемента массива и смещения этого элемента на i единиц от начала массива. Это достигается индексированием: a[i]-i -й элемент массива. Но доступ к любому элементу массива может быть выполнен и с помощью указателей, причем, более эффективно. Если uk -указатель на целое, описанный как int *uk, то uk после выполнения операции uk=&a[0] содержит адресс a[0], а uk+i указывает на i -й элемент массива. Таким образом, uk+i является адрессом a[i]*(uk=1) - содержимым i- го элемента(операции * и & более приоритетны, чем арифметические операции). Так как имя массива в программе отождествляется с адресом его первого элемента, то выражение uk=&a[0] эквивалентно такому: uk=a. Поэтому значение a[i] можно записать как *(a+i). Применив к этим двум элементам операцию взятия адреса, получим, что &a[i] и a+i идеитичны.

Раньше, в связи с использованием функции scanf, мы говорили, что применение указателей в качестве аргументов функции дает способ обхода защиты значений вызывающей функции от действий вызванной функции. На примере 5.4 приведен текст программы с функцией obmen(x,y), которая меняет местами значения двух целых величин. Так как x,y -адреса переменных a и b, то *x и *y обеспечивают косвенный доступ значениям a и b. К сказанному добавим, что использование указателей позволяет нам обходить ограничения языка Си, согласно которым функциям может возращать только одно значение.

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

Пример 5.4

/*обмен a и b */ obmen(int *x,int *y) { int t; t=*x; *x=*y; *y=t; } #include <stdio.h> main() { int a,b; a=3;b=7; obmen(a,b); printf("a=%d b=%d",a,b); }

В определении функции формальные параметры char s[] и char *s совершенно идеитичны. Операция s++ ( пример 5.5 ) увеличение на единицу текущее значение указателя, первоначально указывающее на первый символ строки, а операция *s!='\0' сравнивает очередной символс признаком конца строки.

Пример 5.5

/*длина строки*/ length(s) char *s; { int i; for(i=0; *s!='\0';s++) i+++; return(i); }

Кроме ранее расмотренных операций адресной арифметики, к указателям можно применить операции сравнения == и !=. Даже операции отношения Б <,>= и т.п. работают правильно, если указатели ссылаются на элементы одного и того же массива. В последнем случае возможно даже вычитание ссылок: если u и s ссылаются на элементы одного массива, то u-s есть число элементов между u и s. Используем этот факт для составления еще одной версии функции length ( пример 5.6 ). Cначала u указывает на первый символ строки (char *u = s). Затем в цикле по очереди проверяется каждый символ, пока в конце концов не будет обнаружен "\0". Разность u-s дает как раз длину строки.

Пример 5.6

/*длина строки*/ length(s) char *s; { char *u=s; while(*u!='\0') u++; return(u-s); }

Для илюстрации основных аспектов применения указателей в СИ рассмотрим функцию копирования строки s1 в строку s2. Сначала приведем версию, основанную на работе с массивами(пример 5.7). Для сравнения рядом помещена версия с использованием указателей(пример 5.8).

Пример 5.7

/*копия строки*/ copy(s1,s2) char s1[],s2[]; { int i=0; while((s2[i]=s1[i])!='\0') i++; }

Пример 5.8

/*копия строки*/ copy(s1,s2) char *s1,*s2; { while((*s2=*s1)!='\0') { s2++;s1++; } }

Здесь операция копирования помещена непосредственно в условие, определяющее момент цикла: while((*s2=*s1)!='\0'). Продвижение вдоль массивов вплоть до тех пор, пока не встретится "\0", обеспечивают операторы s2++ и s1++. Их, однако, тоже можно поместить в проверку (пример 5.9).

Пример 5.9

/*копия строки*/ copy(s1,s2) char *s1,*s2; { while((*s2++=*s1++)!='\0'); }

Еще раз напомним, что унарные операции типа * и ++ выполняются справа налево. Значение *s++ c есть символ, на который указывает s до его увеличения. Так как значение "\0" есть нуль, а цикл while проверет, не нуль ли выражение в скобках, то это позволяет опустить явное сравнение с нулем(пример 6.0). Так постепенно функция копирования становится все более компактной и... все менее понятной. Но в системном программировании предпостение чаще отдают именно компактным и, следовательно, более эффективным по быстродействиб программам.

Пример 6.0

/*копия строки*/ copy(s1,s2) char *s1,*s2; { while(*s2++=*s1++); }

В языке Си, что некоторая литерная строка, выраженная как "строка", фактически рассматривается как указатель на нулевой элемент массива " строка". Допускается, например, такая интересная запись:

char *uk; uk="ИНФОРМАТИКА";

Последний оператор присваивает указателю адрес нулевого элемента строки, т.е. символа " И ". Возникает вопрос, где находится массив, содержащий символы " ИНФОРМАТИКА "? Мы его нигде не описывали. Ответ такой: эта строка - константа; она является частью функции, в которой встречается, точно также, как целая константа 4 или символьная константа "А" в операторах i=4; c="A";. Более детально пояснит сказанное программа на пример 6.1, которая печатает строку символов в обратном порядке.

Пример 6.1

#include <stdio.h> main() { char *uk1,*uk2; uk1=uk2="ИНФОРМАТИКА"; while(*uk2!='\0') putchar(*uk2++); putchar('\n'); while(--uk2 >= uk1) putchar(*uk2); putchar('\n'); }

В самом начале указателям uk1 и uk2 присваивается начальный адресс строки " ИНФОРМАТИКА ". Затем строка посимвольно печатается и одновременно указатель uk2 смещается вдоль строки. В конце вывода uk2 указывает на последний символ исходной строки. Во втором цикле while все тот же указатель uk2 начинает изменяться в обратном направлении, уменьнаясь до тех пор, пока он не будет указывать на нулевой элемент массива, обеспечивая выдачу строки в обратном порядке.

Структуры

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

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

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

Для образования структуры присваиваются имена каждому из включаемых элементов и структуре в целом. Затем посредством спечиального описания задают иерархию, порядок следования и типы элементов, включаемых в структуру. Так, для рассмотренного выще примера с анкетой служащего можно выбрать имена:

tab_nom - табельный номер; fio - фамилия, имя, отчество; pol - пол; summa - зарплата;

: Все эти понятия можно объединить в такую, например, структуру:

struct anketa { int tab_nom; char fio[30]; char data[10]; int pol; char adres[40]; float summa; };

Эта запись называется описанием структуры. Она начинается с ключевого слова struct и состоит из заключенного в фигурные скобки списка описаний. За словом struct может следовать необязательное имя, которое называется именем типа структуры(иногда его называют тэгом или ярлыком структуры). Этот ярлык именует структуру и в дальнейшем может использоваться для сокращения подробного описания. Переменные, упоминающиеся в записи, называются элементами. Следом за правой фигурной скобкой, заканчивающей список элементов, может следовать список переменных, так же, как и в случае базисных типов. Вот почему в приведенном выше описании структуры после закрывающей фигурной скобки стоит точка с запятой; она завершает пустой список. Описание struct {....} p1, p2, p3; синтаксически аналогично int p1, p2, p3; в том смысле, что каждый из операторов описывает p1, p2, p3 как переменные соответствующего типа и приводит к выделению для них памяти. Описание же структуры без последующего списка переменных не выделяет никакой памяти. Оно только определяет форму сируктуры и действует как шаблон. Если такое описание снабжено ярлыком (именем типа), то его можно позже использовать при определении фактических экземпляров структуры. Например, используя указание выше описане anketa, можно с помощью строки

struct anketa a0, a1,a2;

описать структурные переменные a0, a1, a2, каждая из которых строится по шаблону, введенному структурой anketa. Любая переменная a0, a1, a2 содержит в строго определенном порядке элементы tab_nom, fio, data, pol, adres, summa. Все переменные, как и все остальные переменные языкаЮ получают места в памяти.

Внешние и статические структуры можно инициировать, помещая следом за определением список начальных значений элементов:

struct anketa a0={ 1024, "Макагон В.М", "10.01.1943",0, "Одесса, Варневская, 23/99", 175.00};

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

имя_структуры.имя_элемента

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

a0.data="10.01.43"; a1.summa=0.0; if(a2.pol==1) man=man+1;

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

На практике структурные переменные обычно появляются в виде массива или списка. Нетрудно видеть, что наши три переменные a0, a1, a2 будет проще использовать, если их объединить в массив, сосотоящий из элементов типа struct anketa. Применив в программе описание

struct anketa a[3];

мы можем употреблять в ней, например, такие операторы:

a[0].fio ="Макагон В.М"; if(a[i].tab_nom>a[i+1].tab_nom) { p=a[i].tab_nom; a[i].tab_nom=a[i+1].tab_nom; a[i+1].tab_nom=p; }

Структуры и указатели

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

struct anketa *uk;

говорит, что uk -указатель на структуру типа anketa. Обозначение относится к конкретному элементу структуры и означает выборку этого элемента, например: uk-> tab_nom. Поскольку uk есть указатель на структуру anketa, то к элементу tab_nom можно обращаться и так:

(*uk).tab_nom,

если учесть, чтоуказатель установлен на начало массива структур. Имя массива, как обычно, эквивалентно адресу его начального элемента и при добавлении к указателю на структуру или вычитании из него целого числа размер структуры учитывается автоматически Так, оператор uk=a; устанавливает указатель на первый экземпляр массива структур, а запись ++a; обеспечивает автоматический переход к следующему экземпляру. В выражении (*uk).fio скобки обязательны, так как приоритет операции выделения элемента ". " выше чем у "*".

Препроцессор языка Си

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

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

Замена лексических единиц. Командная строка вида #define name text вызывает в оставшейся части программы замену всех вхождений идентификатора name на строку text. Например, определение #define p1 3.14159265 позволяет использовать в программе имя p1 вместо константы 3.14159265. Обратите внимание, что это определение не завершается точкой с запятой. Замещающий текст обычно представляет собою остаток строки. Длинное определение можно продолжить, если в конце продолжаемой строки поставить \. Внутри строк, заключенных в кавычки, подстановка не производится, так что, например, для определенного выше имени P1 в printf("P1"); подстановки не будет. Имена могут переопределяться и новые определения могут использовать ранее введенные определения.

Так как препроцессор не является частью компилятора языка Си, а представляет относительно простой макрогенератор, имеется возможность переопределять различные синтаксические единицы языка-лексемы (т.е. идентификаторы, ключевые слова, константы, цепочки литер, знаки операций и знаки пунктуаций). В приведенной (на примере 6.2) программе, предназначенной для выявления всех пар целых чисел из интервала [-n,n], являющихся решениями уравнения 2*y-x*x =4, используются привычные для таких языков как Алгол, Паскаль, операторные скобки begin-end вместо пары {}, ключевое слово then. Это стало возможным благодаря предварительно определенным лексическим заменам.

Пример 6.2

#include <stdio.h> #define then #define begin { #define end } main() begin int n,x,y,k=0; printf("введиn\n");scanf("%d",&n); for(x=-n;x<=n;x++) for(y=-n;y<=n;y++) if(2*y-x*x==4)then begin k=k+1; printf(x=%d, y=%d\n",x,y); end if(k==0) then printf("корнейнет\n "); end

Приведенная выше технология замены лесксем относится к макросредствам языка. Строка #define name text называется макроопределением, name называется макрошаблоном, а text - макрорасширением. Каждое появление имени name в теле программы называется макровызовом. Командная строка

#define name (p1,p2,..,pk) text

является макроопределением с аргументами. За именем name в круглых скобках (после name не должно быть пробела!) следует разделенные запятыми формальные параметры p1, p2.., pk, также являющиеся идентификаторами. Каждый раз, когда в тексте программы встречается имя макроопределения с фактичкскими аргументами, они подставляются вместо формальных, так что заменяющий текст будет зависеть от вида макровызова. Определим в качестве примера такую макроподстановку:

# define MAX(X,Y) ((X)>(Y)?(X):(Y))

Как и в определении функции, переменные X и Y в макроопределении являются формальными параметрами. После этого строка в программе:

m=MAX(a+b, a-b);

будет заменена на строку

m=((a+b)>(a-b)?(a+b):(a-b);

Текст макроопределения берут в скобки для обеспечения большей надежности программы. Пренебрежение скобками может привести к серьезным ошибкам, что иллюстрирует следующий пример 6.3. делит число 16 на квадрат числа 2 и дает правильный результат. Во второй программе (пример 6.4), где скобки в макроопределении опущены, результат ошибочный, так как макроподстановка породила текст:

printf("%d\n",16/2*2);

что конечно, не равносильно задуманному.

Пример 6.3

#include <stdio.h> #define SQR(n) (n*n) main() { printf("%d\n",16/SQR(2)); }

Пример 6.4

#include <stdio.h> #define SQR(n) n*n main() { printf("%d\n",16/SQR(2)); }

Макроопределения иногда используются вместо определений функций, обычно из сображений эффективности. Но следует помнить, что препроцесор может лишь тупо и бездумно заменять одну строку на другую, не разбираясь, зачем это нужно. В отличае от параметра функции, параметр макроопределения вычисляется при каждом вхождении в макроопределение. Поэтому иакровызов MAX(i++, j++) для приведенного выше макроопределения к увеличению i и j на 2.

Включение файлов

Командная строка для включения файлов выглядит следующим образом: #include "filename" и указывает препроцессору, что содержимое файла с именем filename надо вставить в том месте программы, где использованна командная строка. Эта возможность препроцессора позволяет следовать в Си идеям структурного программирования, согласно которым большая порграмма обычно расчленяется на логически завершенные части и каждая затем оформляется как самостоятельная функция. После отладки каждая из них оформляется в виде отдельного файла и при необходимости включается в отлаживаемую программу командой #include. Часто в таких файлах содержатся макроопределения и после включения их в исходный модуль утверждением #include они становятся доступными для всех функций. Например, приведенная ниже (пример 6.5) полезные макроопределения, используемые в программе (пример 6.6), можно "замаскировать", поместив их в файл " makro.h ", а в начале исходного файла с текстом программы поместить командную строку # include "makro.h".

Пример 6.5

#include <stdio.h> #define pr(int) printf("%d",int); #define SKIP putchar('\n'); #define PRINT1(X1) pr(X!);SKIP #define PRINT2(X1,X2) pr(X1);PRINT(X2);SKIP #define PRINT3(X1,X2,X3) pr(X1);PRINT(X2,X3);SKIP

Команда включения может иметь другую форму: #include <filename>. В частности, все наши пограммы включали командную строку #include <stdio.h>, благодаря которой программы пользователя могут обращаться к функциям, обеспечивающим стандартный ввод-вывод (getchar, putchar, printf, scanf и др.)

Пример 6.6

#include <stdio.h> main() { int a,b,c; a=5;b=7;c=a+b; PRINT1(a);PRINT2(a,b);PRINT3(a,b,c); }

Условная компиляция

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

#if константное_выражение

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

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

Последующий тест компилируется, если "идентификатор" уже был опредеоен для препроцессора в команде #define.

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

Последующий текст компилируется, если "идентификатор" в данный момент не определен. Конструкция

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

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

Приведенная на примере 6.7 программа иллюстрирует применение некоторых из рассмотренных выше команд, обеспечивающих условную компиляцию.

Пример 6.7



Поделиться:


Последнее изменение этой страницы: 2017-01-27; просмотров: 77; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.142.114.245 (0.072 с.)