69073

Короткий огляд мови C#

Лекция

Информатика, кибернетика и программирование

Весь виконуваний код C# повинен міститися у класі – у даному випадку класі Program. На відміну від мови C та аналогічних, у C# не можна об’явити глобальну функцію чи змінну. Клас Program міститься у просторі імен DemoApp. При створенні програми в Visual C# простір імен створюється автоматично.

Украинкский

2014-09-29

568.5 KB

7 чел.

Лекція №4. Короткий огляд мови C#

Слайд 1: Hello, World

// Перша програма на C#

using System;

namespace DemoApp

{

   class Program

   {

       static void Main(string[] args)

       {

           /* Вивести на екран рядок "Hello, world" */

           System.Console.WriteLine("Hello, world!");

       }

   }

}

Весь виконуваний код C# повинен міститися у класі – у даному випадку класі Program. На відміну від мови C та аналогічних, у C# не можна об’явити глобальну функцію чи змінну. 

Клас Program міститься у просторі імен DemoApp. При створенні програми в Visual C# простір імен створюється автоматично. Для використання в програмі класів з інших просторів імен необхідно вказати їх у директиві using. При створенні нового застосування найбільш часто використовувані простори імен .NET Framework включаються до списку за промовчанням. При використанні класів з інших просторів імен з бібліотеки класів необхідно додати директиву using для відповідного простору імен.

У програмі на C# повинен бути присутнім метод Main, який є точкою входу в програму. У методі Main створюються об'єкти і виконуються інші методи. Цей метод є статичним методом, розташованим усередині класу або структури. У наведеному вище прикладі "Hello World!" він розташований в класі з ім'ям програми.

Метод Main можна оголосити таким, що повертає значення типу int або не повертає значень (тип void, як у прикладі). Він також може приймати аргументи, що може бути корисно для програм командного рядка, або не приймати аргументи.

Параметр методу Main є масивом рядків (string[] args), що представляє аргументи командного рядка, використовувані для виклику програми. Зверніть увагу, що на відміну від C++, масив не містить ім'я виконуваного (EXE) файлу.

namespace DemoApp: ми заявляємо, що наш клас знаходиться у просторі імен DemoApp.

Метод Main викликає статичний метод WriteLine класу (типу) System.Console. Метод WriteLine приймає у якості аргументу рядок.

Оператор Console.WriteLine("Hello, world!"); використовує метод WriteLine, який виводить свій параметр у вікно командного рядка з нового рядка. Інші методи Console використовуються для різних операцій введення і виведення. Клас Console, який містить методи для різних операцій введення і виведення, є членом простору імен System.

System.Console.WriteLine("Hello, world!"); – повне кваліфіковане ім'я функції-члена класу Console, що відповідає за виведення рядка в вікно застосування. При компіляції модуля, транслятор за повним іменем функції (якщо використовується оператор using, то за відновленим) знаходить її код, який і використовується при виконанні збірки.

Текст програми містить коментарі. У мові C# використовуються однострокові // та багатострокові /*  */ коментарі. Крім того, можна використовувати XML-коментарі для докуметовання коду.

Слайд 2: Простори імен

namespace DemoApp

{

   class m1{};

   namespace MyClasses

   {

       class m2{};

   }

}

namespace DemoApp.MyClasses

{   

   class m3{};

}

Простори імен групують разом класи та структури, що обмежує їх область дії і дозволяє уникнути конфлікту імен з іншими класами та структурами.

Простори імен можуть бути вкладеними. В обох наведених вище прикладах задекларовано простір імен MyClasses в середені простору імен DemoApp. Обидві декларації правильні, означають одне й те саме, і можуть існувати у межах одного вихідного файлу.

Повні імена класів у цьому прикладі:

DemoApp.m1

DemoApp.MyClasses.m2

DemoApp.MyClasses.m3

Засобом навігації серед множин класів у просторах імен є оператор:

using <Ім’яПросторуІмен>;

Слайд 3: Різні класифікації типів даних

Типи даних прийнято розділяти на прості і складні в залежності від того, як влаштовані їх дані. У простих (скалярних) типів можливі значення даних єдині і неподільні. Складні типи характеризуються способом структуризації даних: одне значення складного типу складається з множини значень даних, які організовують складний тип.

Крім того, типи поділяються на вбудовані типи і типи, визначені користувачем (програмістом). Вбудовані типи споконвічно належать мові програмування і складають її базис. В основі системи типів будь-якої мови програмування завжди лежить базисна система типів, вбудованих в мову. На основі вбудованих типів програміст може будувати власні, визначені ним типи даних. Але способи (правила) створення таких типів є базисними, вбудованими в мову.

Типи даних розділяються також на статичні і динамічні типи. Для даних статичного типу пам'ять відводиться в момент оголошення, необхідний розмір даних відомий при їх оголошенні. Для даних динамічного типу розмір даних в момент оголошення зазвичай не відомий і пам'ять їм виділяється динамічно за запитом в процесі виконання програми.

