Лекция ветвление. 3 Операции сравнения
Скачать 0.53 Mb.
|
3.3. Операции сравнения == - равно или эквивалентно; != - не равно; < - меньше; <= - меньше либо равно; > - больше; >= - больше либо равно. Пары символов соответствующих операций разделять нельзя. Общий вид операций отношений: <выражение1> <знак_операции> <выражение2> Общие правила: - операндами могут быть любые базовые (скалярные) типы; значения операндов перед сравнением преобразуются к одному типу; - результат операции отношения - целое значение 1, если отношение истинно, или 0 в противном случае. Следовательно, операция отношения может использоваться в любых арифметических выражениях. 3.4. Логические операции Перечень логических операций в порядке убывания относительного приоритета и их обозначения: ! - отрицание (логическое НЕТ); && - коньюнкция (логическое И); || - дизьюнкция (логическое ИЛИ). Общий вид операции отрицания: !<выражение> Общий вид операций коньюнкции и дизьюнкции <выражение1> <знак_операции> <выражение2> Например: y>0 && x==7 истина, если 1-е и 2-е выражения истинны; e>0 || x==7 истина, если хотя бы одно выражение истинно. Ненулевое значение операнда трактуется как "истина", а нулевое - "ложь". Например: !0 1 !5 0 x=10; y=10; !((x==y)>0) 0 Пример правильной записи двойного неравенства: 0 <выражение1> <операция><выражение2>, - если выражение1 операции коньюнкция ложно, то результат операции - ноль и выражение2 может не вычисляться; - если выражение1 операции дизьюнкция истинно, то результат операции - единица и выражение2 может не вычисляться. Таким образом, появляется возможность записью логического выражения задать условную последовательность вычисления выражений в направлении слева направо: scanf("%d",&i) && test1(i) && test2(i) нулевой результат одной из функций может привести к игнорированию вызова остальных; search1(x) || search2(x) || search3(x) только ненулевой результат одной из функций может привести к игнорированию вызова остальных. Действительно ли "ненужные" функции не будут вызываться - зависит от настроек компилятора. 6. Операторы языка С. Основной частью любой программы являются операторы, то есть инструкции (действия), выполняемые машиной во время работы программы. В конце каждого оператора ставится точка с запятой. Простые операторы: - пустой оператор «;» ; - оператор присваивания - выполнение операций присваивания; - оператор вызова функции - выполнение операции вызова функции. Примеры простых операторов: ; b=3; a=b+7; printf("%lf\n", a); Если в программе не указано иное, то операторы выполняются по очереди, один за другим, сверху вниз по тексту программы. Но существуют операторы, меняющие последовательность выполнения других операторов. К ним относятся условные операторы, операторы цикла и перехода. 7. Составление разветвляющихся алгоритмов 7.1. Условные операторы Условный оператор if используется для разветвления процесса выполнения кода программы на два направления. В языке Си имеется две формы условного оператора: простая и полная. Синтаксис простой формы: if (выражение) оператор; выражение – логическое или арифметическое выражение, вычисляемое перед проверкой, и, если выражение истинно (не равно нулю), то выполняется оператор, иначе он игнорируется; оператор – любой оператор языка Си. Если в случае истинности выражения необходимо выполнить несколько операторов (более одного), их необходимо заключить в фигурные скобки. (Группа операторов, заключенная в фигурные скобки, называется составным оператором или блоком). Примеры записи: if (x > 0) x = 0; if (i != 1) j++, s = 1; – используем операцию «запятая»; if (i != 1) { j++; s = 1; – последовательность операций (блок); } if (getch() != 27) k = 0; – если нажата любая клавиша, кроме “Esc”. if (!x) exit (1); или так : if (x == 0) exit(1); if ( i>0 && i if (выражение) оператор 1 ; else оператор 2 ; Если выражение не равно нулю (истина), то выполняется оператор 1, иначе – оператор 2. Операторы 1 и 2 могут быть простыми или составными (блоками). Наличие символа «;» перед словом else в языке Си обязательно. Примеры записи: if (x > 0) j = k+10; else m = i+10; if ( x > 0 && k !=0 ) { j = x/k; x += 10; } else m = k*i + 10; Операторы 1 и 2 могут быть любыми операторами, в том числе и условными. Тогда, если есть вложенная последовательность операторов if – else, то слово else связывается с ближайшим к ней предыдущим if, не содержащим ветвь else. Например: if (n > 0) if(a > b) z = a; else z = b; Здесь ветвь else связана со вторым if (a > b). Если же необходимо связать слово else с внешним if, то используются операторные скобки: if (n > 0) { if (a > b) z = a; } else z = b; В следующей цепочке операторов if – else – if выражения просматриваются последовательно: if (выражение 1) оператор 1; else if (выражение 2) оператор 2; else if (выражение 3) оператор 3; else оператор4 ; Если какое-то выражение оказывается истинным, то выполняется относящийся к нему оператор и этим вся цепочка заканчивается. Каждый оператор может быть либо отдельным оператором, либо группой операторов в фигурных скобках. Оператор 4 будет выполняться только тогда, когда ни одно из проверяемых условий не выполняется. Иногда при этом не нужно предпринимать никаких явных действий, тогда последний else может быть опущен, или его можно использовать для контроля, чтобы зафиксировать "невозможное" условие (своеобразная экономия на проверке условий). Пример: if (x < 0) printf("\n X отрицательное \n"); else if(x==0) printf ("\n X равно нулю \n"); else prinf("\n X положительное \n"); Замечание. Наиболее распространенной ошибкой при создании условных операторов является использование в выражении операции присваивания «=» вместо операции сравнения на равенство операндов «==» (два знака равно). Например, в следующем операторе синтаксической ошибки нет: if (x = 5) a++; но значение а будет увеличено на единицу независимо от значения переменной х, т.к. результатом операции присваивания х = 5 в круглых скобках является значение 50 – истина. Задача 1. Найти наибольшее из двух чисел. #include using namespace std; int main() { double a, b, max; cin >> a >> b; if (a>b) max = a; else max = b; cout << "max=" << max; } Задача 2. Найти наибольшее из трех чисел. #include using namespace std; int main() { double a, b, c, max; cin >> a >> b >> c; if (a>b) max = a; else max = b; if (c > max) max = c; cout << "max=" << max; } Задача 3. Определить является ли введенное число четным. #include using namespace std; int main() { int a; cin >> a; if (a % 2 == 0) cout << "chetnoe"; else cout << " ne chetnoe"; } 2-ой способ: #include using namespace std; int main() { int a; cin >> a; if (a % 2) cout << "ne chetnoe"; else cout << " chetnoe"; } 7.2. Оператор выбора альтернатив (переключатель) Оператор switch (переключатель) предназначен для разветвления процесса вычислений на несколько направлений. Общий вид оператора: switch ( выражение ) { case константа1: список операторов 1 case константа2: список операторов 2 ... case константаN: список операторов N default: список операторов N+1 – необязательная ветвь; } Выполнение оператора начинается с вычисления выражения, значение которого должно быть целого или символьного типов. Это значение сравнивается со значениями констант, и используется для выбора ветви, которую нужно выполнить. В данной конструкции константы фактически выполняют роль меток. Если значение выражения совпало с одной из перечисленных констант, то управление передается в соответствующую ветвь. Все константы должны иметь разные значения, но быть одного и того же типа. Несколько меток могут следовать подряд, и тогда переход в указанную ветвь будет происходить при совпадении хотя бы одной из них. Порядок следования ветвей не регламентируется. В случае несовпадения значения выражения ни с одной из констант выбора происходит переход на метку default, либо, при ее отсутствии, к оператору, следующему за оператором switch. Управляющий оператор break (разрыв) выполняет выход из оператора switch. Если в некоторой ветви выход из переключателя явно не указан, то после ее выполнения начнут последовательно выполняться последующие ветви. Поэтому, если по совпадению с каждой константой должна быть выполнена одна и только одна ветвь, схема оператора switch следующая: switch (выражение) { case константа1: операторы 1; break; case константа2: операторы 2; break; ... case константаN: операторы N; break; default: операторы (N+1); } Структурная схема рассмотренной конструкции (с использованием оператора break) приведена на рисунке. Пример оператора switch с использованием оператора break: #include #include < stdio.h > using namespace std; int main() { int i = 2; switch (i) { case 1: puts("Sluchay 1. "); break; case 2: puts("Sluchay 2. "); break; case 3: puts("Sluchay 3. "); break; default: puts("Случай default. "); } } Для того чтобы выйти из оператора switch в любом месте использовали оператор break, поэтому результатом данной программы будет: Случай 2. П ример оператора switch без использования оператора break (схема общего вида такой конструкции приведена на рисунке): void main() #include #include using namespace std; int main() { int i = 2; switch (i) { case 1: puts("Случай 1. "); case 2: puts("Случай 2. "); case 3: puts("Случай 3. "); default: puts("Случай default. "); } } Так как оператор разрыва отсутствует, результат в данном случае: Случай 2. Случай 3. Случай default. Пример реализации простейшего калькулятора на четыре действия с контролем правильности ввода символа нужной операции. Ввод данных осуществляется следующим образом: операнд 1, символ нужной операции, операнд 2. Вывод – а, символ операции, b, = , вычисленное значение. #include #include using namespace std; int main() { double a, b, c; char s; cin >> a >> s >> b; switch (s) { case '+': c = a + b; cout << c; break; case '–': c = a - b; cout << c; break; case '*': c = a*b; cout << c; break; case '/': c = a/b; cout << c; break; default: cout << "ne pravilno"; } } 7.3. Условная операция «? :» Если одно и то же выражение (или переменная) вычисляется по-разному в зависимости от некоторого условия, вместо оператора if можно использовать более короткую запись - условную операцию. Эта операция – тернарная, т.е. в ней участвуют три операнда. Формат написания условной операции следующий: Выражение1?выражение2 :выражение3; если выражение 1 (условие) отлично от нуля (истинно), то результатом операции является значение выражения 2, в противном случае – значение выражения 3. Каждый раз вычисляется только одно из выражений 2 или 3. На рисунке приведена схема вычисления результата, которая аналогична схеме полного оператора if (см. рисунок): Рассмотрим участок программы для нахождения максимального значения z из двух чисел a и b, используя оператор if и условную операцию. 1. Запишем оператор if : if (a > b) z = a; else z = b; 2. Используя условную операцию: z = a > b ? a : b; Условную операцию можно использовать так же, как и любое другое выражение. Если выражения 2 и 3 имеют разные типы, то тип результата определяется по правилам преобразования. Например, если f имеет тип double, а n – int, то результатом операции: (n > 0) ? f : n; по правилам преобразования типов будет double, независимо от того, положительно n или нет. Задача 2. Найти наибольшее из трех чисел. #include using namespace std; int main() { double a, b, c, max; cin >> a >> b >> c; max = (a > b) ? a : b; max = (c > max) ? c : max; cout << "max=" << max; } int scanf(const char *format, arg-list)Прототип: stdio.h Описание: Функция scanf() является процедурой ввода общего назначения, считывающей данные из потока stdin. Она может считывать данные всех базовых типов и автоматически конвертировать их в нужный внутренний формат. Если бы printf() выполняла ввод, а не вывод, ее можно было бы назвать аналогом scanf(). Управляющая строка, на которую указывает format, состоит из символов трех типов: Спецификаторы формата Специальные символы Прочие символы (не специальные) Спецификаторы формата следуют за символом процент и сообщают scanf(), данные какого типа будут считаны следующими. Коды спецификаторов приведены в таблице.
Например, %s считывает строку, a %d считывает переменную целого типа. Строка формата считывается слева направо, при этом устанавливается соответствие между кодами формата и аргументами из списка аргументов. Специальные символы в управляющей строке заставляют scanf() пропускать один или больше специальных символов во входном потоке. Специальные символы — это пробел, табуляция или новая строка. Один специальный символ в управляющей строке заставляет scanf() считывать, не запоминая, любое количество (включая нуль) идущих подряд специальных символов из входного потока, пока не встретится символ, не являющийся специальным символом. Наличие обычного символа заставляет scanf() считать и отбросить соответствующий символ. Например, "%d,%d" заставляет scanf() считать целое число, считать и отбросить запятую и затем считать еще одно целое число. Если указанный символ не обнаружен во входном потоке, scanf() останавливается. Все переменные, используемые для приема значений с помощью функции scanf(), должны отыскиваться по их адресам. Это значит, что все аргументы функции должны быть указателями на переменные. Таким образом, С создает возможность передачи по ссылке, и это позволяет функции изменять содержимое аргумента. Например, чтобы считать целое число и присвоить его значение переменной count, необходимо воспользоваться следующим обращением к scanf(): scanf("%d", &count); Строки считываются в массивы символов, и имя массива, без всякого указателя, является адресом первого элемента массива. Поэтому, чтобы считать строку в массив символов address, можно использовать команду scanf("%s", address); В этом случае имя address уже является указателем и не нуждается в префиксе &. Элементы вводимых данных должны разделяться пробелами, знаками табуляции или новой строки. Знаки пунктуации, такие как запятая, точка с запятой и т.п., не считаются разделителями. Это значит, что для оператора scanf("%d%d", &r, &с); последовательность 10 20 будет воспринята, а последовательность 10,20 — нет. Спецификаторы формата scanf() расположены в том же порядке, что и переменные в списке аргументов, которым присваиваются значения принимаемых переменных. Знак *, помещенный после % и перед спецификатором формата, считывает данные указанного типа, но подавляет их присваивание. Таким образом, код scanf ("%d%*c%d", &х, &у); при вводе последовательности 10/20 присваивает значение 10 переменной х, отбрасывает символ / и присваивает значение 20 переменной у. Командами форматирования может задаваться модификатор максимальной ширины поля. Он представляет собой целое число, которое помещается между знаком % и спецификатором формата. Он ограничивает количество считываемых символов для любого поля. Например, если необходимо считать не больше, чем 20 символов в массив address, следует написать scanf ("%20s", address); Если входной поток содержал больше 20 символов, то при последующем вызове функция ввода начнет ввод с того места, где был остановлен ввод при текущем обращении. Ввод поля может быть прерван и до достижения максимальной длины поля, если встретится пробел. В этом случае scanf() переходит к следующему полю. Хотя пробелы, символы табуляции и новых строк используются как разделители полей, они считываются как любой другой символ при вводе одиночного символа. Например, при входном потоке х у функция scanf("%с%с%с", &а, &b, &с); поместит символ х в переменную а, пробел — в переменную b и y — в переменную c. Надо быть внимательным: любые другие символы в управляющей строке — включая пробелы, символы табуляции и новых строк — используются для указания и отбрасывания символов из входного потока. Например, при входном потоке 10t20 функция scanf ("%st%s", &х, &у); поместит 10 в х, а 20 в у. Символ t будет отброшен, поскольку в управляющей строке имеется t. Еще одна возможность функции scanf() называется множеством сканирования. С помощью множества сканирования определяются символы, которые будут считываться функцией scanf() и присваиваться элементам соответствующего массива символов. Чтобы задать множество сканирования, надо символы, ввод которых допустим, поместить в квадратные скобки. Перед первой квадратной скобкой ставится знак процента. Например, следующий перечень множества сканирования задает считывание функцией scanf() только символов А, В и С: %[ABC] Соответствующий перечню множества сканирования аргумент должен быть указателем на массив символов. При использовании множества сканирования функция scanf() считывает символы и помещает их в указанный массив до тех пор, пока не встретится символ, не входящий в множество сканирования (то есть считываются только символы, входящие в множество сканирования). Массив, возвращенный scanf(), будет содержать строку с нулевым символом в конце. Перечень считываемых символов можно задать и в инверсной форме. Для этого в качестве первого символа надо поместить ^. Тогда scanf() будет принимать любой символ, не входящий в множество сканирования. С помощью кавычек можно задать диапазон воспринимаемых символов. Например, следующее выражение дает указание scanf() принимать буквы от «А» до «Z»: %[A-Z] Множество сканирования различает прописные и строчные буквы. Если необходимо, чтобы scanf() принимала те и другие, необходимо перечислить их в множестве сканирования отдельно. Функция scanf() возвращает число, равное количеству полей, значения которых были действительно присвоены переменным. В это количество не входят поля, которые были считаны, но их значения не были ничему присвоены вследствие использования модификатора * для подавления присваивания. Если до присвоения значения первого поля произошла ошибка, возвращается EOF. При использовании Borland С++ в 16-разрядной среде можно изменить модель памяти, используемую по умолчанию для компилирования программы, путем явного указания размера каждого указателя, используемого при вызове scanf(). Ближний указатель задается модификатором N, а дальний — модификатором F. (Нельзя использовать модификатор N, если программа скомпилирована для модели памяти huge.) Пример: Действия функции scanf() в следующих примерах поясняются комментариями: char str[80]; int i; /* чтение строки и целого */ scanf("%s%d", str, &i); /* чтение до 79 символов в str */ scanf ("%79s", str); /* пропуск целого между двумя строками */ scanf (" %s%*d%s", str, &i, str); |