|
Скачати 2.03 Mb.
|
using System; namespace Comparing_Operators { class Program { static void Main() { int x = 1, y = 2; bool b = (x > y); Console.WriteLine("x > y ? " + b.ToString()); b = (x <= y); Console.WriteLine("x <= y ?" + b.ToString()); b = (x == y); Console.WriteLine("x == y ?" + b.ToString()); } } } Після запуску програми одержимо наступний результат: x > y ? False x <= y ? True x == y ? False Логічні операції. Логічні операції виконуються над операндами логічного (булівського) типу та визначають результат логічного типу. Логічні операції мають дві форми: звичайну та скорочену. Розглянемо спочатку набір звичайних логічних операцій: (&) – логічне множення або логічне «І», (|) – логічне додавання або логічне «АБО», (^) – логічне виключне «АБО», (!) – логічне заперечення «НІ». Значення логічних операцій наведені нижче у таблиці для різних значень операндів (op1 та op2).
Крім того, логічні множення та додавання мають ще скорочені форми, які позначаються знаками && та || відповідно. Ідея їх використання пов’язана з прискоренням логічних обчислень – обчислення логічного виразу, складеного із скорочених логічних операцій припиняється, якщо його значення стає визначеним. Наступний приклад демонструє різницю у використанні повної та скороченої форм логічних операцій. using System; namespace Logic_Operator { class Program { static void Main() { int i = 10, k = 100; if (!(k > 10) && (++i < 100)) // Тут i не зміниться // Цей оператор не виконується Console.WriteLine( "Скорочена форма &&: тут i не зміниться" ); Console.WriteLine("i = " + i.ToString()); i = 10; // Відновлюємо i if (!(k > 10) & (++i < 100)) // Тут i зміниться // Цей оператор не виконується Console.WriteLine("Звичайна форма &: тут i зміниться"); Console.WriteLine("i = " + i.ToString()); } } } Порозрядні (бітові) операції. Порозрядні операції виконуються над відповідними бітами внутрішнього подання лише цілих операндів. Результатом виконання є ціле відповідного операндам типу. Таких операцій є 6 : (&) – порозрядне «І», тобто кон’юнкція бітів, (|) – порозрядне «АБО»,тобто диз’юнкція бітів, (^) – порозрядне виключне «АБО», (>>) – порозрядний зсув праворуч, (<<) – порозрядний зсув ліворуч, (~) – порозрядне заперечення. Всі операції, крім останньої, є бінарними. Слід зауважити, що при зсуві ліворуч (<<) на вказану правим операндом кількість позицій внутрішнє подання лівого операнду просто зсувається ліворуч, а позиції, що вивільняються, заповнюються нулями. При зсуві праворуч (>>) позиції, що вивільняються ліворуч, заповнюються нулями для беззнакового операнду, якщо ж зсув виконується для знакового операнду, то на вільні ліві позиції розповсюджується знаковий розряд, тобто для від’ємного числа вільні позиції ліворуч заповняться одиницями. Це обов’язково слід враховувати. У наведеній нижче таблиці вказані результати бітових операцій для різних значень операндів (op1 та op2).
Наступний приклад демонструє можливості операцій над бітами. using System; namespace Bits_Operators { class Program { static void Main() { int x = 5, y = 6, z; z = x & y; // Логічне множення "I" Console.WriteLine("x = {0} y = {1} x & y = {2}",x,y,z); z = x | y; // Логічне додавання "АБО" Console.WriteLine("x = {0} y = {1} x | y = {2}",x,y,z); z = x ^ y; // Логічне виключне "АБО" Console.WriteLine("x = {0} y = {1} x ^ y = {2}",x,y,z); z = x << 1; // Зсув на 1 позицію ліворуч Console.WriteLine("x = {0} x << 1 = {1}", x, z); z = x >> 1; // Зсув на 1 позицію праворуч Console.WriteLine("x = {0} x >> 1 = {1}", x, z); z = ~y; // Логічне заперечення "НІ" Console.WriteLine("y = {0} ~y = {1}", y, z); z = y | 0X7; // Встановлюємо одиниці в останні 3 розряди Console.WriteLine("y = {0} y|0X7 = {1}", y, z); z = x & ~0X7; // Встановлюємо нулі в останні 3 розряди Console.WriteLine("x = {0} x&~0X7 = {1}", x, z); } } } Виконання цієї програми приведе до наступних результатів: x = 5 y = 6 x & y = 4 x = 5 y = 6 x | y = 7 x = 5 y = 6 x ^ y = 3 x = 5 x << 1 = 10 x = 5 x >> 1 = 2 y = 6 ~y = -7 Умовна (тернарна) операція. Умовна операція має наступну синтаксичну форму: <�вираз_1> ? < вираз_2> : < вираз_3> Назву «тернарна» ця операція має тому, що її визначають 3 вирази. Перший вираз повинен мати тип bool. Якщо його значення рівне true, то обчислюється значення другого виразу, яке і визначає всю тернарну операцію. Якщо ж значення першого виразу false, то обчислюється значення третього виразу, і його значення стає значенням всього тернарного виразу. Наприклад, у наступному фрагменті коду обчислюється максимум двох цілих змінних: int z = (x > y) ? x : y; int x = 3, y = 4; Console.WriteLine("максимум із {0} та {1} є {2}",x,y,z); Після виконання цього фрагменту на екрані побачите повідомлення : максимум із 3 та 4 є 4 Операції присвоєння. Крім звичайної операції присвоєння (=) в мові С# виконуються ще 10 скорочених операцій присвоєння, які позначаються як = , де знак може бути замінений на знак однієї з операцій : + - * / % & | ^ >> << . При цьому значення конструкції <�змінна> = <�вираз>; обчислюється наступним чином: <�змінна> = <�змінна> <�вираз> ; Наприклад, інструкція x += 1; еквівалентна наступній інструкції: x = x + 1; Оскільки виконання операції присвоєння генерує результат, рівний значенню своєї правої частини, допускається виконання ланцюжку присвоєнь. Так, наприклад, в наступному фрагменті коду ініціалізуються нулями відразу 3 змінні: int i, j, k; i = j = k = 0; Пріоритет операцій. При складанні виразів слід враховувати, що порядок виконання операцій у виразі визначається пріоритетом операцій. Проте правилом хорошого тону слід вважати використання дужок, які підкреслюють порядок обчислень та роблять вираз більш зрозумілим. Наступна таблиця вказує основні операції мови С# в порядку спадання їх пріоритетів від найвищого до найнижчого. ( ) [ ] ++(постфіксний) --(постфіксний) new sizeof ! ~ +(унарний) -(унарний) ++(префіксний) --(префіксний) * / % + - << >> < <= > >= is == != & | ^ && || ? : = = Зауваження. Різницю у пріоритетах префіксних та постфіксних операцій інкременту-декременту можна побачити у наступному прикладі. using System; namespace Prioritet { class Program { static void Main() { int x = 1, y = 2, z; z = x++ + y; // Вираз мав вигляд: z = x+++y; Console.WriteLine("x = {0} y = {1} z = {2}", x, y, z); x = 1; y = 2; // Вcтановлюємо початкові значення змінних z = x + ++y; // Визначаємо пріоритет пробілами Console.WriteLine("x = {0} y = {1} z = {2}", x, y, z); } } } Тобто, вираз записаний у вигляді z = x+++y; був проінтерпретований згідно таблиці пріоритетів як z = x++ + y; , а не як z = x + ++y; . Якщо ми хочемо визначити порядок операцій іншим, використовуємо дужки та пробіли.
Для реалізації розгалужень (одного із трьох основних елементів програм) в мові С# використовуються конструкції if та switch. Конструкція if може бути використана у двох формах. Повна форма має наступний синтаксис. if (<�умова>) інструкція_1; then інструкція_2; <�Умовою> є вираз з результатом типу bool. Порядок виконання цієї конструкції очевидний – якщо результатом умови є «Істина» (true), то виконується перша з інструкцій, якщо ж результатом умови є «Хибність» (false), – то друга. Коли необхідно виконати не одну інструкцію, а більше, їх необхідно об’єднати у блок: if (<�умова>) { // інструкції } else { // інструкції } Частина then не є обов’язковою і може бути пропущена. Тоді при істинності умови єдина інструкція if виконується, а при хибності – управління виконанням програми передається наступній конструкції програми. В першому з них шукаємо максимум з двох чисел, використовуючи спочатку коротку, а потім – повну форму конструкції if. using System; namespace Construct_if { class Program { static void Main() { // Знаходження максимуму із двох чисел float x, y, max; Console.Write("Введiть значення x = "); x = float.Parse(Console.ReadLine()); Console.Write("Введiть значення y = "); y = float.Parse(Console.ReadLine()); max = x; // Призначаємо х максимумом if (y > max) // Можливо, максимумом є y? max = y; Console.WriteLine( "Максимум iз {0} та {1} дорiвнює {2}", x, y, max); Console.WriteLine(""); // Шукаємо максимум iншим способом if (y > x) max = y; else max = x; Console.WriteLine( "Максимум iз {0} та {1} дорiвнює {2}", x, y, max); } } } В наступному прикладі для деякого вкладника можливе одержання бонусу в разі, коли він вказує правильний пароль та сума на його рахунку перевищує контрольну константу. Зверніть увагу, на умову (parol == RIGHT_PAROL). Поширеною помилкою, навіяною синтаксисом аналогічної конструкції в Паскалі, є використання одного знаку = замість двох == при перевірці на рівність двох об’єктів. Крім того, тут конструкції if-else вкладені одна в одну. using System; namespace Construct_if_else { class Program { static void Main() { // Мінімальна сума для бонусу const decimal MINSUM = 10000; // Значення справжнього паролю const string RIGHT_PAROL = "myparol"; string parol; decimal sum; Console.WriteLine("Введiть пароль"); parol = Console.ReadLine(); // Перевірка правильності паролю if (parol == RIGHT_PAROL) { // Пароль правильний Console.WriteLine("Введiть суму внеску"); sum = int.Parse(Console.ReadLine()); if (sum > MINSUM) // Перевіряємо суму внеску Console.WriteLine( "Вiтаємо! Ви одержуєте бонус!"); else Console.WriteLine("Накопичуйте ще!"); } else // Пароль неправильний Console.WriteLine( "Ви ввели невiрний пароль"); } } } Використання вкладених умовних конструкцій може привести до випадку, коли на дві або більше частини if приходиться лише одна частина else. Тоді вважається, що вона відноситься до найближчої частини if, що не має частини else. using System; namespace Nested_if { class Program { static void Main() { // Розбираємось із вкладеними if-else int i = 1, j = 2, k = 5; if ((i != 0) & (j > 1)) if (k == 10) Console.WriteLine("Перевiрка k == 10 дає true"); else Console.WriteLine("Перевiрка k == 10 дає false"); } } } Тому при виконанні даного прикладу на екрані з’являється повідомлення: Перевiрка k == 10 дає false Поширеною практикою при «багатошарових перевірках» є використання вкладених конструкцій if-else-if. У наступному прикладі завжди виконується одна і тільки одна інструкція. using System; namespace Construct_if_else_if { class Program { static void Main() { // Виконуємо операції з цілими числами char op; int x = 10, y = 20; Console.WriteLine( "Введiть знак для операцiї з числами {0} {1}", x, y); op = (char)Console.Read(); if (op == '+') // Додаємо? Console.WriteLine( "{0} " + op + " {1} = {2}" , x, y, x + y); else // Ні! if (op == '-') // Віднімаємо? Console.WriteLine( "{0} " + op + " {1} = {2}", x, y, x - y); else // Ні! if (op == '*') // Множимо? Console.WriteLine( "{0} " + op + " {1} = {2}", x, y, x * y); else // Ні! if (op == '/') // Ділимо? Console.WriteLine( "{0} " + op + " {1} = {2}", x, y, x / y); else // Ні! if (op == '%') // Шукаємо залишок? Console.WriteLine( "{0} " + op + " {1} = {2}", x, y, x % y); else // Ні! Console.WriteLine( "Неприпустимий знак операцiї"); } } }
Для більш зручної та компактної реалізації подібних розгалужень з багатьма альтернативами в мові С# використовується конструкція switch. Вона має наступний синтаксис. switch (<�вираз>) { case <�константа_1> : <�інструкції> break; case <�константа_2> : <�інструкції> break; … case <�константа_n> : <�інструкції> break; default : <�інструкції> break; } Тут <�вираз> повинен мати цілий тип (або тип char), кожна з констант є унікальною і сумісною за типом із <�виразом>. Після обчислення <виразу> виконується та гілка конструкції switch, яка містить константу рівну значенню <�виразу>. Якщо жодна з констант не співпадає із значенням <�виразу>, виконуються інструкції гілки default. Втім, остання не є обов’язковою і в разі її відсутності у випадку, коли жодна з констант не співпадає із значенням <�виразу>, жодна інструкція конструкції switch не виконується взагалі. Перепишемо попередню програму за допомогою конструкції switch. using System; namespace Construct_switch { class Program { static void Main() { char op; int x = 10, y = 20; Console.WriteLine( "Введiть знак для операцiї з числами {0} {1}", x, y); op = (char)Console.Read(); switch (op) { case '+': // Додаємо? Console.WriteLine( "{0} " + op + " {1} = {2}", x, y, x + y); break; case '-': // Віднімаємо? Console.WriteLine( "{0} " + op + " {1} = {2}", x, y, x - y); break; case '*': // Множимо? Console.WriteLine( "{0} " + op + " {1} = {2}", x, y, x * y); break; case '/': // Ділимо? Console.WriteLine( "{0} " + op + " {1} = {2}", x, y, x / y); break; case '%': // Беремо залишок? Console.WriteLine( "{0} " + op + " {1} = {2}", x, y, x % y); break; default: // Помилка Console.WriteLine( "Неприпустимий знак операцiї"); break; } } } } Зауваження.
using System; namespace Construct_case_case { class Program { static void Main() { Console.WriteLine("Введiть цiле число"); int i = int.Parse(Console.ReadLine()); switch( i*i % 4) { // Однаковий набір інструкцій для i*i % 4 == 0 або 2 case 0: case 2: Console.WriteLine("Число було парним"); break; // Однаковий набір інструкцій для i*i % 4 == 1 або 3 case 1: case 3: Console.WriteLine("Число було непарним"); break; } } } }
Для реалізації ітерацій деякої інструкції або групи інструкцій в мові С# передбачено 4 види циклів. Зараз познайомимось з трьома з них. 2.1. Цикл for. Синтаксис цього циклу наступний. for (<�вираз-ініціалізація>;<�вираз-умова>;<�вираз-ітерація>) <�інструкція циклу>; або for (<�вираз-ініціалізація>;<�вираз-умова>;<�вираз-ітерація>) { <�група інструкцій>; } Виконання циклу for відбувається наступним чином.
Найчастіше у <�виразі-ініціалізації> встановлюється початкове значення деякої змінної, яка відіграє роль змінної циклу. <�Вираз-ітерація> змінює значення цієї змінної, а у <�виразі-умові> її значення порівнюється з деяким граничним значенням для прийняття рішення щодо продовження чи завершення циклу. Розглянемо приклади. У першому прикладі обчислюється сума . using System; namespace Construct_for_sum { class Program { static void Main() { // Обчислюємо суму double s = 0; for (int i = 1; i <= 10; i++) s += Math.Sin(i) / i; Console.WriteLine( "Сума sin(i)/i вiд 1 до 10 рiвна {0}", s); } } } Можливості мови дозволяють записати цикл, еквівалентний попередньому «порожнім», тобто таким, що містить лише порожню інструкцію ; (зауважимо, що за синтаксисом «тіло» циклу for повинно містити принаймні одну інструкцію, хоч і порожню). using System; namespace Construct_for_sum { class Program { static void Main() { // Обчислюємо суму double s = 0; // Тіло циклу – порожнє, все «заховано» в ітерації for (int i = 1; i <= 10; s += Math.Sin(i)/i++) ; Console.WriteLine( "Сума sin(i)/i вiд 1 до 10 рiвна {0}", s); } } } У наступному прикладі розглядається ціле число типу byte (тип byte може бути замінений з відповідними виправленнями у програмі на довільний цілий беззнаковий тип – беззнаковий тому що використовується операція зсуву праворуч, про особливості якої ми говорили раніше). По результату порозрядного множення числа на маску 0X1, яка у внутрішньому поданні є послідовністю нулів з одиницею лише в останньому розряді, встановлюємо зміст останнього розряду числа. А оскільки треба «переглянути» всі розряди, то ми просто по черзі використовуємо порозрядний зсув числа праворуч, починаючи з найстаршого розряду, а отже, з максимального зсуву на sizeof(byte)*8-1 позицій. using System; namespace Construct_for_Bits { class Program { static void Main() { // друкуємо біти внутрішнього подання цілого числа byte ui; Console.WriteLine("Введiть цiле число"); ui = byte.Parse(Console.ReadLine()); byte size = sizeof(byte) * 8; for (int i = size - 1; i >= 0; i--) { // використовуємо бітові операції; 0X1 = 00000…001 if (((ui >> i) & 0X1) != 0) Console.Write("1"); else Console.Write("0"); // пробіл між четвірками бітів if (i % 4 == 0) Console.Write(" "); } Console.WriteLine(); } } } Зауваження.
for (;;) { // інструкції нескінченного циклу // вихід з циклу має бути передбаченим якимось чином }
int i, j; // тут 2 змінні циклу: i та j for (i = 0, j = 10; i < j; i++, j--) Console.WriteLine("i = {0} j = {1}", i, j); 2.2. Цикл while. Синтаксис цього циклу наступний. while (<�вираз-умова >) <�інструкція циклу>; Порядок виконання циклу наступний:
Зрозуміло, що в інструкції циклу (або в блоці інструкцій) слід передбачити якийсь вплив на умову циклу, інакше він, розпочавшись, не зможе завершитись. У наступній програмі обчислюється та сама суму, що була запрограмована з допомогою циклу for у першому прикладі. Переконайтесь у незмінності результату. using System; namespace Construct_WhileSum { class Program { // Обчислюємо ту саму суму, що й у прикладі з циклом for static void Main() { int i = 1; double sum = 0; while (i <= 10) { sum += Math.Sin(i) / i; i++; } Console.WriteLine("sum = {0}", sum); } } } У прикладі, наведеному нижче, знаходимо кількість цифр у цілому числі. В циклі while фіксується кількість кроків, за яку число шляхом цілочисельного ділення на 10 перетворюється на 0. using System; namespace Construct_whileDigits { class Program { // знаходимо кількість цифр у цілому числі static void Main() { Console.WriteLine("Введiть цiле число"); long num = long.Parse(Console.ReadLine()); if (num < 0) num = Math.Abs(num); byte count = 0; while (num != 0) { num /= 10; // Зменшуємо число на один розряд count++; } Console.WriteLine("Кiлькiсть цифр = {0}", count); } } } 2.3. Цикл do-while. Цей цикл на відміну від попереднього називають циклом з післяумовою, оскільки умова виходу з циклу аналізується вже після його виконання. Він має наступний синтаксис. do { <�інструкції циклу> } while (<�вираз-умова >) Порядок виконання циклу наступний:
Цикл do-while відрізняється від циклів while та for тим, що його інструкції виконуються завжди принаймні один раз. Розглянемо приклад, який забезпечить повторні запуски для тестування вашої програми. Сигналом для виходу стане натискання клавіші ESC . Цей контроль відбувається в умові циклу do-while. using System; namespace Construct_do_while { class Program { // Забезпечуємо повторний запуск програми // до натискання клавіши ESC static void Main() { // Змінна для збереження значень натиснутих клавіш ConsoleKeyInfo conKey; do { Console.WriteLine("Тут будуть iнструкцiї програми"); Console.WriteLine("Для виходу натиснiть ESC"); // Одержуємо значення натиснутої клавіши conKey = Console.ReadKey(true); } // Порівнюємо його з ESC while (conKey.Key != ConsoleKey.Escape); } } Нижче – інший варіант реалізаціїї тієї ж ідеї, программа виконується повторно до тих пір, поки не буде натиснутий символ ‘1’. using System; namespace Construct_do_while { class Program { // Запит на повторний запуск програми // Погодження – натискання символу 1 static void Main() { string answer; do { Console.WriteLine("Тут будуть iнструкцiї програми "); Console.WriteLine("Продовжувати виконання? \n Для пiдтвердження натиснiть 1"); answer = Console.ReadLine(); } while (answer == "1"); } } } Зауваження. Будь-який з означених циклів може містити інший цикл – так виникають вкладені цикли. Наприклад, для обчислення подвійної суми виду можна використати вкладений цикл: for (int i = 1; i <= N; i++) for (int j = 1; i <= M; j++) s += a (i, j); Зазначимо ще, що враховуючи сказане вище, можна запропонувати певні правила вибору типу циклу для різних конкретних випадків, а саме:
|
Програма курсу програмування на мов і С++ Курс націлений на отримання знань і практичних навиків програмування на мовах C і C + + в рамках процедурно-орієнтованого програмування.... |
Основні методології (стилі, парадигми) програмування. Поняття програми.... Дів розробки програм Граді Буча “О’єктно-орієнтоване програмування (ООП) – це методологія програмування, яка заснована на представленні... |
Курс програмування на С # Зусилля, які ви витратите на вивчення С #, будуть винагороджені, так як Сі Шарп був розроблений в якості основної мови програмування,... |
27. Процедурні мови програмування Процедурні мови програмування. Характеристика процедурних мов програмування. Алфавіт. Основні поняття мови: числа, рядки, ідентифікатори,... |
27. Методика навчання обєктно-орієнтованого програмування. Об'єктно́-орієнтоване́... Не зважаючи на те, що ця парадигма з'явилась в 1960-тих роках, вона не мала широкого застосування до 1990-тих. На сьогодні багато... |
29. Опис та використання підпрограм Реалізація базових алгоритмічних структур процедурною мовою програмування. Опис процедур та функцій процедурною мовою програмування.... |
2. Дробово-лінійне програмування Постановка задачі дробово-лінійного... Дослідження операцій”, “Економетрія”, “Моделювання економіки”, “Економічна кібернетика” а також дисциплін циклу загальноекономічної... |
Методичні рекомендації щодо вивчення інформатики у 2012-2013 навчальному році Особливо гостро стоїть питання поглибленого вивчення інформатики та сучасних мов програмування |
ПОРЯДОК проведення відкритої Всеукраїнської студентської олімпіади з програмування Першості світу) з програмування АСМ-ICPC (Association for Computing Machinery International Collegiate Programming Contest), яка... |
1. Українська мова належить до: а східнослов’янської підгрупи мов;... Яке з поданих слів має значення „спрямований вперед; який рухається у висхідному напрямі” |