Ще одна важлива класифікація типів – це їх поділ на типи-значеня і типи-посилання. Для типів-значень значення змінної (об'єкта) є невід'ємною власністю змінної (точніше власністю є пам'ять, відведена значенням, а саме значення може змінюватися). Для типів-посилнь значенням є посилання на деякий об'єкт в пам'яті, розташований зазвичай у динамічній пам'яті – купі. Об'єкт, на який вказує посилання, може бути таким, що розділяється. Це означає, що кілька змінних типу-посилння можуть вказувати на один і той же об'єкт і розділяти його значення. Тип-значення прийнято називати розгорнутим, підкреслюючи, що значення об'єкта розгорнуто безпосередньо в пам'яті, що відводиться об'єкту.

Для більшості процедурних мов, реально використовуваних програмістами, – Паскаль, C++, Java, Visual Basic, C#, система вбудованих типів влаштована більш-менш однаково: завжди в мові присутні арифметичний, логічний (булевий), символьний типи. Арифметичний тип завжди розбивається на підтипи. Завжди допускається організація даних у вигляді масивів і записів (структур). Усередині арифметичного типу завжди допускаються перетворення, завжди є функції, що перетворюють рядок в число і навнаки. Тому знання, принаймні, однієї з процедурних мов, дозволяє побудувати загальну картину системи типів і для мови C#. Відмінності будуть лише у нюансах.

Оскільки мова C# є безпосереднім нащадком мови C++, то і системи типів цих двох мов близькі і збігаються аж до назви типів і областей їх визначення. Але відмінності, в тому числі принципового характеру, є і тут.

Система типів C#. Як зазначалося на попередній лекції, система типів C# підтримує дві категорії типів, кожна з яких розділена на підкатегорії: типи-значення () і типи-посилання (). Схема типів наведена нижче.

У мові C# жорстко визначено, які типи є типапи-посиланнями, а які – типами-значенннями. Типи-значення: логічний, арифметичний, структури, перерахування. Масиви, рядки і класи відносяться до типів-посилань. На перший погляд, така класифікація може викликати деяке здивування, чому це структури, які в C++ близькі до класів, відносяться до типів-значень, а масиви і рядки до типів-посилань. Однак у C# масиви розглядаються як динамічні, їх розмір може визначатися на етапі обчислень, а не в момент трансляції. Рядки в C# також розглядаються як динамічні змінні, довжина яких може змінюватися. Тому рядки і масиви відносяться до типів-посилань, що вимагає розподілу пам'яті в купі.

Зі структурами справа складніше. Структури C# представляють окремий випадок класу. Оголосивши свій клас як структуру, програміст отримує можливість віднести клас до типів-значень, що іноді буває вкрай корисно. Правда, це не повноцінний засіб, оскільки на структури накладаються додаткові обмеження в порівнянні із звичайними класами.

Розглянемо класифікацію, згідно якої всі типи діляться на вбудовані і визначені користувачем. Всі вбудовані типи C# однозначно відображаються, а фактично збігаються з системними типами каркаса .Net Framework, розміщеними в просторі імен System. Тому всюди, де можна використовувати ім'я типу, наприклад, int, з тим же успіхом можна використовувати ім'я – System.Int32.

Всі типи, за винятком простих типів, можуть визначатися програмістом. Всі інші типи (похідні типи) вимагають попереднього оголошення.

Прості (елементарні) типи  це типи, імена та основні властивості яких відомі компілятору. Щодо вбудованих типів компілятору не потрібно ніякої додаткової інформації. Він підтримує ці типи самостійно. Серед простих типів розрізняють:

  •  цілочисельні
  •  з плаваючою точкою;
  •  DECIMAL;
  •  булевий.

Для позначення простих (елементарних) типів в C# використовується псевдоніми. Деякі характеристики типів відображені у наступній таблиці 1.

Таблиця 1. Вбудовані типи C#

Назва

Ключове слово

Тип .NET

Діапазон значень

Опис

Розмір, бітів

Логічний тип

bool

Boolean

true, false

Цілі типи

sbyte

SByte

від –128 до 127

Зі знаком

8

byte

Byte

від  0 до 255

Без знака

8

short

Int16

від  –32768 до 32767

Зі знаком

16

ushort

UInt16

від  0 до 65535

Без знака

16

int

Int32

від –2 × 109 до 2 × 109

Зі знаком

32

uint

UInt32

від 0 до 4 × 109

Без знака

32

long

Int64

від  –9 × 1018 до 9 × 1018

Зі знаком

64

ulong

UInt64

від 0 до 18 × 1018

Без знака

64

Символьний тип

char

Char

від U+0000 до U+ffff

Unicode-символ

16

Дійсні числа

float

Single

від 1.5 × 10-45 до 3.4 × 1038

7 цифр

32

double

Double

від 5.0 × 10-324 до 1.7 × 10308

15–16 цифр

64

Фінансовий тип

decimal

Decimal

від 1.0 × 10-28 до 7.9 × 1028

28–29 цифр

128

Рядки

string

String

Довжина обмежена об'ємом доступної пам'яті

Рядок із Unicode-символів

Тип object

object

Object

Можна зберігати все, що завгодно

Загальний предок

Примітка

Дійсні типи і фінансовий тип є знаковими. Для них у стовпчику "діапазон значень" наведені абсолютні величини допустимих значень.

Логічний або булевий, тип містить всього два значення: true (істина) і false (не істина).

Всі цілі і дійсні типи разом з символьним і фінансовим можна назвати арифметичними типами.

Внутрішнє представлення величини цілого типу — ціле число в двійковому коді. У знакових типах старший біт числа інтерпретується як знак (0 - позитивне число, 1 -  негативне).

Дійсні типи, або типи даних, з плаваючою крапкою зберігаються в пам'яті комп'ютера інакше, ніж цілі. Внутрішнє представлення дійсного числа складається з двох частин – мантиси і порядку, причому кожна частина має знак. Довжина мантиси визначає точність числа, а довжина порядку – його діапазон. Всі дійсні типи можуть представляти як додатні, так і від'ємні числа. Найчастіше в програмах використовується тип double, оскільки його діапазон і точність покривають більшість потреб.

Тип decimal призначений для грошових обчислень, в яких критичні помилки округлення. Величини типа decimal дозволяють зберігати 28–29 десяткових розрядів. Тип decimal не відноситься до дійсних типів, у них різне внутрішнє представлення. Величини грошового типа навіть не можна використовувати в одному виразі з дійсними без явного перетворення типа.

Будь-який вбудований тип C# відповідає стандартному класу бібліотеки .NET, визначеному в просторі імен System.

Базовий клас System.Object. У мові C# згладжено розходження між типом та класом. Всі типи – вбудовані та користувацькі – одночасно є класами, пов'язаними відношенням успадкування. Батьківським, базовим класом є клас System.Object. Всі інші типи чи, точніше, класи є його нащадками, що успадковують методи цього класу. У класа object є чотири наслідуваних методу:

  1.  bool Equals(object obj) – перевіряє еквівалентність поточного об'єкта та об'єкта, переданого в якості аргументу;
  2.  System.Type GetType() – повертає системний тип поточного об'єкта;
  3.  string ToString() – повертає рядок, пов'язаний з об'єктом. Для арифметичних типів повертається значення, перетворене в рядок;
  4.  int GetHashCode() – служить, як хеш-функція у відповідних алгоритмах пошуку по ключу при зберіганні даних в хеш-таблицях.

Природно, що всі вбудовані типи потрібним чином перевизначають методи батька і додають власні методи і властивості. Враховуючи, що і типи, створювані користувачем, також є нащадками класу object, то для них необхідно перевизначити методи батька, якщо передбачається використання цих методів, а реалізація батька, що надається за промовчанням, не забезпечує потрібного ефекту.

Перейдемо тепер до прикладів, на яких будемо пояснювати подальші питання, пов'язані з типами і класами, змінними та об'єктами. Почнемо з цілком коректного в мові C # прикладу оголошення змінних і присвоювання їм значень.

Змінні простих типів та їх ініціалізація

Змінна — це іменована область пам'яті, призначена для зберігання даних певного типу. Під час виконання програми значення змінної можна змінювати.

Мова C# є строго типізованою мовою з чітким контролем типів даних. Усі змінні повинні бути визначені до їх першого використання.

При описі для кожної змінної задаються її ім'я і тип.

Визначення змінних простих типів (вбудованих типів-значень) має наступний загальний синтаксис:

Тип_змінної  им’я_змінної [=значення];

Ім'я змінної служить для звернення до області пам'яті, в якій зберігається значення змінної. Ім'я дає програміст. Тип змінної вибирається, виходячи з діапазону і необхідної точності представлення даних. При оголошенні слід присвоїти змінній деяке початкове значення, тобто ініціалізувати її, наприклад:

           int b = 1, а = 100;

           int c = b * а + 25;

           float x = 0.1f;

           string s = "Hello, world!";

           int z;

           z = 100;

           int a, b = 1;

           float x = 0.1f, y = 0.1f;

           long p = 100;

           long q = 100 * p;

Рекомендується завжди ініціалізувати змінні при описі. При ініціалізації можна використовувати не лише константу, але і вираз — головне, щоб на момент опису воно було обчислюваним.

Програма на C# складається з класів, усередині яких описують методи та дані. Змінні, описані безпосередньо усередині класу, називаються полями класу. Їм автоматично призначається так зване "значення за промовчанням" — як правило, це 0 відповідного типу. Змінні, описані усередині методу класу, називаються локальними змінними. Їх ініціалізація покладається на програміста.

У C # також існує ще одне важливе обмеження на використання об'єктів типів-значень: необхідною умовою застосування цих об'єктів є їх явна ініціалізація.

Іменовані константи. Можна заборонити змінювати значення змінної, задавши при її описі ключове слово const, наприклад:

           const double pi = 3.14159265358979323846264338327950;

Такі величини називають іменованими константами, або просто константами. Вони застосовуються для того, щоб замість значень констант можна було використовувати в програмі їх імена. Це робить програму зрозумілішою і полегшує внесення до неї змін. Іменовані константи повинні обов'язково ініціалізуватися при описі.

Область дії змінної в C# – блок коду ({}). Змінна створюється при вході в область видимості і знищується при виході з неї.

Область дії змінної, тобто область програми, де можна використовувати змінну, починається в точці її опису і триває до кінця блоку, усередині якого вона описана.

Блок — це код, взятий у фігурні дужки. Основне призначення блоку — угрупування операторів. У C# будь-яка змінна описана усередині якого-небудь блоку: класу, методу або блоку усередині методу. Ім'я змінної має бути унікальним в області її дії. Область дії поширюється на вкладені в метод блоки.

Увага

Змінні створюються при вході в блок і знищуються при виході. Це означає, що після виходу з блоку значення змінної не зберігається. При повторному вході в цей же блок змінна створюється заново.

Операції та вирази

  •  Вираз – правило обчислення значення.
  •  У виразі беруть участь операнди, об'єднані знаками операцій.
  •  Операндами виразу можуть бути константи, змінні і виклики функцій.
  •  Операції виконуються відповідно до пріоритетів.
  •  Для зміни порядку виконання операцій використовуються круглі дужки.
  •  Результатом виразу завжди є значення певного типу, який визначається типами операндів.
  •  Величини, що беруть участь у вираженні, повинні бути сумісних типів.

Таблиця 2. Операції C#

Категорія

Знак операції

Назва

Первинні

Доступ до елементу

x()

Виклик методу або делегата

x[]

Доступ до елементу

x++

Постфіксний інкремент

x--

Постфіксний декремент

new

Виділення пам'яті

typeof 

Отримання типу

checked

Код, що перевіряється 

unchecked

Код, що не перевіряється

Унарні

+

Унарний плюс

-

Унарний мінус (арифметичне заперечення)

!

Логічне заперечення

?

Порозрядне заперечення

++x

Префіксний інкремент

--x

Префіксний декремент

(тип)x

Перетворення типу

Мультиплікативні

*

Множення

/

Ділення

%

Залишок від ділення

Додавання/віднімання

+

Додавання

-

Віднімання

Зсув

<<

Зсув вліво

>>

Зсув вправо

Відношення і перевірка типу

<

Менше

>

Більше

<=

Менше або рівно

>=

Більше або рівно

is

Перевірка належності до типу

as

Приведення типа

Перевірки на рівність

==

Рівно

!=

Не рівно

Порозрядні логічні

&

Порозрядна кон'юнкція (І)

Порозрядне АБО

|

Порозрядна диз'юнкція (АБО)

Умовні логічні

&&

Логічне І

||

Логічне АБО

Умовна

? :

Умовна операція

Призначення

=

Призначення

*=

Множення з призначенням

/=

Ділення з призначенням

%=

Залишок відділення з призначенням

+=

Складання з призначенням

–=

Віднімання з призначенням

<<=

Зсув вліво з призначенням

>>=

Зсув вправо з призначенням

&=

Порозрядне І з призначенням

=

порозрядне виключаюче  АБО з призначенням

|=

Порозрядне АБО з призначенням

Якщо операнди, що входять у вираз, одного типу, і операція для цього типу визначена, то результат виразу буде мати той же тип.

Якщо операнди різного типу і (або) операція для цього типу не визначена, перед обчисленнями автоматично виконується перетворення типу за правилами, що забезпечує приведення більш коротких типів до більш довгим для збереження значущості і точності.

Автоматичне (неявне) перетворення можливе не завжди, а тільки якщо при цьому не може трапитися втрата значущості.

Якщо неявного перетворення з одного типу в інший не існує, програміст може задати явне перетворення типу за допомогою операції (тип) х.

           int i = 10;

           double d = i; // неявне перетворення

           

           d = 3.5;

           i = (int) d;  // явне перетворення або "cast"

Перетворення вбудованих арифметичних типів-значень

Розрізняють розширююче та звужуюче перетворення.

Розширююче перетворення – значення одного типу приводиться до значення іншого типу, яке має такий самий або більший розмір. Наприклад, значення, представлене у вигляді 32-розрядного цілого числа із знаком, може бути перетворено в 64-розрядне ціле число із знаком. Таке перетворення вважається безпечним, оскільки початкова інформація при такому перетворенні не спотворюється.

           int  i = 874650375;

           long j = i;

Можливі варіанти перетворення типів наведені на схемі (див. таблицю нижче).

Byte

UInt16, Int16, UInt32, Int32, UInt64, Int64, Single, Double, Decimal

SByte

Int16, Int32, Int64, Single, Double, Decimal

Int16

Int32, Int64, Single, Double, Decimal

UInt16

UInt32, Int32, UInt64, Int64, Single, Double, Decimal

Char

UInt16, UInt32, Int32, UInt64, Int64, Single, Double, Decimal

Int32

Int64, Double, Decimal

UInt32

Int64, Double, Decimal

Int64

Decimal

UInt64

Decimal

Single

Double

Всі арифметичні класи, у тому числі клас int, мають перегружений статичний метод Parse, в якого першим обов'язковим параметром є рядок, що задає значення відповідного арифметичного типу в локалізованій формі. Форматом рядка і стилем її представлення можна управляти за допомогою інших параметрів методу Parse.

Звужуюче перетворення – значення одного типу перетвориться до значення іншого типу, яке має менший розмір (з 64-розрядного у 32-розрядне). Таке перетворення потенційно небезпечно втратою значення.

           int a = -1;

           byte b = (byte) a;

           double d = 3.14;

           float f  = (float) d;

Звужуючі перетворення можуть приводити до втрати інформації. Якщо тип, до якого здійснюється перетворення, не може правильно передати значення джерела, то результат перетворення виявляється рівний константі PositiveInfinity або NegativeInfinity. При цьому значення PositiveInfinity інтерпретується як результат ділення позитивного числа на нуль, а значення NegativeInfinity інтерпретується як результат ділення негативного числа на нуль.

Якщо звужуюче перетворення забезпечується методами класу System.Convert  то втрата інформації супроводиться генерацією виключної ситуації.

Система Common Type System середовища Microsoft .NET забезпечує безпечну типізацію, тобто гарантує відсутність побічних ефектів (переповнення оперативної пам'яті комп'ютера, некоректне перетворення типів тощо).

Перетворення з рядкового типу в арифметичний. Коли користувач вводить дані різних типів (з консолі чи форми), то він задає ці дані як рядки тексту. Дані строкового типу потребують явного перетворення до арифметичного типу. Класи бібліотеки FCL надають два способи явного виконання таких перетворень:

  •  Метод Parse;
  •  Методи класу Convert.

Метод Parse. Всі скалярні типи (арифметичний, логічний, символьний) мають статичний метод Parse, аргументом якого є рядок, а результатом об'єкт відповідного типу.

Розглянемо приклад перетворення даних з використанням методу Parse.

           string str1 = "100";

           string str2 = "3.14";

           // Перетворення рядкового типу в арифметичний методом Parse

           int    a = int.Parse(str1);

           double pi = double.Parse(str2);

Перетворення з арифметичного типу у тип string. Перетворення в тип string завжди визначені, оскільки всі типи є нащадками базового класу object і успадковують метод ToString().

Для всіх підтипів арифметичного типу метод ToString() повертає рядок, який задає відповідне значення арифметичного типа. Метод ToString завжди потрібно викликати явно. Його можна опускати при виконанні операції конкатенації. Якщо один з операндів операції «+» є рядком, то операція сприймається як конкатенація рядків і другий операнд неявно перетвориться до цього типу.  Ось відповідний приклад:

           string name = "Василь Iванов";

           int age = 20;

           double salary = 2700;

           string s = "Iм'я: " + name +

               ". Вiк: " + age.ToString() +

               ". Зарплатня: " + salary;

           Console.WriteLine(s);

Тут для змінної age метод був викликаний явно, а для змінної salary він викликається автоматично.

Клас Convert та його методи. Для перетворень усередині арифметичного типа можна використовувати кастинг - приведення типа. Для перетворень строкового типа в скалярний тип можна використовувати метод Parse,  а у зворотний бік – метод ToString.

У всіх ситуаціях, коли потрібно виконати перетворення з одного базового вбудованого типа в інший базовий тип, можна використовувати методи класу Convert бібліотеки FCL, вбудованого в простір імен System, - універсального класу, статичні методи якого спеціально спроектовані для виконання перетворень.

Серед інших методів класу Convert є загальний статичний метод ChangeType, що дозволяє перетворення об'єкту до деякого заданого типа. Існує також можливість перетворення у системний тип DateTime, який хоча і не є базисним типом мови C#, але допустимий в програмах, як і будь-який інший системний тип.

Методи класу Convert підтримують загальний спосіб виконання перетворень між типами. Клас Convert містить 15 статичних методів вигляду To<Type> (ToBoolean(),.ToUInt64()), де Type може набувати значень від Boolean до UInt64 для всіх вбудованих типів. Єдиним виключенням є тип object, – методу ToObject немає із зрозумілих причин, оскільки для всіх типів існує неявне перетворення до типа object.

          // Тестування методів класу Convert

           char sym = '7';

           string s = Convert.ToString(sym);

           double x = Convert.ToDouble(s);

           int    n = Convert.ToInt32(x);

           byte   b = Convert.ToByte(n);

           bool   flag = Convert.ToBoolean(b);

           x = Convert.ToDouble(flag);

           s = Convert.ToString(flag);

           s = "300";

           n = Convert.ToInt32(s);

           s = "14.09";

           s = "14.09.2008";

           DateTime dt = Convert.ToDateTime(s);   

Цей приклад демонструє різні перетворення між типами. Всі ці перетворення виконуються явно з використанням методів класу Convert. Спочатку дані символьного типа перетворюються в рядок. Потім ці дані перетворюються в дійсний тип, потім проводяться перетворення усередині арифметичного типа з пониженням типа від double до byte. Перетворенням, що завершує приклад, є перетворення даних строкового типа до типа DateTime.

Оператори мови C#

Базові конструкції структурного програмування

Структурне програмування — це технологія створення програм, що дозволяє шляхом дотримання певних правил скоротити час розробки і зменшити кількість помилок, а також полегшити можливість модифікації програми.

У C# ідеї структурного програмування використовуються на найнижчому рівні — при написанні методів об'єктів. Доведено, що будь-який алгоритм можна реалізувати лише з трьох структур, які називаються базовими конструкціями структурного програмування: це послідовність, розгалуження і цикл.

Послідовністю називається конструкція, що реалізовує послідовне виконання двох або більше операторів (простих або складних).

Розгалуження задає виконання того чи іншого оператора залежно від виконання якої-небудь умови. Реалізується за допомогою операторів if та switch.

Цикл реалізує багатократне виконання операторів.  Реалізується за допомогою операторів циклу. В C# є 4 типи операторів циклу: while, do, for, foreach.

Блок (складений оператор)

Блок — це послідовність операторів, що розміщується всередині операторних дужок:

{          }

Блок сприймається компілятором як один оператор і може використовуватися скрізь, де синтаксис вимагає одного оператора, а алгоритм – декількох.

Блок може містити один оператор або бути порожнім.

Умовний оператор if використовується для розгалуження процесу обчислень на два напрями. Формат оператора:

if (логічна умова) оператор1

[else оператор2]

Спочатку обчислюється логічна умова. Якщо вона має значення true, виконується перший оператор, інакше — другий. Після цього управління передається на оператор, який слідує за умовним оператором if. Гілка else може бути відсутньою.

Якщо в якій-небудь гілці потрібно виконати декілька операторів, їх необхідно укласти в блок. Блок може містити будь-які оператори, у тому числі описи інших умовних операторів, але не може складатися з одних описів.

if (a>b)

  Console.WriteLine(“a>b”);

else

 Console.WriteLine(“a<=b”);

Логічна умова може бути складною, наприклад:

if ( a < b && ( a > d || a == 0 ) ) b++; else { b *= a; a = 0; }     

Оператори if можуть бути вкладеними один в одний.

if(умова_1) {оператор_1}

else if(умова_2) {оператор_2}

...

else if(умова_K){ оператор_K}

else {оператор_N}

Для зрозумілості програми не рекомендується використовувати більше 3 вкладень if.

Оператор switch (перемикач) – альтернатива вкладеним операторам if. Формат оператора:

switch (вираз)

{

  case константний_выраз_1:

       [оператори_1 оператор_переходу_1]

  ...

  case  константний_выраз _K:

      [оператори_K оператор_переходу_K]

  [default: оператори_N оператор_переходу_N]

}

Виконання оператора починається з обчислення виразу. Тип виразу найчастіше цілочисельний (включаючи char) або строковий (string). Потім управління передається першому оператору із списку, поміченому константним виразом, значення якого збіглося з обчисленим. Якщо збігу не сталося, виконуються оператори, розташовані після слова default, а при його відсутності управління передається наступному за switch оператору.

Кожна гілка перемикача повинна закінчуватися явним оператором переходу, а саме одним з операторів break, goto або return:

  •  оператор break виконує вихід з самого внутрішнього з охоплюючих його операторів switch, for, while і do;
  •  оператор goto виконує перехід на вказану після нього мітку, звичайно це мітка case однієї з гілок оператора switch, що пролягають нижче;
  •  оператор return виконує вихід з функції, в тілі якої він записаний.

Частіше за все використовується оператор break.

Приклад: консольний калькулятор на 4 дії (див. слайд).

Оператори циклу

Оператори циклу використовуються для обчислень, що повторюються багато разів. Блок, для виконання якого організовується цикл, називається тілом циклу. Решта операторів використовуються для управління процесом повторення обчислень: це початкові установки, перевірка умови продовження циклу і модифікація параметра циклу. Один прохід циклу називається ітерацією.

В усіх мовах програмування є два типи циклів: з передумовою і з пост-умовою. Також є цикл з параметром (for).

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

Перевірка умови продовження циклу виконується на кожній ітерації або до тіла циклу (тоді говорять про цикл з передумовою), або після тіла циклу (цикл з пост-умовою).

Параметром циклу називається змінна, яка використовується при перевірці умови продовження циклу і примусово змінюється на кожній ітерації, причому, як правило, на одну і ту саму величину. Якщо параметр циклу цілочисельний, він називається лічильником циклу.

Цикл завершується, якщо умова його продовження не виконується. Можливе примусове завершення як поточної ітерації, так і циклу в цілому. Для цього служать оператори break, continue, return та goto. Передавати управління ззовні всередину циклу забороняється.

В С# для організації циклів використовуються чотири типи циклів: for, while, do, foreach. Всі цикли крім foreach успадковані від С++ і мають той самий синтаксис.

Умова в операторі while перевіряється до входження в цикл. Це гарантує, що цикл не буде виконуватися, якщо умова зразу має значення false.

Приклад. Нижче наведено програму, яка виводить для аргументу х, що змінюється в заданих границях із заданим кроком, таблицю значень наступної функції:

Назвемо початкове значення аргументу Xn, кінцеве значення аргументу — Xk, крок зміни аргументу — dX і параметр t. Всі величини дійсні числа (double). Програма повинна виводити таблицю, що складається з двох стовпців: значень аргументу і відповідних ним значень функції.

namespace ConsoleApplication1

{

   class Program

   {

       static void Main(string[] args)

       {

           double Xn = -2, Xk = 12, dX = 2, t = 2, y;

           Console.WriteLine("|   x    |    y   |"); // заголовок таблиці

           double x = Xn;

           while (x <= Xk)

           {

               y = t;

               if (x >= 0 && x < 10) y = t * x;

               if (x >= 10) y = 2 * t;

               Console.WriteLine("| {0,6} | {1,6} |", x, y);

               x += dX;

           }

           Console.ReadKey();

       }}}

Цикл з пост-умовою dowhile 

Синтаксис циклу do

do

{  список операторів }

while(умова);

Оператори у тілі циклу виконуються до тип пір, поки умова має значення true.

Умова в операторі while перевіряється після ітерації циклу. В цьому циклі завжди виконується хоча б одна ітерація.

Цей тип циклу застосовується в тих випадках, коли тіло циклу необхідно обов'язково виконати хоч б один раз (див. на слайді приклад Купи слоника, а?”).

Цикл з перебором for. Синтаксис оператора:

for (ініціалізатор; умова; список_виразів)

{ оператори}

Ініціалізація використовується для оголошення змінних, які використовуються в циклі, і призначення їм початкових значень. У цій частині можна записати декілька операторів, розділених комою, наприклад:

for ( int i = 0, j = 20; ...

int k, m;

for (k = 1, m = 0; ...

Областю дії змінних, оголошених в частині ініціалізації циклу, є цикл. Ініціалізація виконується один раз на початку виконання циклу.

Вираз типу bool визначає умову виконання циклу: якщо його результат рівний true, цикл виконується.

Модифікації виконуються після кожної ітерації циклу і служать для зміни параметрів циклу. У частині модифікацій можна записати декілька операторів через кому, наприклад:

for ( int i = 0, j = 20; i < 5 && j > 10; i++, j-- ) ...

Простий або складений оператор є тілом циклу. Будь-яка з частин оператора for може бути опущена (але крапки з комою треба залишити на своїх місцях!).

Обчислення суми чисел від 1 до 100:

int s = 0;

for ( int i = 1; i <= 100; i++ )

      s += i;

Обчислення ступеню n числа,  xn (для n>0)

static public double Power(double x, int n)

{

   double z=1;

   for (int i=1;n>=i;i++)

    {

       z = z*x;

    }

   return z;

}

Цикл перебору foreach. Новим видом циклу, не успадкованим від С++, є цикл foreach, зручний при роботі з масивами, колекціями та іншими подібними контейнерами даних.

Синтаксис циклу foreach :

foreach(тип ідентифікатор in контейнер)

{оператори}

Тіло циклу виконується для кожного елемента в контейнері. Тип ідентифікатора повинен бути узгоджений з типом елементів, що зберігаються в контейнері даних.

 Оператори переходу

У С# є п'ять операторів, що змінюють природний порядок виконання обчислень:

  •  оператор безумовного переходу goto;
  •  оператор виходу з циклу break;
  •  оператор переходу до наступної ітерації циклу continue;
  •  оператор повернення з функції return;
  •  оператор генерації виключення throw.

Ці оператори можуть передати управління в межах блоку, в якому вони використані, і за його межі. Передавати управління всередину іншого блоку забороняється.

Оператор goto. Оператор безумовного переходу goto використовується в одній з трьох форм:

goto мітка;

goto case константний_вираз;

goto default;

У тілі функції має бути присутня тільки одна конструкція вигляду:

мітка: оператор;

Оператор goto мітка передає управління на помічений оператор. Мітка – це звичайний ідентифікатор, зоною видимості якого є функція, в тілі якої він заданий. Мітка повинна знаходитися в тій же зоні видимості, що і оператор переходу.

Друга і третя форми оператора goto використовуються в тілі оператора вибору switch. Оператор goto case константний_вираз передає управління на відповідну константному виразу гілку, а оператор goto default — на гілку default.

Оператор break використовується усередині операторів циклу або вибору для переходу в точку програми, що знаходиться безпосередньо за оператором, усередині якого знаходиться оператор break.

Оператор continue. Оператор переходу до наступної ітерації поточного циклу continue пропускає всі оператори тіла циклу, що залишилися до кінця, і передає управління на початок наступної ітерації.

Оператор return. Оператор повернення з функції return завершує виконання функції і передає управління в точку її виклику. Синтаксис оператора:

return [ вираз ];

Тип виразу повинен мати неявне перетворення до типу функції. Якщо тип значення, який повертає функція описаний як void, вираз має бути відсутнім.

Стандартні класи С#. Робота з рядками

Клас String та його методи. Тип string, призначений для роботи з рядками символів в кодуванні Unicode, є вбудованим посилковим типом C#. Йому відповідає базовий клас System.String бібліотеки .NET.

Створити рядок можна декількома способами:

string s;                               // відкладена ініціалізація

string t = "qqq";                  // ініціалізація строковим літералом

string u = new string(' ', 20); // конструктор створює рядок з 20 пробілів

char[] а = { '0', '0', '0' };        // масив для ініціалізації рядка

string v = new string( а );     // створення з масиву символів

Для рядків визначені наступні операції:

  •  призначення (=);
  •  перевірка на рівність (==);
  •  перевірка на нерівність (!=);
  •  звернення по індексу ([]);
  •  конкатенація рядків (+).

Не дивлячись на те, що рядки є посилковим типом даних, на рівність і нерівність перевіряються не посилання, а значення рядків. Рядки рівні, якщо мають однакову кількість символів і збігаються посимвольно. Крім того, оператор "+" об'єкту string перевизначений тому при його використанні застосовується метод Concat().

Звертатися до окремого елементу рядка за індексом можна лише для отримання значення, але не для його зміни. Це пов'язано з тим, що рядки типу string відносяться до так званих незмінних типів даних. Методи, що змінюють вміст рядка, насправді створюють нову копію рядка. Невживані "старі" копії автоматично видаляються при збірці сміття.

В базовому класі System.String реалізовано багато різних методів, що виконують операції над рядками. Основні властивості і методи класу String перелічені у табл.

Таблиця. Деякі властивості і методи класу System.String

Length

Властивість. Дозволяє отримати кількість символів у рядку.

Concat()

Дозволяє з'єднати декілька рядків або змінних типу object.

CompareTo()

Дозволяє порівняти два рядки. В разі рівності рядків результат виконання функції дорівнює нулю. При позитивному значенні функції більшим є рядок, для якого викликався метод.

Copy()

Створює нову копію існуючого рядка.

Format()

Застосовується для форматування рядка з використанням різних примітивів (рядків і числових даних) і підстановочних виразів вигляду {0}.

Insert()

Дозволяє вставити один рядок всередину існуючого.

Remove()

Replace()

Видаляють або замінюють символи в рядку.

ToUpper()

ToLower()

Перетворюють всі символи рядка в строкові або прописні.

Chars

Дозволяє отримати символ, що знаходиться в певній позиції рядка.

Join()

Створює рядок, сполучаючи задані рядки і розділяючи їх рядком-роздільником.

Replace()

Замінює один символ рядка іншим.

Split()

Повертає масив рядків з елементами - підрядками основного рядка, між якими знаходяться символи-роздільники.

Substring()

Дозволяє отримати підрядок основного рядка, заданої довжини, що починається з певного символу.

Trim()

Видаляє пропуски або набір заданих символів на початку і кінці основного рядка.

ToCharArray()

Створює масив символів і вставляє в нього символи початкового рядка.

Форматування рядків

У операторі 4 цього прикладу неявно застосовується метод Format, який замінює всі входження параметрів у фігурних дужках значеннями відповідних змінних із списку виводу. Після номера параметра можна задати мінімальну ширину поля виводу, а також вказати специфікатор формату, який визначає форму представлення значення, що виводиться.

У загальному вигляді параметр задається таким чином:

{n [,m[:спецификатор_формата]]}

Тут n — номер параметра. Параметри нумеруються з нуля, нульовий параметр замінюється значенням першої змінної із списку виводу, перший параметр — другою змінною, і так далі Параметр m визначає мінімальну ширину поля, яке відводиться під значення, що виводиться. Якщо числу, що виводиться, досить меншої кількості позицій, невживані позиції заповнюються пробілами. Якщо числу потрібно більше позицій, параметр ігнорується.

Специфікатор формату визначає формат виведення значення. Наприклад, специфікатор C (Currency) означає, що параметр повинен форматуватися як валюта з урахуванням національних особливостей представлення, а специфікатор Х (Hexadecimal) задає шістнадцяткову форму представлення значення, що виводиться.

Досить часто при роботі з рядками виникає необхідність розділити рядок на підрядки, відокремлені один від одного заданими символами-роздільниками. Виділення лексем використовується в задачах лексичного аналізу в усіх компіляторах. У наступному прикладі задається рядок символів, в якому є декілька символів-роздільників. За допомогою функції Split рядок розділяється на підрядки, які потім виводяться на екран кожний в окремому рядку. Для завдання символів-роздільників використовується масив символів. В цьому прикладі також застосовується функція Trim, необхідна для того, щоб переконатися в тому, що заданий рядок не складається з одних лише пробілів.

static void Main(string[] args)

       {

         string words = "рядок, що містить декілька слів, а також знаки пунктуації: такі як двокрапка і крапка.";

         string [] split = words.Split(new Char [] {' ', ',', '.', ':'});

         foreach (string s in split)

         {

          if (s.Trim() != "")

          Console.WriteLine(s);

         }

         Console.ReadKey();

       }

Клас StringBuilder та його методи

Іноді слід уникати ситуацій, коли в результаті виконання операції створюється новий рядок, оскільки це пов'язано з додатковими витратами пам'яті та інших ресурсів комп'ютера при виконанні операції.

C# містить спеціальний клас StringBuilder, використовуючи який можна уникнути створення копій рядків при їх обробці. Всі зміни, що вносяться до об'єкту даного класу, негайно відображаються в ньому, що ефективніше, ніж робота з копіями рядка.

Основною операцією, яка найчастіше використовується класом StringBuilder, є операція додавання до рядка вмісту. Для цього існує метод Append. Наступний код додає один рядок до іншого і виводить результат на консоль. При цьому змінюється оригінал рядка, копія не створюється:

StringBuilder sb = new StringBuilder("Наступного тижня у нас кредит");

sb.Append(", потрібно захистити лаб.роботи");

Сonsole.Write(sb);

Окрім додавання клас StringBuilder містить інші методи, найбільш значимі з яких наведені нижче. Після того, як усі необхідні дії, пов'язані з обробкою рядка, були виконані, необхідно викликати метод ToString() для перетворення вмісту об'єкту в звичайний тип даних string.

Таблиця 5.3. Деякі методи класу StringBuilder

Append

Додавання заданого рядка в кінець рядка об'єкту.

AppendFormat

Додавання заданого форматованого рядка (рядка, що містить управляючі символи) в кінець рядка об'єкту.

CopyTo

Копіювання символів заданого сегменту рядка в задані комірки масиву символів.

Insert

Додавання рядка в задану позицію рядка об'єкту.

Remove

Видалення заданої кількості символів з рядка об'єкту

Replace

Заміна заданого символу або рядка об'єкту на інший заданий символ або рядок.

При інтенсивній роботі з рядками рекомендується використовувати клас StringBuilder, оскільки це дозволяє зменшити накладні витрати, пов'язані із створенням копії рядка при виконанні кожної операції.

Масиви і стандартні класи мови C#

Масив — це обмежена сукупність однотипних величин. Елементи масиву мають одне і те саме ім'я, а розрізняються за порядковим номером (індексом).

Масиви відносяться до типів-посилань, тобто розташовуються в динамічній області пам'яті (купі), тому створення масиву починається з виділення пам'яті під його елементи. Елементами масиву можуть бути величини як типів-значень, так і типів-посилань (у тому числі масиви), наприклад:

           int[] w = new int[10];          // масив з 10 цілих чисел

           string[] z = new string[100];   // масив зі 100 рядків

Масив типів-значень зберігає значення, масив типу-посилання — посилання на елементи (див. рис. на слайді Розташування масивів у пам’яті). Всім елементам при створенні масиву призначається значення за промовчанням: нулі для типів-значень і null для типів-посилань.

В C# є три види масивів:

• одновимірні масиви;

• прямокутні масиви.

• "зубчасті" (ступінчасті, jagged) масиви.

Розмірність масиву. Кількість елементів у масиві (розмірність) задається при виділенні пам'яті і не може бути змінена згодом. Вона може задаватися виразом:

           short n = 100;

           string[] arrStr = new string[n + 1];

Результат обчислення цього виразу (розмірності) повинен бути невід'ємним, а його тип повинен мати неявне перетворення до int, uint, long або ulong.

Розмірність не є частиною типу масиву.

Елементи масиву нумеруються з нуля. Для звернення до елемента масиву після імені масиву вказується номер елемента в квадратних дужках, наприклад: w[4] або z[i].

З елементом масиву можна робити все, що припустимо для змінних того ж типу.

При роботі з масивом автоматично виконується контроль виходу за його межі: якщо значення індексу виходить за межі масиву, генерується виключення IndexOutOfRangeException.

Дії з масивами. Масиви одного типу можна присвоювати один одному. При цьому відбувається присвоєння посилань, а не елементів:

           int[] a = new int[10];

           int[] b = a;        // Масиви b та a вказують на один і той же масив

Всі інші дії виконуються з елементами масиву окремо:

           for (int i = 0; i < n; ++i) Console.Write("\t" + a[i]);

Одновимірні масиви. Одновимірні масиви використовуються в програмах найчастіше. Варіанти опису масиву:

тип[] ім'я;

тип[] ім'я = new тип [ розмірність ];

тип[] ім'я = { список_ініціалізаторів };

тип[] ім'я = new тип [] { список_ініціалізаторів };

тип[] ім'я = new тип [ розмірність ] { список_ініціалізаторів };

Приклади описів (один приклад на кожен варіант опису):

           int[] a;                                // елементів немає

           int[] b = new int[4];                   // елементи дорівнюють 0

           int[] c = { 61, 2, 5, -9 };             // опертор new мається на увазі

           int[] d = new int[] { 61, 2, 5, -9 };   // розмірність підраховується

           int[] e = new int[4] { 61, 2, 5, -9 };  // надлишковий опис

Тут описано п'ять масивів. Відмінність першого оператора від останніх полягає в тому, що в ньому фактично описано лише посилання на масив, а пам'ять під елементи масиву не виділена.

У кожному з решти масивів по чотири елементи цілого типа. Як видно з операторів 3–5, масив при описі можна ініціалізувати. Якщо при цьому не задана розмірність (оператор 3), кількість елементів обчислюється з кількості вказаних значень. Для полів об'єктів і локальних змінних можна опускати операцію new, вона буде виконана за замовчанням (оператор 2). Якщо присутня і розмірність, і список ініціалізаторів, розмірність має бути константою (оператор 4).

Прямокутні масиви. Прямокутний масив має більше одного виміру. Найчастіше в програмах використовуються двовимірні масиви (матриці). Варіанти опису двовимірного масиву:

тип[,] ім'я;

тип[,] ім'я = new тип [ розм_1, розм_2 ];

тип[,] ім'я = { список_ініціалізаторів };

тип[,] ім'я = new тип [,] { список_ініціалізаторів };

тип[,] ім'я = new тип [ розм_1, розм_2 ] { список_ініціалізаторів };

Приклади описів (один приклад на кожен варіант опису):

     int[,] a;                                             // елементів немає

     int[,] b = new int[2, 3];                             // елементи дорівнюють 0

     int[,] c = { { 1, 2, 3 }, { 4, 5, 6 } };              // опертор new мається на увазі

     int[,] c = new int[,] { { 1, 2, 3 }, { 4, 5, 6 } };   // розмірність підраховується

     int[,] d = new int[2, 3] { { 1, 2, 3 }, { 4, 5, 6 } };// надлишковий опис

До елементу двовимірного масиву звертаються, вказуючи номери рядка і стовпця, на перетині яких він розташований, наприклад: а[1, 4], b[i, j], b[j, i].

Необхідно пам'ятати, що компілятор сприймає у якості номера рядка перший індекс, як би він не був позначений в програмі.

Як приклад розглянемо програму, яка для цілочисельної матриці розміром 3x4 визначає середнє арифметичне її елементів і кількість позитивних елементів в кожному рядку.

Для знаходження середнього арифметичного елементів масиву потрібно знайти їх загальну суму, після чого розділити її на кількість елементів. Порядок перебору елементів масиву (по рядках або по стовпцях) ролі не грає. Знаходження кількості позитивних елементів кожного рядка вимагає перегляду матриці по рядках.

           const int m = 3, n = 4;

           int[,] a = new int[m, n] {

               { 2,-2, 8, 9 },

               {-4,-5, 6,-2 },

               { 7, 0, 1, 1 }

            };

           Console.WriteLine("Початковий масив:");

           for (int i = 0; i < m; ++i)

           {

               for (int j = 0; j < n; ++j) Console.Write("\t" + a[i, j]);

               Console.WriteLine();

           }

           double sum = 0;

           for (int i = 0; i < m; ++i)

               for (int j = 0; j < n; ++j) sum += a[i, j];

           Console.WriteLine("Середнє арифметичне всiх елементiв: "+sum/(m+n));

           Console.ReadKey();

           

Ступінчасті масиви. У ступінчастих масивах кількість елементів в різних рядках може розрізнятися. У пам'яті ступінчастий масив зберігається інакше, ніж прямокутний: у вигляді декількох внутрішніх масивів, кожен з яких має свій розмір. Крім того, виділяється окрема ділянка пам'яті для зберігання посилань на кожен з внутрішніх масивів (рис. 4.1).

Рис. Ступінчастий масив

Приклад ступінчастого масиву

    static void Main(string[] args)

    {

          // Ломаний двовимірний масив з п'яти внутрішніх масивів різного розміру

        int[][] JagArr = new int[10][];

        // Ініціалізація генератора випадкових чисел

        Random rand = new Random();

        // Динамічне створення ломаного масиву

        for (int i = 0; i < JagArr.Length; i++) JagArr[i] = new int[i + rand.Next(10)];

        

        // Виведення рядків на консоль

        // Кожний елемент за промовчанням має значення, що дорівнює 0  

        for (int i = 0; i < 10; i++)

        {

            // Властивість Length масиву повертає його розмір

            Console.Write("Length of row {0} is {1}:\t", i, JagArr[i].Length);

            for (int j = 0; j < JagArr[i].Length; j++) Console.Write(JagArr[i][j] + " ");

            Console.WriteLine();

        }

    }

Клас System.Array. Всі масиви наслідуються від базового класу System.Array. Основні члени (властивості і методи) класу System.Array наведені у таблиці.

Елемент

Вид

Опис

Length

Властивість

Повертає кількість елементів масиву (по всій розмірності)

Rank

Властивість

Повертає кількість вимірювань масиву

BinarySearch

Статичний метод

Двійковий пошук у відсортованому масиві

Clear

Статичний метод

Призначення елементам масиву значень за замовчанням

Copy

Статичний метод

Копіювання заданого діапазону елементів одного масиву в інший

GetValue

Метод

Повертає значення елементу масиву

GetLength

Метод

Повертає розмір і-го вимірювання

IndexOf

Статичний метод

Пошук першого входження елементу в одновимірний масив

Reverse

Статичний метод

Зміна порядку слідування елементів на зворотній

Sort

Статичний метод

Сортування елементів одновимірного масиву

Методи сортування, IndexOf і BinarySearch є статичними, тому до них звертаються через ім'я класу, а не екземпляра, і передають в них ім'я масиву. Двійковий пошук можна застосовувати тільки для впорядкованих масивів. Він виконується набагато швидше, ніж лінійний пошук, реалізований у методі IndexOf. У лістингу пошук елементу, що має значення 0, виконується лише останнім способом.

У наведеному нижче прикладі створюється масив цілих чисел ArInt. У циклі foreach на консоль виводиться кожний елемент масиву. Далі виводиться кількість елементів у масиві, отримана за допомогою властивості масиву Length, та індекс елементу, що дорівнює 0. Потім елементи масиву розташовуються у зворотньму порядку і знову виводяться на екран. Визначається індекс елементу, що дорівнює 0. Після елементи масиву сортуються, виводяться на екран і знову визначається індекс елементу, що дорівнює 0.

    static void Main(string[] args)

    {

        int[] ArInt = { 5, 9, 1, 0, 2, 7, 3, 6, 4, 8 };

        Console.WriteLine("Array contains elements:");

        foreach (int item in ArInt) Console.Write("{0} ", item);

        Console.WriteLine("\nThe array size is " + ArInt.Length);

        Console.WriteLine("The index of element 0 is " + Array.IndexOf(ArInt,0) +"\n");

        Array.Reverse(ArInt); // Розташування елементів у зворотньому порядку

        Console.WriteLine("Reversed array contains elements:");

        foreach (int item in ArInt) Console.Write("{0} ", item);

        Console.WriteLine("\nThe index of element 0 is " + Array.IndexOf(ArInt, 0) +"\n");

        Array.Sort(ArInt); // Сортування елементів

        Console.WriteLine("Sorted array contains elements:");

        foreach (int item in ArInt) Console.Write("{0} ", item);

        Console.WriteLine("\nThe index of element 0 is " + Array.IndexOf(ArInt,0));

        Console.WriteLine("Press any key to continue...");

        Console.ReadKey();

    }

Оператор foreach використовується для перебору елементів в спеціальним чином організованій групі даних, яка називається колекцією. Масив є саме такою групою (колекцією). Зручність цього вигляду циклу полягає в тому, що нам не потрібно визначати кількість елементів в групі та виконувати їх перебір за індексом: ми просто вказуємо на необхідність перебрати всі елементи групи. Синтаксис оператора:

foreach ( тип ім'я in вираз ) тіло_циклу

Ім'я задає локальну по відношенню до циклу змінну, яка по черзі набуватиме всіх значень з масиву виразу (у якості виразу найчастіше застосовується ім'я масиву або іншої колекції даних). У простому або складеному операторі, що є тілом циклу, виконуються дії зі змінною циклу. Тип змінної повинен відповідати типу елементу масиву.

Наприклад, нехай заданий масив:

           int[] a = { 24, 50, 18, 3, 16, -7, 9, -1 };

Виведення цього масиву на екран за допомогою оператора foreach виглядає таким чином:

           foreach (int x in a) Console.Write("\t" + x);

Цей оператор виконується так: на кожному проході циклу черговий елемент масиву призначається змінній х і з нею виконуються дії, записані в тілі циклу.

У наступному прикладі вирішується те ж завдання, що і в попередньому прикладі, але з використанням циклу for:

           for (int i = 0; i < 8; ++i) Console.Write("\t" + a[i]);

Обмеженням оператора foreach є те, що з його допомогою можна лише переглядати значення в групі даних, але не змінювати їх.


 

А также другие работы, которые могут Вас заинтересовать

31376. Актуальные проблемы категории субъективного вещного права 995.5 KB
  Для достижения этой цели в диссертации решаются такие задачи как выявление качественных отличий между вещными и обязательственными субъективными правами, выработка определения понятия субъективного вещного права, установление видов субъективных вещных прав
31377. Пути адаптации тайцзицюань к системе физического воспитания России 185 KB
  Проблеме адаптации тайцзицюань в систему физического воспитания посвящена кандидатская диссертация аспирантки кафедры СБЕ, шестикратной чемпионки Китая по ушу Лю Шухуэй, фрагменты которой приводятся ниже.
31379. ЭКОНОМИЧЕСКИЙ МЕХАНИЗМ ОПЕРАТИВНОГО УПРАВЛЕНИЯ ТЕКУЩИМИ АКТИВАМИ КОРПОРАЦИЙ 448 KB
  Как правило, при проведении научных исследований процесса управления, рассматриваются различные стратегические задачи, такие как маркетинг, персонал. На наш взгляд, однако, большое внимание должно также уделяться оперативному (текущему) управлению, от которого зависит повседневная деятельность предприятий, то есть та, которая, в основном, и приносит коммерческий доход.
31380. Корпоративная культура: методы ее формирования и развития в организации 463 KB
  Выбор темы дипломной работы: Корпоративная культура: методы ее формирования и развития в организации обусловлен тем что корпоративная культура напрямую связанна с коммерческий успехом компании. Компания будет успешной только в случае если сотрудники будут понимать важность своей работы чувствовать что их профессиональный уровень пропорционален успеху компании. Мотивация сотрудников построение отношений между сотрудниками принципы и методы работ используемых в деятельности организации все это является важнейшим фактором в борьбе...
31381. ПРАВОВОЕ ГОСУДАРСТВО И ГРАЖДАНСКОЕ ОБЩЕСТВО 506 KB
  Основные признаки правового государства и гражданского общества. Формирование и развитие правового государства и гражданского общества в современной России. Конституционно – правовые основы построения правового государства 37 2. Проблема становления и развития правового государства и гражданского общества до сих пор считается нерешенной и недостаточно разработанной в современной политической и правовой науках хотя период ее изучения измеряется столетиями а время от времени она...
31382. ПРАВОВОЕ РЕГУЛИРОВАНИЕ ДЕЯТЕЛЬНОСТИ ИНДИВИДУАЛЬНЫХ ПРЕДПРИНИМАТЕЛЕЙ, КАК УЧАСТНИКОВ ГРАЖДАНСКИХ ПРАВООТНОШЕНИЙ ПО СОВРЕМЕННОМУ ЗЗАКОНОДАТЕЛЬСТВУ» (НА ПРИМЕРЕ ИП ПОЛЯКОВА Л.А) 511 KB
  Исходные данные к работе: Конституция Российской Федерации Гражданский кодекс Российской Федерации Налоговый кодекс Российской Федерации федеральные конституционные законы иные федеральные нормативные правовые акты. Содержание расчетнопояснительной записки перечень подлежащих разработке вопросов: дать понятие предпринимательской деятельности и ее признаков; определить правовое положение в ней индивидуального предпринимателя; рассмотреть вопросы законодательного регулирования предпринимательской деятельности сформулировать конкретные...
31383. Направления по усовершенствованию системы оплаты труда в ООО «Проект 69» 643 KB
  Теоретические основы системы организации и оплаты труда. Формы и системы оплаты труда на предприятии. Основные принципы организации оплаты труда состав фонда оплаты труда. Анализ организации оплаты труда в ООО Проект 69. Анализ существующей системы оплаты труда ООО Проект 69...
31384. Себестоимость продукции промышленного предприятия и пути ее оптимизации на примере ОАО «Сарановская шахта «Рудная» 621.5 KB
  Технологический процесс получения продукции и формирование себестоимости в ОАО Сарановская шахта Рудная. Анализ и оценка структуры затрат в себестоимости продукции. Мероприятия по снижению себестоимости продукции в ОАО Сарановская шахта Рудная как путь повышения производства.