Лабораторная работа оператор присваивания. Оператор
![]()
|
2. Операция явного преобразования типов Существует возможность явно указывать тип данных, к которому необходимо привести значение некоторого типа. Этот способ называется явным преобразованием типов и основывается на применении операции, которая называется операцией приведения типов. Определение (синтаксис операции приведения типа). Синтаксис операции явного приведения типов таков: (<Спецификация_типа>)<Выражение>, т.е. перед выражением <Выражение> в круглых скобках записывается имя требуемого типа. Именем операции приведения типа называется слово (<Спецификация_типа>) Пример (операции приведения типов). (int)x+(int)y Замечание. Вообще говоря, смешивать типы опасно: вот почему в некоторых языках программирования это запрещено, но бывают ситуации, когда это оказывается полезным. Философия языка C заключается в том, чтобы не устанавливать барьеров на пути, но при этом возложить на программиста всю ответственность за злоупотребление предоставленной свободой. Работа с демонстрационными примерами См. Пример 7. Операторы языка C 1. Оператор увеличения. Оператор уменьшения Сложению тебя обучали? - спросила Белая Королева. - Сколько будет один плюс один, плюс один, плюс один, плюс один, плюс один, плюс один, плюс один, плюс один, плюс один? Не знаю, - ответила Алиса. - Я сбилась со счёта. Л.Кэррол. Алиса в стране чудес В программировании часто встречаются ситуации, когда необходимо увеличить или уменьшить значение некоторой переменной на 1. Для этого обычно выполняются операторы присваивания вида: x=x+1; или x=x-1; Однако вспомним, что в языке C для выполнения этих действий существуют специальные арифметические операции, которые называются увеличение (++) и уменьшение (--). Превращая эти операции в соответствующие операторы, которые называются операторами увеличения и уменьшения, получим эквивалентные по операционной семантике записи на языке C: i=i+1 ; и i++; , а также j=j-1; и j-- ; Слова "++" или "--" записываются как после имени переменной, так и перед ним. Примеры. 1. Прокомментируем следующие операторы: x++; /* Значение x увеличивается на единицу */ y--; /* Значение y уменьшается на единицу */ ++a; /* Значение a увеличивается на единицу */ --b; /* Значение b уменьшается на единицу */ 2. Рассмотрим два программных фрагмента: (а) i=5; x=++i; (б) i=5; x=i++; Переменная x из примера (а) получит значение 6, а в примере (б) - значение 5, хотя в обоих случаях i становится равным 6. Таким образом, в контексте, где используется само значение переменной, а не только эффект её увеличения, использование операций присваивания ++i и i++ приводит к разным результатам. 3. Рассмотрим следующий программный фрагмент: int i,j,x; i=j=2; x=(i++)+(--j); Разберём подробнее выполнение последнего оператора присваивания. Сначала вычисляется значение выражения в первых скобках. Значение i увеличивается (новое значение i равно 3), но операция записана в постфиксной форме, поэтому в выражении используется "старое" значение i, т.е. 2. При вычислении значения выражения во-вторых скобках j уменьшается. Форма операции - префиксная, следовательно, в выражении участвует "новое" значение j, равное 1. Затем выполняется операция сложения (2+1) и оператор присваивания (x=3;). Работа с демонстрационными примерами См. Пример 9. 2. Оператор условного перехода Каждое "математическое предложение" есть изображённый в знаках modus ponens. Л.Витгенштейн, 1915 Определение. Синтаксис оператора условного перехода таков: if (<Выражение>) <Оператор_1>; else <Оператор_2>; Часть "else <Оператор_2>" (else-часть) является необязательной: можно использовать оператор if со следующим синтаксисом: if (<Выражение>) <Оператор_1>; В качестве <Оператор_1> может находиться любой оператор, в частности, - вновь оператор if/else. При этом может возникнуть неоднозначность, если во вложенной последовательности операторов if/else else-часть опускается. Подобные конструкции понимаются следующим образом: else всегда соответствует ближайшему предыдущему if, не содержащему else. Например, в операторе условного перехода if (n>0) if (a>b) z=a; else z=b; else-часть относится к внутреннему if. Если же требуется отнести else к внешнему if, то необходимо использовать фигурные скобки следующим образом: if (n>0) { if (a>b) z=a; } else z=b; Определение (операционная семантика оператора if). Вначале вычисляется значение выражения <Выражение>. Если его значение отлично от нуля, то выполняется <Оператор_1>. Если его значение равно нулю, и если есть else-часть, то выполняется <Оператор_2>. Операции отношения применяются при формировании условных выражений, используемых в операторах if и while. Указанные операции позволяют проверить, истинно или ложно данное выражение. Примеры (использования операций отношения). 1. if (number<6) printf("Ваше число слишком мало."); 2. if (total==100) printf("Вы набрали максимум.\n"); 3. if (ch>'M') printf("Отправьте его обратно.\n"); Замечание (важное). Применяйте отступы от начала строки для того, чтобы сделать структуру программы наглядной. 3. Конструкция else/if Я рекомендовал бы ставить после "если" "то" во всех математических текстах. Наличие слова "то" никогда не приведёт к недоразумению, а вот его отсутствие может. П.Р.Халмош. Как писать математические тексты Часто желательно осуществлять выбор более, чем из двух вариантов. Чтобы учесть это, мы можем расширить конструкцию if/else конструкцией else/if. Приведём синтаксис распространённого способа выбора по значению из нескольких вариантов, который называется конструкцией else/if: if (<Выражение_1>) <Оператор_1> else if (<Выражение_2>) <Оператор_2> else if (<Выражение_3>) <Оператор_3> else <Оператор_N>; Операционная семантика конструкции else/if очевидна: выражения просматриваются последовательно слева направо; как только какое-то выражение становится истинным, выполняется следующий за ним оператор, и на этом вся цепочка заканчивается. Последняя else-часть, как и ранее, может быть опущена. Пример [Болски,1988]. Приведём фрагмент, заимствованный из игровой программы, где переменная bonus представляет собой количество дополнительных "фотонных бомб", получаемых игроком для следующей партии: int score,bonus; if (score<1000) bonus=0; else if (score<1500) bonus=1; else if (score<2000) bonus=2; else if (score<2500) bonus=4; else bonus=6; Работа с демонстрационными примерами См. Пример 10, Пример 11, Пример 12, Пример 13. 4. Оператор switch Вся трудность - в выборе. Джордж Моор. Ветви гнутся Жить — значит постоянно решать проблему выбора. Народная мудрость Условная операция и конструкция if/else облегчают написание программ, в которых осуществляется выбор между двумя вариантами. Однако часто в программе необходимо произвести выбор одного из нескольких вариантов. Конечно, мы можем сделать это с помощью конструкции if/else, но во многих случаях оказывается более удобным воспользоваться оператором switch. Определение (синтаксис оператора switch). Оператор switch имеет следующий вид: switch (<Выражение>) { case <Константа_1>:<Список_операторов_1> case <Константа_2>:<Список_операторов_2> case <Константа_N>:<Список_операторов_N> default :<Список_операторов> } где switch (англ. переключатель), default (англ. используемый по умолчанию) - служебные слова; <Выражение> - выражение, значением которого должна быть величина целого или символьного типа; <Константа_1>,...,<Константа_N> - константы или константные выражения, которые называются метками оператора switch (константные выражения - это выражения, операнды которого являются константами). Список операторов, стоящий после двоеточия, может быть либо пустым, либо заканчиваться одним из операторов завершения (break, continue, goto, return). Определение (операционная семантика оператора switch). Вычисляется значение выражения <Выражение>, затем компилятор просматривает список меток оператора switch до тех пор, пока не находит метку, которая совпадает со значением этого выражения. Если метка найдена, то управление передается оператору, расположенному в этой строке, а затем (если не предусмотрены переходы или выход из оператора switch) последовательно выполняются все операторы, начиная с той метки, на которую передано управление. Пусть подходящей метки не нашлось. Тогда, если существует строка с меткой default, то выполняется оператор, помеченный этой меткой. В противном случае произойдет переход к оператору, расположенному вслед за оператором switch. Если у вариантов нет общих частей, то рекомендуется каждый вариант завершать оператором break. Работа с демонстрационными примерами См. Пример 14, Пример 15, Пример 16. Замечание (важное). Отсутствие оператора break при обработке одной из ветвей оператора switch может служить источником ошибок. Эта проблема называется проблемой провала (fail-through). Элементы языка C++ без классов Для понимания языка С++ желательно, чтобы уже был изучен язык С. Т.Пратт, М.Зелковиц [2002,c.293] 1. Комментарии В С++ можно использовать два вида комментариев: (1) обычные, оформленные по правилам языка С; (2) однострочные комментарии, начинающиеся с лексемы // и продолжающиеся до конца строки. Возможно использование вложенных комментариев. Пример. // Коммен-/* Такое вложение возможно! */-тарий 2. Организация ввода/вывода Каждый программист на языке C++ должен уметь программировать на языке C. Неписаное правило Г.Шилдта Этот раздел является вводным и даёт необходимый минимум понятий, достаточный, чтобы Вы смогли освоиться и начать работать. Ввод/вывод не является непосредственной деталью языка программирования С++. Он представляет собой дополнение в виде набора типов и подпрограмм, заложенных в стандартной библиотеке. В распоряжении С++ находятся следующие стандартные библиотеки: - библиотека stdio.h; - библиотека потокового ввода/вывода C++ iostream.h. Библиотека iostream.h перегружает две операции поразрядного сдвига ("левый сдвиг" и "правый сдвиг"): << - "поместить в" выходной поток; >> - "получить из" входного потока. Эта библиотека также объявляет три стандартных потока: cout - стандартный вывод, cin - стандартный ввод (по умолчанию - клавиатура), cerr - стандартная ошибка. Использование их вместе со значениями и переменными рассмотрим с помощью примера. Работа с демонстрационными примерами См. Пример 17. ДЕМОНСТРАЦИОННЫЕ ПРИМЕРЫ Зачем знать, если не уметь, зачем уметь, если не делать? Монгольская пословица Пример 1. /* Демонстрация синтаксиса и семантики оператора присваивания */ /* ---------------------------------------------------------- */ #include { int x,y,a; /* -------------- */ x=5; y=x*2+7; a=y/4; printf("Результаты: %d %d %d\n",x,y,a); y=(10*10+11*11+12*12+13*13+14*14)/365; printf("Ответ: %d\n",y); return 0; } Результат работы программы: Результаты: 5 17 4 Ответ: 2 Пример 2. /* Демонстрация вычисления суммы цифр натурального */ /* числа n, меньшего 1000 */ /* ----------------------------------------------- */ #include #include { int x,a,b,c; /* ------------------------------------------------ */ /* Первый вариант. Стиль начинающего C-программиста */ printf("Введите натуральное x<1000: "); scanf("%d",&x); a=x/100; x=x-a*100; b=x/10; x=x-b*10; c=x; printf("Результат : %d\n",a+b+c); getch(); /* --------------------------------------------- */ /* Второй вариант. Стиль опытного C-программиста */ printf("Введите натуральное x<1000: "); scanf("%d",&x); x-=(b=(x-=(a=x/100)*100)/10)*10; printf("Результат : %d\n",a+b+x); getch(); /* -------------------------------------------------- */ /* Третий вариант. Стиль экономного C-программиста. */ /* Обратить внимание на количество переменных */ printf("Введите натуральное x<1000: "); scanf("%4d",&x); printf("Результат : %d\n", x%10+x/10%10+x/100%10); getch(); return 0; } Результат работы программы: Введите натуральное x<1000: 925 16 Введите натуральное x<1000: 925 16 Пример 3. /* Демонстрация специальных форм присваивания, к ко- */ /* торым относятся: */ /* += (сложение с присваиванием); */ /* -= (вычитание с присваиванием); */ /* *= (умножение с присваиванием); */ /* /= (деление с присваиванием); */ /* %= (остаток от деления с присваиванием); */ /* >>= (сдвиг влево с присваиванием); */ /* <<= (сдвиг вправо с присваиванием); */ /* &= (битовое "И" с присваиванием); */ /* |= (битовое "ИЛИ" с присваиванием); */ /* ^= (битовое исключающее "ИЛИ" с присваиванием) */ /* -------------------------------------------------- */ #include #include { int a,b; float x,y,z; /* ----------------------------- */ printf("\nВводите целые числа:\n"); printf("a="); scanf("%d",&a); printf("b="); scanf("%d",&b); /* ---------------------------------- */ printf("Вводите вещественные числа:\n"); printf("x="); scanf("%f",&x); printf("y="); scanf("%f",&y); printf("z="); scanf("%f",&z); /* ----------------------- */ a%=b; printf("a%=b, теперь a="); printf("%d, ",a); printf("b=%d\n",b); x+=y; printf("x+=y, теперь x=%f, y=%f\n",x,y); z/=x; printf("z/=x, теперь z=%f, x=%f\n",z,x); y*=b; printf("y*=b, теперь y=%f, b=%d\n",y,b); getch(); return 0; } Результат работы программы: Вводите целые числа: a=9 b=5 Вводите вещественные числа: x=1.32 y=2.23 z=3.003 a%=b, теперь a=4, b=5 x+=y, теперь x=3.550000, y=2.230000 z/=x, теперь z=0.845915, x=3.550000 y*=b, теперь y=11.150000, b=5 Пример 4 [Керниган,Ритчи,Фьюер,1985,с.195]. /* Демонстрация некоторых специальных форм присваивания */ /* ---------------------------------------------------- */ #include #include { int x=2,y,z,k; /* ------------------------------------------------------ */ x*=3+2; printf ("1. x=%d\n",x); /* Операция 1 */ x*=y=z=4; printf ("2. x=%d\n",x); /* Операция 2 */ x=y==z; printf ("3. x=%d\n",x); /* Операция 3 */ k=x==(y=z); printf ("4. k=%d, x=%d\n",k,x); /* Операция 4 */ getch(); return 0; } Результат работы программы: x=10 x=40 x=1 k=0,x=1 Комментарии результата работы программы. Операции 1. x*=3+2; Следуем таблице приоритетов операций: x*=(3+2); (x*=(3+2)); Вычисляем выражение: (x*=5); Раскроем операцию присваивания: (x=x*5); (x=10); 10 Операции 2. x=10; x*=y=z=4; В этом выражении все операции есть операции присваивания, значит, порядок их выполнения справа налево. x*=y=(z=4); x*=(y=(z=4)); (x*=(y=(z=4))); Вычисляем значение выражения: (x*=(y=4)); (x*=4); 40 Операции 3. y=4; z=4; x=y==z; Нельзя путать операцию присваивания "=" и операцию отношения "==". Из таблицы приоритетов операций следует, что приоритет операции "==" выше, чем операции "=". x=(y==z); (x=(y==z)); (x=(TRUE)); (x=1); 1 Операции 4. x=1; z=4; k=x==(y=z); В выражении x==(y=z) операция присваивания (благодаря действию скобок) выполняется раньше, чем операция сравнения на равенство. k=0; 0 Пример 5 [Керниган,Ритчи,Фьюэр,1985,с.195]. /* Демонстрация синтаксиса и семантики логических */ /* операций и операций увеличения */ /* ---------------------------------------------- */ #include #include { int x=1, y=1, z=0; /* ------------ */ x=x&&y||z; /* Операции 1 */ printf("%d ",x); /* ----------- */ x=x||!y&&z; /* Операции 2 */ printf("%d ",x); /* ----------- */ x=y=1; z=x++-1; /* Операции 3 */ printf("%d ",x); printf("%d ",z); /* ----------------------------- */ z+=-x++ + ++y; /* Операции 4 */ /* z+=(-(x++))+(++y); */ printf("%d ",x); printf("%d ",z); /* ---------------------------- */ z=x/++x; /* Операции 5 */ printf("%d ",x); printf("%d\n",z); getch(); return 0; } Результат работы программы: 1 1 2 0 3 0 4 1 Комментарии результата работы программы. Операции 1. int x=2; y=1; z=0; x=x&&y||z; Сопоставляем операции с операндами в соответствии с приоритетами операций. x=(x&&y)||z; x=((x&&y)||z); (x=(x&&y)||(z)); Логические операции выполняются слева направо. Считается, что значение операнда в логической операции есть "ложь", если операнд равен 0, и "истина", если операнд имеет любое другое значение. (x=((TRUE&&TRUE)||(z)); (x=(TRUE||z); Если известно, что один из операндов логической операции "ИЛИ" (||) имеет значение "истина", то результат операции - "истина", независимо от значения другого операнда. Таким образом, в данном случае нет смысла продолжать вычисления дальше. (x=TRUE); 1 Операции 2. x=1; y=1; z=0; Сопоставляем операции с операндами в соответствии с приоритетами операций. x=x||!y&&z; x=x||(!y)&&z; x=x||((!y)&&z); (x=(x||(!y)&&(z))); Вычисляем слева направо: (x=(TRUE||((!y)&&z))); (x=TRUE); (x=1); 1 Операции 3. x=1; y=1; Вследствие приоритетов операций: z=x++-1; z=(x++)-1; z=((x++)-1); (z=((x++)-1)); Операция ++, стоящая справа от операнда, представляет собой постфиксную операцию. Это означает, что x увеличится на 1 после того, как значение x будет использовано в выражении: (z=(1-1)); x=2; (z=0) 0 Операции 4. x=2; y=1; z=0; z+=-x++ + ++y; Унарные операции выполняются справа налево, так что операция ++ выполнится перед операцией "-". z+=-(x++) + (++y); Фактически, если бы операция изменения знака выполнялась первой, выражение было бы некорректным, так как операции ++ и -- требуют, чтобы операндом было адресное значение; x является адресным значением, а -x - нет. z+=(-(x++))+(++y); z+=((-(x++))+(++y)); (z+=((-(x++))+(++y))); Вычисление выражения начинается изнутри: (z+=((-2)+2)); x=3; y=2; (z+=0); 0 Операции 5. x=3; z=0; z=x/++x; z=x/(++x); z=(x/(++x)); (z=(x/(++x))); Вы могли бы поддаться искушению вычислять это выражение "изнутри". Вначале было бы выбрано значение x, увеличено на 1, а потом уже пойдет деление на значение x. Но возникает вопрос: какое значение x нужно использовать в качестве делимого - "старое" (3) или "новое" (4)? Иными словами, что делается раньше - выбирается ли значение x, используемое в качестве делимого, или в x записывается его значение, увеличенное на 1. Описание языка C не определяет, что получается, если возникают такие побочные эффекты; их реализация остается за разработчиками трансляторов. Побочным эффектом называется любое изменение результатов работы программы как следствие выполнения некоторого оператора. Большинство побочных эффектов в языке C связано с записью в память промежуточных значений переменных, которые, как выше, получаются в результате операции увеличения или в результате присваивания, встретившегося в выражении. Отсюда - совет: избегайте выражений, вычисление которых зависит от Вашего знания того, что происходит при побочных эффектах. |