Введення та виведення даних в консоль

Введення даних в консоль C#

Щойно ми розглянули напростіше набуття змінною свого значення - присвоєння. a = 12; - змінна а набуває значення 12.

Метод ReadLine() - це ще один спосіб присвоїти змінній значення, але не наперед визначене, а введене з клавіатури у процесі виконання програми.

фрагмент коду 1:

Console.Write ( "Введіть ім'я та натисніть Enter:"); //виведення на екран запрошення

string name = Console.ReadLine(); //оголошення рядкової величини на надання їй значення новим методом

Console.WriteLine ( "Привіт, " + name + "!") //виведення тексту "Привіт, " та значення, що містить змінна "name"

Метод ReadLine() ще називають оператором введення і працює він наступним чином.

  1. програма зупиняється;

  2. програма чекає доки користувач введе данні з клавіатури і натисне Enter;

  3. після натискання Enter програма продовжує своє виконання;

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

У фрагменті коду 1 данні присвоюються змінній "name".

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


Введення в консоль числових даних

Щоб отримати з рядкових даних числові значення, треба їх попередньо конвертувати, наприклад, використовувати методи класу Convert:

фрагмент коду 2:

Console.Write ( "Введіть свій вік і натисніть Enter:"); //виведення на екран тексту

int age = Convert.ToInt32 (Console.ReadLine ()); //оголошення цілочисельної змінної "age". Присвоєння їй значення конвертованого у чилове з введної рядкової величини.

Console.Write ( "Введіть свій зріст і натисніть Enter (можна використовувати дробове значення ):"); //знову виведення повідомлення на екран

double height = Convert.ToDouble (Console.ReadLine ()); //оголошення дійсної змінної "height". Присвоєння їй значення конвертованого у чилове з введної рядкової величини.

// наступний рядок Console.WriteLine... ми організували трішечки іншим способом ніж у фрагменті коду 1

Console.WriteLine ( "Отже, вам {0} років, а зріст {1}.", age, height); //виведення текстового повідомлення до якого включено аргументи {0} та {1}. Значення аргументів перераховані після текстової величини.


Використання оператор введення для тимчасової зупинки виконання програми

Ще, рядок Console.ReadLine(); дуже часто ставлять в кінці консольних програм без присвоєня можливих результатів введеданих жодним аргументам. ReadLine () верівно зупинить виконання програми допоки користувач не натисне ENTER. Коли ENTER натиснуто, програма збирає всю інформацію, що ввів користувач з клавіатури, і ... нічого з нею не робить, тому що в цьому рядку не вкзано писвоєння жодній змінній. Комп'ютеру залишається тільки потиснути плечима, забути все, що ввів користувач і продовжити роботу. Ну хіба не гріх опускати таку просту можливість тимчасово зупинити програму?


Зразок програми 1:

using System;

class FirstClass

{

static void Main ()

{

Console.Write ( "Введіть ім'я та натисніть Enter:");

string name = Console.ReadLine ();

// "name" можна використовувати як звичайну змінну

Console.WriteLine ( "Hello, " + name + "!");

// Зробимо це знову, тільки тепер запитаємо яку піцу Ви бажаєте замовити

Console.Write ( "Введіть назву піци яку Ви бажаєте замовити та натисніть Enter:");

string pizza = Console.ReadLine ();

// А тепер використовуємо обидві змінні

Console.WriteLine ( "Привіт, {0}! Одна {1} піца на підході! Підготуйте гроші!", Name, pizza);

// Використовуємо ReadLine () з чисельними типами

Console.Write ( "Введіть свій вік і натисніть Enter:");

int age = Convert.ToInt32 (Console.ReadLine ());

Console.Write ( "Введіть свій зріст і натисніть Enter (можна використовувати дробові значення):");

double height = Convert.ToDouble (Console.ReadLine ());

Console.WriteLine ( "Отже, вам {0} років, а зріст {1}.", age, height);

// А тепер зупинимо програму оператором введення щоб користувач зміг прочитати останнє повідомлення

// та попросимо його натиснути "Enter" для продовження роботи програми. А в нашому випадку продовженням роботи програми є її завершення.

Console.Write ( "Програма завершена. Натисніть \" Enter \ "для завершення ...");

Console.ReadLine ();

}

}


Можливі помилки використання оператора введення

Інформація введена командою ReadLine() може призвести до помилок за кількох умов:

  1. Невідповідність типу введених даних присвоєній змінній;

  2. Некоректність подальшого перетворення введених даних в інші типи;

  3. Саме на етапі введення можуть бути порушені допустимі межі аргументів;

  4. Інше.

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

Не "Convert - ом" єдиним

Convert це клас, що містить відносно багато методів перетворення даних рядкового типу в числові. Проте практично для кожного числового типу даних... А для тих хто не знає чи забув то нагадаю, що у C# типи даних це також певні класи. Так от, в класі кожного числового типу, є метод Parse. Це також метод перетворення типів даних, правда лише з рядкового у інші. Скажімо виклик методу Parse класу int (int.Parse) та методу ToInt32 класу Convert (Convert.ToInt32), для конвертації рядка в число, виконують практично одне і теж. В прикладних програмах зустрічаються обидва способи перетворення типів: метод Parse та метод ToInt32. Відмінність між ними деяка, незначна, є - при конвертації рядка null. Але ми цю відмінність розглядати та використовувати не плануємо.

Перепишемо перший приклад фрагменту коду 2 з використанням Parse:

фрагмент коду 3:

Console.Write ( "Введіть свій вік і натисніть Enter:");

int age = int.Parse (Console.ReadLine ());

Console.Write ( "Введіть свій зріст і натисніть Enter (можна використовувати дробове значення ):");

double height = int.Parse (Console.ReadLine ());

Console.WriteLine ( "Отже, вам " + age + " років, а зріст " + height);


Неявне перетворення

Щойно наведений рядок: "double height = int.Parse (Console.ReadLine ());" помилки у компілятора не викликає хоча дані введені з клавіатури перетворюються в тип Integer (Інтеджер) а присвоюються змінній типу "double". Це приклад неявного перетворення типів. У C# практично завжди при присвоєні даних меншого за обсягом типу до змінної типу більш "громіздкого" відбувається неявне перетворення типів даних. Зворотнє ж перетворення можливе лише з використання уже розглянутих нами операторів явного перетворення типів Parse та Conwert.To.... Окрім неявного перетворення є ще неявне оголошення і про це ми лише коротко згадаємо у наступних абзацах.


Зауваження

Є така приказка: "Те що можна коневі не можна волові." Те, що просто реалізовується в одних мовах програмування для реалізації засобами інших потребує від програміста певних знань та їх усвідомлення.

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

Старше покоління може пригадати як у мові Basic типи даних можна було взагалі не вказувати. Звичайно про Basic вже всі практично забули не через це. Ну а так зване неявне оголошення типів можна використовувати і в C#, починаючи з версії 3.0 (контекстне ключове слово "var"). Та чи варто схиляти до цього наших учнів?


Введення в консоль кількох числових значень записаних в одному рядку

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

фрагмент коду 4:

string line = System.Console.ReadLine(); // оголошуємо рядкову величину поіменовану line та зчитуємо її значення з клавіатури.

string[] str_int = line.Split(' '); // оголошуємо масив str_int та формуємо його значення з методом Split з рядка line.

Ці дві операції можна поєднати у одному рядку не оголошуючи рядкової величини line:

string[] str_int = System.Console.ReadLine().Split(' ');

На приклад на сайті змагань зі спортивного програмування Timus Online Judge (acm.timus.ru), що підтримує мову C#, пропонується наступний спосіб зчитування двох величин, що вводяться в консольний рядок через проміжок (http://acm.timus.ru/help.aspx?topic=csharp):

фрагмент коду 5:

string[] tokens = Console.ReadLine().Split(' '); // оголошується масив даних рядкового типу та до нього, з консолі, вводяться значення

// що відокремлюються одне від одного методом "Split".

Ось так потім використовуються отримані з клавіатури числові значення:

Console.WriteLine(int.Parse(tokens[0]) + int.Parse(tokens[1])); // на екран виводиться сума перших двох елементів того масиву,

// які при цьому перетворюються в числові та додаються.

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

фрагмент коду 6:

int[] mass = int.Parse(Console.ReadLine().Split(' '));

чи

int[] mass =Convert.ToInt32 (Console.ReadLine ().Split(' '));

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

фрагмент коду 7:

string[] mass = Console.ReadLine ().Split(' '); // оголошується масив даних рядкового типу та до нього, з консолі, вводяться значення

int[] m = new int[5]; //оголошується масив цілочисельних даних обсягом 5 елементів

for (int i = 0; i<5; i=i+1) m[i] = Convert.ToInt32(mass[i]); // у циклі значення елементів масиву даних рядкового типу перетворюються у

// цілочисельні значення та записуються у масив.

Якщо попередньо не відомо скільки чисел буде введено з клавіатури визначити їх обсяг, тобто кількість елементів масиву можна методом Length.Наприклад для масиву mass метод буде записуватись так: mass.Length. Значення отримане з mass.Length можна використати і для наступного перетворення масиву рядкових значень у числовий масив:

фрагмент коду 8:

string[] mass = Console.ReadLine ().Split(' '); // оголошується масив та зчитуваний рядок записується у його елементи

int[] m = new int[mass.Length]; // оголошується цілочисельний масив такого ж обсягу як і рядковий

for (int i = 0; i<mass.Length; i=i+1) m[i] = Convert.ToInt32(mass[i]); // тут метод mass.Length вказує на умову завершення циклу

На сайті e-olimp задачі як правило мітять вхідні дані масивів у такому форматі: "В першому рядку міститься ціле число: кількість елементів масиву n. У наступному рядку міститься n цілих чисел - елементів масиву. Зчитування таких даних здіснюється наступним кодом.

фрагмент коду 9:

int n = Convert.ToInt32(Console.ReadLine ()); // оголошується та зчитується з клавіатури n - кількість елементів масиву.

string[] mass = Console.ReadLine ().Split(' '); // оголошується масив та зчитуваний рядок записується у його елементи.

int[] m = new int[n]; // оголошується цілочисельний масив обсягом n.

for (int i = 0; i<n; i=i+1) m[i] = Convert.ToInt32(mass[i]); // дані з рядкового масиву перетворюються та записується у числовий.


Більш детально про метод Split, про рядкові величини в C# та про інші засоби роботи з рядками гарно написано тут: http://it.fitib.altstu.ru/neud/cs/index.php?action=show&show=131


Ось приклад розв'язку задачі №7336 сайту "Є олімп" Пиріжки (Пиріжок у шкільній їдальні коштує a гривень та b копійок. Знайдіть скільки гривень та копійок заплатить Петрик за n пиріжків. Вхідні дані: Три натуральних числа a, b, n (0 ≤ a,b, n ≤ 100). Вихідні дані: Через пропуск два числа: вартість покупки у гривнях та копійках. Приклад: вхідні дані 1 25 2, вихідні дані 2 50 )

Зразок програми 2:

class SumPrerequisite

{

static void Main()

{

string line;

line = System.Console.ReadLine();

string[] str_int = line.Split(' ');

int a, b, n;

a = System.Convert.ToInt32(str_int[0]);

b = System.Convert.ToInt32(str_int[1]);

n = System.Convert.ToInt32(str_int[2]);

b = (a * 100) + b;

int k = b*n;

int g = k / 100;

k = k % 100;

System.Console.WriteLine(g+" "+k);

}

}

Запишемо усе компактніше:

Зразок програми 3:

using System;

class SumPrerequisite

{

static void Main()

{

string line = System.Console.ReadLine();

string[] str_int = line.Split(' ');

int a = Convert.ToInt32(str_int[0]);

int b = Convert.ToInt32(str_int[1]);

int n = Convert.ToInt32(str_int[2]);

b = (a * 100) + b;

int k = b*n;

int g = k / 100;

k = k % 100;

Console.WriteLine(g+" "+k);

}

}



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

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

Загалом рядок, як масив, зручно перетворювати не в окремі величини а в інший масив. Тобто розбивати одну рядкову величину на масив рядкових величин. Масив типу string хоча і є фактично масивом масивів, тобто двовимірним, але оголошується і опрацьовується як звичайний одновимірний масив. Наприклад масив з іменем smatrix оголошено буде так string[] smatrix = ...