Введення. 2
Загальні положення. 3
Потоковий ввід-вивід 9
Форматний введення-виведення. 13
Форматний введення з вхідного потоку. 15
Література 17
Введення.
У стандарті мови Сі відсутні засоби введення-виведення. Всі операції введення-виведення реалізуються за допомогою функцій, що знаходяться в бібліотеці мови Сі, що поставляється в складі конкретної системи програмування Сі. Під час роботи з файлами дані можуть передаватися або у своєму внутрішньому двійковому поданні або в текстовому форматі, тобто в більш зрозумілому людині вигляді.
Особливістю мови Сі, який вперше був застосований три розробці операційної системи UNIX, є відсутність заздалегідь спланованих структур файлів. Всі файли розглядаються як неструктурована послідовність байтів. При такому підході до організації файлів вдалося поширити поняття файла і на різні пристрої. У UNIX конкретному пристрою відповідає так званий "спеціальний файл", а одні і ті ж функції бібліотеки мови Сі використовуються як для обміну даними з файлами, так і для обміну з пристроями.
Бібліотека мови Сі підтримує три рівні введення-виведення: потоковий ввід-висновок, введення-виведення нижнього рівня та введення-виведення для консолі і портів. Останній рівень, що забезпечує зручний спеціалізований обмін даними з дисплеєм і портами введення-виведення, ми розглядати не будемо в силу його системної залежності. Наприклад, він різний для MS-DOS, Windows і UNIX.
Загальні положення.
Мова Сі є фундаментом С + +. При цьому С + + підтримує всю файлову систему Сі. Тому при використанні С-коду в С + + немає необхідності міняти процедури введення-виведення. Хоча під час написання програм на С + + зазвичай більш зручно використовувати саме систему С + +. Це стосується, зокрема, і використання "iostream.h" замість "stdio.h", які реалізують введення-виведення. Вивчимо файловий ввід-висновок у мові Сі. Тим більше, що це саме по собі дуже цікаво і дуже важливо для розуміння "потоків" і "файлів" як у Сі, так і в С + +.
У системі вводу-виводу в Сі для програм підтримується єдиний інтерфейс, що не залежить від того, до якого конкретного пристрою здійснюється доступ. Тобто в Сі між програмою і пристроєм знаходиться щось більш загальне, ніж сам пристрій. Таке узагальнене пристрій введення або виведення (пристрій більш високого рівня абстракції) називається потоком. У той же час конкретне пристрій називається файлом. Наше завдання - зрозуміти, яким обрз відбувається взаємодія потоків і файлів.
Файлова система Сі призначена для роботи з різними пристроями, в тому числі з терміналами, дисководами і накопичувачами. Навіть, якщо якийсь пристрій дуже сильно відрізняється від інших пристроїв, буферизованная файлова система все одно представить його у вигляді логічного пристрою, який називається потоком. Всі потоки поводяться схожим чином. І так як вони в основному не залежать від фізичних пристроїв, то та ж функція, яка виконує запис в дисковий файл, може ту ж операцію виконати і на іншому пристрої. Наприклад, на консолі. Потоки бувають двох видів: текстові та виконавчі.
У мові Сі файлом може бути все, що завгодно, починаючи в дискового файлу і закінчуючи терміналом або принтером. Потік пов'язують з певним файлом, виконуючи обов'язкову операцію відкриття. Як тільки файл відкритий, можна проводити обмін інформацією між ним і програмою.
Але не у всіх файлів однакові можливості. Наприклад, до дискового файлу прямий доступ можливий, у той час як до деяких принтерів - він не можливий. Таким чином, ви бачите, що напрошується певний висновок, що є принципом системи введення-виведення мови Сі: всі потоки однакові, а файли - ні!
Якщо файл може підтримувати запити про місцезнаходження (покажчик поточної позиції), то при відкритті такого файлу покажчик поточної позиції у файлі встановлюється в початок файлу. При читанні кожного символу з файлу (або запису у файл) покажчик поточної позиції збільшується. Тим самим забезпечується просування по файлу.
Файл від'єднується від певного потоку (тобто розривається зв'язок між файлом і потоком) за допомогою операції закриття файлу. При закритті файлу, відкритого з метою виведення, вміст (якщо воно, звичайно, є) пов'язаного з ним потоку записується на зовнішній пристрій. Цей процес зазвичай називають дозапису потоку. При цьому гарантується, що ніяка інформація випадково не залишиться в буфері диска.
Якщо програма завершує роботу нормально, тобто або main () повертає керування операційній системі, або вихід відбувається через exit (), то всі файли закриваються автоматично.
У разі ж аварійного завершення роботи програми, наприклад, у випад краху або завершення шляхом виклику abort (), файли не закриваються.
У кожного потоку, пов'язаного з файлом, є керуюча структура, що містить інформацію про файл. Вона має тип FILE. Блок управління файлом - це невеликий блок пам'яті, тимчасово виділений операційною системою для зберігання інформації про файл, який був відкритий для використання. Блок управління файлом звичайно містить інформацію про ідентифікаторі файлу, його розташування на диску і покажчику поточної позиції у файлі.
Для виконання всіх операцій введення-виведення слід використовувати тільки поняття потоків і застосовувати всього лише одну файлову систему. Введення або виведення від кожного пристрою автоматично перетвориться системою в легко управлемий потік. І це є досягненням мови Сі.
Такі основні зауваження щодо існування різних потоків інформації і пов'язаних з ними файлів.
Файлова система мови Сі складається з декількох взаємопов'язаних між собою функцій. Для їх роботи в Сі потрібно заголовний файл <stdio.h> і такий же аналогічний йому заголовний файл <iostream.h> потрібно для роботи в С + +.
Нижче наведена таблиця основних (часто використовуваних) функцій файлової системи мови Сі.
Тема <stdio.h> представляє прототипи функцій вводу-виводу в Сі і визначає наступні три типи: size_t, fpos_t і FILE. Перші два: size_t, fpos_t представляють собою різновиди такого типу, як ціле без знака. Окремо розглянемо третій тип: FILE.
Покажчик файлу - це те, що поєднує в єдине ціле всю систему введення-виведення мови Сі. Покажчик файлу - це покажчик на структуру типу FILE. Він вказує на структуру, яка містить різноманітні відомості про файл, наприклад, його ім'я, статус, і покажчик поточної позиції в початок файлу. По суті покажчик файлу визначає конкретний файл і використовується відповідним потоком при виконанні функції введення-виведення.
Щоб виконувати у файлах операції читання і запису, програми повинні використовувати покажчики відповідних файлів. Щоб об'віть змінну-вказівник файлу необхідно використовувати наступний оператор:
FILE * fp;
Функція fopen () відкриває потік і пов'язує з цим потоком файл. Потім вона повертає покажчик цього файлу. Прототип функції має вигляд:
FILE * fopen (const char * ім'я_файлу, const char * режим);
Тут ім'я_файлу - це покажчик на рядок символів, що представляє собою припустиме ім'я файлу, у яке може входити специфікація файлу (включає позначення логічного пристрою, шлях до файлу та власне ім'я файлу).
Режим - визначає, яким чином файл буде відкритий. Нижче в таблиці показані допустимі значення режимів.
Наведемо фрагмент програми, у якому використовується функція fopen () для відкриття файлу по імені TEST.
FILE * fp;
fp = fopen ("test", "w");
Слід відразу ж вказати на недостатність такого коду в програмі. Хоча наведений код технічно правильний, але його зазвичай пишуть трохи по-іншому.
FILE * fp;
if ((fp = fopen ("test", "w") == NUL)
{
printf ("Помилка при відкритті файлу. \ n \ r") "
exit (1);
}
Рис. 1
Цей метод допомагає при відкритті файлу виявити будь-яку помилку.
Наприклад, захист від запису або повний диск. Причому, виявити ще до того, як програма спробує в цей файл щось записати. Тому завжди потрібно спочатку отримати підтвердження, що функція fopen () виконалася успішно, і лише потім виконувати c файлом інші операції. Нижче на малюнку 1 наведена невелику частину програми, яка. підтверджує або не підтверджує відкриття файлу. Результати роботи зазначеної програми наведені на малюнку 2.
Рис. 2.
Потоковий ввід-висновок
На рівні потокового введення-виведення обмін даними виробляється побайтно. Такий введення-виведення можливий як для власне пристроїв побайтово обміну (друкуючий пристрій, дисплей), так і для файлів на диску, хоча пристрої зовнішньої пам'яті, строго кажучи, є пристроями поблочної обміну, тобто за одне звернення до пристрою проводиться зчитування або запис фіксованого порції даних. Найчастіше мінімальної порцією даних, що бере участь в обміні з зовнішньою пам'яттю, є блоки в 512 байт або 1024 байта. При введенні з диска (при читанні з файлу) дані містяться в буфер операційної системи, а потім побайтно або певними порціями передаються програми користувача. При виведенні даних у файл вони накопичуються в буфері, а при заповненні буфера записуються у вигляді єдиного блоку на диск за одне звернення до останнього. Буфери операційної системи реалізуються у вигляді ділянок основної пам'яті. Тому пересилання між буферами введення-виведення і виконуваної програмою відбуваються досить швидко на відміну від реальних обмінів з фізичними пристроями.
Функції бібліотеки введення-виведення мови Сі, що підтримують обмін даними з файлами на рівні потоку, дозволяють обробляти дані різних розмірів і форматів, забезпечуючи при цьому буферизованная введення і виведення. Таким чином, потік - це файл разом з наданими засобами буферизації.
При роботі з потоком можна проводити наступні дії:
· Відкривати і закривати потоки (пов'язувати покажчики на потоки з конкретними файлами);
· Вводити і виводити: символ, рядок, форматовані дані, порцію даних довільної довжини;
· Аналізувати помилки потокового введення-виведення і умова досягнення кінця потоку (кінця файлу);
· Управляти буферизацією потоку і розміром буфера;
· Отримувати та встановлювати покажчик (індикатор) поточної позиції
При відкритті потоку можуть виникнути такі помилки: зазначений файл, пов'язаний з потоком, не знайдений (для режиму "читання"); диск заповнений або диск захищений від запису і т.п. Необхідно також відзначити, що при виконанні функції fopen () відбувається виділення динамічної пам'яті. При її відсутності встановлюється ознака помилки "Not enough memory" (недостатньо пам'яті). У перерахованих випадках покажчик на потік набуває значення NULL. Зауважимо, що покажчик на потік у будь-якому режимі, відмінному від аварійного ніколи не буває рівним NULL.
Наведемо типову послідовність операторів, яка використовується при відкритті файлу, пов'язаного з потоком:
if ((fp = fopen ("t.txt", "w")) == NULL)
perror ("помилка при відкритті файлу t.txt \ n");
exit (0);
}
Де NULL - нульовий покажчик, визначений у файлі stdio.h.
Відкриті на диску файли після закінчення роботи з ними рекомендується закрити явно. Для цього використовується бібліотечна функція
int fclose (указатель_на_поток);
Відкритий файл можна відкрити повторно (наприклад, для зміни режиму роботи з ним) тільки після того, як файл буде закритий за допомогою функції fclose ().
Коли програма починає виконуватися, автоматично відкриваються п'ять потоків, з яких основними є:
· Стандартного входу (на нього посилаються, використовуючи зумовлений покажчик на потік stdin);
· Стандартний потік виводу (stdout);
· Стандартний потік виводу повідомлень про помилки (stderr).
За замовчуванням стандартному потоку вводу stdin ставиться у відповідність клавіатура, а потокам stdout і stderr відповідає екран дисплея.
Одним з найбільш ефективних способів здійснення введення-виведення одного символу є використання бібліотечних функцій getchar () і putchar (). Прототипи цих функцій мають такий вигляд:
int getchar (void);
int putchar (int c);
Функція getchаr () здійснює введення одного символу. При зверненні вона повертає в викликала її функцію один введений символ.
Функція putchar () виводить у стандартний потік один символ, при цьому також повертає в викликала її функцію тільки що виведений символ.
Зверніть увагу на те, що функція getchar () вводить черговий байт інформації (символ) у вигляді значення типу int. Це зроблено для того, щоб гарантувати успішність розпізнавання ситуації "досягнуть кінець файлу". Справа в тому, що при читанні з файлу за допомогою функції getchar () може бути досягнутий кінець файлу. У цьому випадку операційна система у відповідь на спробу читання символу передає функції getchar () значення EOF (End of File). Константа EOF визначена в заголовному файлі stdio.h і в різних операційних системах має значення 0 або -1. Таким чином, функція getchar () повинна мати можливість прочитати з вхідного потоку не тільки символ, а й ціле значення. Саме з цією метою функція getchar () завжди повертає значення типу int.
У разі помилки при введенні функція getchar () також повертає EOF.
При наборі тексту на клавіатурі коди символів записуються у внутрішній буфер операційної системи, Одночасно вони відображаються (для візуального контролю) на екрані дисплея. Набрані на клавіатурі символи можна редагувати (видаляти і набирати нові). Фактичний перенесення символів з внутрішнього буфера в програму відбувається при натисканні клавіші. При цьому код клавіші також заноситься у внутрішній буфер. Таким чином, при натисканні на (Клавішу 'А' і клавішу (завершення вводу) у внутрішньому буфері виявляються: код символу 'А' і код клавіші.) Про це необхідно пам'ятати, якщо ви розраховуєте на введення функцією getchar () одиночного символу.
Наведемо приклад програму копіювання зі стандартного вводу у стандартний висновок:
# Include
int main ()
{
int c;
while ((c = getchar ())!= EOF)
Putchar (c);
return 0;
}
Для завершення наведеної вище програми копіювання необхідно ввести з клавіатури сигнал переривання Ctrl + C.
Однією з найбільш популярних операцій введення-виведення є операція вводу-виводу рядки символів. У бібліотеку мови Сі для обміну даними через Стандартні потоки вводу-виводу включені функції введення-виведення рядків gets () і puts (), які зручно використовувати при створенні діалогових систем. Прототипи цих функцій мають такий вигляд:
char * gets (char * s) / * Функція введення * /
int puts (char * s) / * Функція виводу * /
Обидві функції мають тільки один аргумент - покажчик s на масив символів. Білі рядок прочитана вдало, функція gets () повертає адресу того масиву s, в який проводився введення рядка. Якщо сталася помилка, то повертається NULL.
Функція puts () у разі успішного завершення повертає останній виведений символ, який завжди є символом '\ n'. Якщо сталася помилка, то повертається EOF.
Форматний введення-виведення.
Для роботи зі стандартними потоками в режимі форматного введення-виведення визначені дві функції:
printf () - форматний вивід;
scanf () - форматний введення.
Прототип функції printf () має вигляд:
int printf (const char * format ,...);
При зверненні до функції printf () можливі дві форми завдання першого параметра:
int printf (* форматна рядок, спісок_аргументов);
int printf (указателъ_на_форматную_строку,. спісок_аргументов);
В обох випадках функція printf () перетворює дані з внутрішнього подання в символьний вигляд відповідно до форматної рядком і виводить їх у вихідний потік. Дані, які перетворюються і виводяться, задаються як аргументи функції printf ().
Значення, що повертається функції printf () - кількість надрукованих символів, а у випадку помилки - негативне число.
Форматная_строка обмежена подвійними лапками і може включати довільний текст, керуючі символи і специфікації перетворення даних. Текст і керуючі символи з рядка формату просто копіюються у вихідний потік. Форматна рядок зазвичай розміщується в списку фактичних параметрів функції, що відповідає першому варіанту виклику функції printf (). Другий варіант припускає, що перший фактичний параметр - це вказівник типу char *, a сама форматна рядок визначена в програмі як звичайна строкова константа або змінна.
До списку аргументів функції printf () включають вираження, значення яких повинні бути виведені з програми. Окремі випадки цих виразів - змінні та константи. Кількість аргументів і їх типи повинні відповідати послідовності специфікацій перетворення в форматної рядку. Для кожного аргументу повинна бути вказана точно одна специфікація перетворення.
Якщо аргументів недостатньо для даної рядка формату, то результат залежить від реалізації (від операційної системи і від системи програмування). Якщо аргументів більше, ніж вказано у ланцюжку формату рядку, "зайві" аргументи ігноруються. Гарантується, що при будь-якій кількості параметрів і будь-якому їх типі після виконання функцій printf () подальше виконання програми буде коректним.
Специфікація перетворення має наступну форму:
% Прапори шіріна_поля. точност' специфікатор
Символ% є ознакою специфікації перетворення. У специфікації перетворення обов'язковими є лише два елементи: ознака% і специфікатор.
Специфікатор Тип аргументу Формат виводу
d int, char, unsigned Десяткове ціле зі знаком
u int, char, unsigned Десяткове ціле без знаку
o int, char, unsigned Вісімкове ціле без знаку
x int, char, unsigned Шістнадцяткове ціле без знаку; при виведенні використовуються символи "0 .. 9a .. f"
X int, char, unsigned Шістнадцяткове ціле без знаку; при виведенні використовуються символи "0 ... 9A ... F"
f double, float Речовий значення зі знаком у вигляді:
Знак_чісла dddd.dddd
де dddd - одна або більше десяткових цифр. Кількість цифр перед десятковою крапкою залежить від величини виведеного числа, а кількість цифр після десяткової точки залежить від необхідної точності. Знак числа при відсутності модифікатора '+' зображається тільки для негативного числа.
Форматний введення з вхідного потоку.
Форматний введення з вхідного потоку здійснюється функцією scanf (). Прототип функції scanf () має вигляд:
int scanf (const char * format, ...);
При зверненні до функції scanf () можливі дві форми завдання першого параметра:
int scanf (форматна рядок, список аргументів);
int scanf (указатель_на_форматную _строку, спісок_аргументов);
Функція scanf () читає послідовності кодів символів (байти) з вхідного потоку та інтерпретує їх відповідно до форматной_строкой як цілі числа, дійсні числа, одиночні символи, рядки. У першому варіанті виклику функції форматна рядок розміщується безпосередньо у списку фактичних параметрів. У другому варіанті виклику передбачається, що перший фактичний параметр - це вказівник типу char *, адресу власної форматну рядок. Форматна рядок у цьому випадку повинна бути визначена в програмі як звичайна строкова константа або змінна.
Після перетворення у внутрішнє представлення дані записуються в області пам'яті, певні аргументами, які слідують за форматної рядком. Кожен аргумент повинен бути покажчиком на змінну, в яку буде записано чергове значення даних і тип якої відповідає типу, зазначеному в специфікації перетворення з рядка формату.
Якщо аргументів недостатньо для даної рядка формату, то результат залежить від реалізації (від операційної системи і від системи програмування). Якщо аргументів більше, ніж потрібно в форматної рядку, "зайві" аргументи ігноруються.
Послідовність кодів символів, яку функція scanf () читає, із вхідного потоку, як правило, складається з полів (рядків), розділених символами проміжку або узагальненими пробільними символами. Поля проглядаються і вводяться функцією scanf () посимвольно. Введення поля припиняється, якщо зустрівся пробільний символ або в специфікації перетворення точно вказано кількість вводяться символу.
Функція scanf () завершує роботу, якщо вичерпана форматна рядок. При успішному завершенні scanf () повертає кількість перетворених і введених полів (точніше, кількість об'єктів, які отримали значення при введенні). Значення EOF повертається при виникненні ситуації "кінець файла"; значення -1 - при виникненні помилки перетворення даних.
Розглянемо форматну рядок функції scanf (): "code:% d% * s% c% s"
Рядок "code:" присутній у вхідному потоці для контролю даних, що вводяться і тому зазначена в форматної рядку. Специфікації перетворення задають наступні дії:
% D - введення десяткового цілого;
% * S - пропуск рядка;
% З - введення одиночного символу;
% S - введення рядка.
Наведемо результати роботи програми для трьох різних наборів вхідних даних.
1.Последовательность символів вихідних даних:
code: 5 поле2 D asd
Результат виконання програми:
i = 5 c = D s = asd ret = 3
Значенням змінної ret є код повернення функц »-scanf (). Число 3 говорить про те, що функція scanf () ввела дані без помилки і було оброблено 3 вхідних поля (рядки "code:" і "поле2" пропускаються при вводі).
Болле глибоко і детально були розглянуті потоковий ввід-висновок символів, його особливості роботи. У роботі для ілюстрації наведені фрагменти програм з кодом, які показують особливості реалізації тих чи інших функцій вводу-виводу.
Література
1. Подбельський В.В. Програмування на мові С. М.: Фінанси і статистика, 1999.
2. В. В. Подбельський, С. С. Фомін «Мова Сі + +». - М.: Фінанси і статистика, 2003.
3. Павловська Т.О., Щупак Ю.А. С / С + +. Структур-ное програмування (практикум). - Спб.: Пі-тер, 2004.
4. Аляєв Ю.А., Козлов О.А. Програмування. Pascal, C + +, Visual Basic. М.: Фінанси і статистика, 2004.
5. Гуденко Д., Петроченко Д. Збірник завдань з програмування. - Спб.: Пітер, 2003.
6. Культін Н. С / С + + у завданнях і прикладах .. БХВ - Петербург, 2004.
7. Фрідман А., Кландер Л. І ін С / С + +. Алгоритми і приклади. М. Біном, 2003.
Загальні положення. 3
Потоковий ввід-вивід 9
Форматний введення-виведення. 13
Форматний введення з вхідного потоку. 15
Література 17
Введення.
У стандарті мови Сі відсутні засоби введення-виведення. Всі операції введення-виведення реалізуються за допомогою функцій, що знаходяться в бібліотеці мови Сі, що поставляється в складі конкретної системи програмування Сі. Під час роботи з файлами дані можуть передаватися або у своєму внутрішньому двійковому поданні або в текстовому форматі, тобто в більш зрозумілому людині вигляді.
Особливістю мови Сі, який вперше був застосований три розробці операційної системи UNIX, є відсутність заздалегідь спланованих структур файлів. Всі файли розглядаються як неструктурована послідовність байтів. При такому підході до організації файлів вдалося поширити поняття файла і на різні пристрої. У UNIX конкретному пристрою відповідає так званий "спеціальний файл", а одні і ті ж функції бібліотеки мови Сі використовуються як для обміну даними з файлами, так і для обміну з пристроями.
Бібліотека мови Сі підтримує три рівні введення-виведення: потоковий ввід-висновок, введення-виведення нижнього рівня та введення-виведення для консолі і портів. Останній рівень, що забезпечує зручний спеціалізований обмін даними з дисплеєм і портами введення-виведення, ми розглядати не будемо в силу його системної залежності. Наприклад, він різний для MS-DOS, Windows і UNIX.
Загальні положення.
Мова Сі є фундаментом С + +. При цьому С + + підтримує всю файлову систему Сі. Тому при використанні С-коду в С + + немає необхідності міняти процедури введення-виведення. Хоча під час написання програм на С + + зазвичай більш зручно використовувати саме систему С + +. Це стосується, зокрема, і використання "iostream.h" замість "stdio.h", які реалізують введення-виведення. Вивчимо файловий ввід-висновок у мові Сі. Тим більше, що це саме по собі дуже цікаво і дуже важливо для розуміння "потоків" і "файлів" як у Сі, так і в С + +.
У системі вводу-виводу в Сі для програм підтримується єдиний інтерфейс, що не залежить від того, до якого конкретного пристрою здійснюється доступ. Тобто в Сі між програмою і пристроєм знаходиться щось більш загальне, ніж сам пристрій. Таке узагальнене пристрій введення або виведення (пристрій більш високого рівня абстракції) називається потоком. У той же час конкретне пристрій називається файлом. Наше завдання - зрозуміти, яким обрз відбувається взаємодія потоків і файлів.
Файлова система Сі призначена для роботи з різними пристроями, в тому числі з терміналами, дисководами і накопичувачами. Навіть, якщо якийсь пристрій дуже сильно відрізняється від інших пристроїв, буферизованная файлова система все одно представить його у вигляді логічного пристрою, який називається потоком. Всі потоки поводяться схожим чином. І так як вони в основному не залежать від фізичних пристроїв, то та ж функція, яка виконує запис в дисковий файл, може ту ж операцію виконати і на іншому пристрої. Наприклад, на консолі. Потоки бувають двох видів: текстові та виконавчі.
У мові Сі файлом може бути все, що завгодно, починаючи в дискового файлу і закінчуючи терміналом або принтером. Потік пов'язують з певним файлом, виконуючи обов'язкову операцію відкриття. Як тільки файл відкритий, можна проводити обмін інформацією між ним і програмою.
Але не у всіх файлів однакові можливості. Наприклад, до дискового файлу прямий доступ можливий, у той час як до деяких принтерів - він не можливий. Таким чином, ви бачите, що напрошується певний висновок, що є принципом системи введення-виведення мови Сі: всі потоки однакові, а файли - ні!
Якщо файл може підтримувати запити про місцезнаходження (покажчик поточної позиції), то при відкритті такого файлу покажчик поточної позиції у файлі встановлюється в початок файлу. При читанні кожного символу з файлу (або запису у файл) покажчик поточної позиції збільшується. Тим самим забезпечується просування по файлу.
Файл від'єднується від певного потоку (тобто розривається зв'язок між файлом і потоком) за допомогою операції закриття файлу. При закритті файлу, відкритого з метою виведення, вміст (якщо воно, звичайно, є) пов'язаного з ним потоку записується на зовнішній пристрій. Цей процес зазвичай називають дозапису потоку. При цьому гарантується, що ніяка інформація випадково не залишиться в буфері диска.
Якщо програма завершує роботу нормально, тобто або main () повертає керування операційній системі, або вихід відбувається через exit (), то всі файли закриваються автоматично.
У разі ж аварійного завершення роботи програми, наприклад, у випад краху або завершення шляхом виклику abort (), файли не закриваються.
У кожного потоку, пов'язаного з файлом, є керуюча структура, що містить інформацію про файл. Вона має тип FILE. Блок управління файлом - це невеликий блок пам'яті, тимчасово виділений операційною системою для зберігання інформації про файл, який був відкритий для використання. Блок управління файлом звичайно містить інформацію про ідентифікаторі файлу, його розташування на диску і покажчику поточної позиції у файлі.
Для виконання всіх операцій введення-виведення слід використовувати тільки поняття потоків і застосовувати всього лише одну файлову систему. Введення або виведення від кожного пристрою автоматично перетвориться системою в легко управлемий потік. І це є досягненням мови Сі.
Такі основні зауваження щодо існування різних потоків інформації і пов'язаних з ними файлів.
Файлова система мови Сі складається з декількох взаємопов'язаних між собою функцій. Для їх роботи в Сі потрібно заголовний файл <stdio.h> і такий же аналогічний йому заголовний файл <iostream.h> потрібно для роботи в С + +.
Нижче наведена таблиця основних (часто використовуваних) функцій файлової системи мови Сі.
Ім'я | Що робить ця функція | Ім'я | Що робить ця функція |
fopen () | Відкриває файл | feof () | Повертає значення true (істина), якщо досягнуто кінець файлу |
fclose () | Закриває файл | ferror () | Повертає значення true (істина), якщо сталася помилка |
putc () | Записує символ в файл | remove () | Пере файл |
fputc () | Те ж, що і putc () | fflush () | Дозапис потоку в файл |
getc () | Читає символ з файлу | rewind () | Встановлює покажчик поточної позиції в початок файлу |
fgetc () | Те ж, що і getc () | ftell () | Повертає поточне значення покажчика поточної позиції у файлі |
fgets () | Читає рядок з файлу | fprintf () | Для файлу то ж, що printf () для консолі |
fputs () | Записує рядок у файл | fscanf () | Для файлу то ж, що scanf () для консолі |
fseek () | Встановлює покажчик поточної позиції на визначений байт файлу |
Покажчик файлу - це те, що поєднує в єдине ціле всю систему введення-виведення мови Сі. Покажчик файлу - це покажчик на структуру типу FILE. Він вказує на структуру, яка містить різноманітні відомості про файл, наприклад, його ім'я, статус, і покажчик поточної позиції в початок файлу. По суті покажчик файлу визначає конкретний файл і використовується відповідним потоком при виконанні функції введення-виведення.
Щоб виконувати у файлах операції читання і запису, програми повинні використовувати покажчики відповідних файлів. Щоб об'віть змінну-вказівник файлу необхідно використовувати наступний оператор:
FILE * fp;
Функція fopen () відкриває потік і пов'язує з цим потоком файл. Потім вона повертає покажчик цього файлу. Прототип функції має вигляд:
FILE * fopen (const char * ім'я_файлу, const char * режим);
Тут ім'я_файлу - це покажчик на рядок символів, що представляє собою припустиме ім'я файлу, у яке може входити специфікація файлу (включає позначення логічного пристрою, шлях до файлу та власне ім'я файлу).
Режим - визначає, яким чином файл буде відкритий. Нижче в таблиці показані допустимі значення режимів.
Режим | Що означає цей режим |
r | Відкрити текстовий файл для читання |
w | Створити текстовий файл для запису |
a | Додати в кінець текстового файлу |
wb | Створити двійковий файл для запису |
rb | Відкрити двійковий файл для читання |
ab | Додати в кінець двійкового файлу |
r + | Відкрити текстовий файл для читання / запису |
w + | Створити текстовий файл для читання / запису |
a + | Додати в кінець текстового файлу або створити текстовий файл для читання / запису |
r + b | Відкрити двійковий файл для читання / запису |
w + b | Створити двійковий файл для читання / запису |
a + b | Додати в кінець двійкового файлу або створити двійковий файл для читання / запису |
FILE * fp;
fp = fopen ("test", "w");
Слід відразу ж вказати на недостатність такого коду в програмі. Хоча наведений код технічно правильний, але його зазвичай пишуть трохи по-іншому.
FILE * fp;
if ((fp = fopen ("test", "w") == NUL)
{
printf ("Помилка при відкритті файлу. \ n \ r") "
exit (1);
}
Рис. 1
Цей метод допомагає при відкритті файлу виявити будь-яку помилку.
Наприклад, захист від запису або повний диск. Причому, виявити ще до того, як програма спробує в цей файл щось записати. Тому завжди потрібно спочатку отримати підтвердження, що функція fopen () виконалася успішно, і лише потім виконувати c файлом інші операції. Нижче на малюнку 1 наведена невелику частину програми, яка. підтверджує або не підтверджує відкриття файлу. Результати роботи зазначеної програми наведені на малюнку 2.
Рис. 2.
Потоковий ввід-висновок
На рівні потокового введення-виведення обмін даними виробляється побайтно. Такий введення-виведення можливий як для власне пристроїв побайтово обміну (друкуючий пристрій, дисплей), так і для файлів на диску, хоча пристрої зовнішньої пам'яті, строго кажучи, є пристроями поблочної обміну, тобто за одне звернення до пристрою проводиться зчитування або запис фіксованого порції даних. Найчастіше мінімальної порцією даних, що бере участь в обміні з зовнішньою пам'яттю, є блоки в 512 байт або 1024 байта. При введенні з диска (при читанні з файлу) дані містяться в буфер операційної системи, а потім побайтно або певними порціями передаються програми користувача. При виведенні даних у файл вони накопичуються в буфері, а при заповненні буфера записуються у вигляді єдиного блоку на диск за одне звернення до останнього. Буфери операційної системи реалізуються у вигляді ділянок основної пам'яті. Тому пересилання між буферами введення-виведення і виконуваної програмою відбуваються досить швидко на відміну від реальних обмінів з фізичними пристроями.
Функції бібліотеки введення-виведення мови Сі, що підтримують обмін даними з файлами на рівні потоку, дозволяють обробляти дані різних розмірів і форматів, забезпечуючи при цьому буферизованная введення і виведення. Таким чином, потік - це файл разом з наданими засобами буферизації.
При роботі з потоком можна проводити наступні дії:
· Відкривати і закривати потоки (пов'язувати покажчики на потоки з конкретними файлами);
· Вводити і виводити: символ, рядок, форматовані дані, порцію даних довільної довжини;
· Аналізувати помилки потокового введення-виведення і умова досягнення кінця потоку (кінця файлу);
· Управляти буферизацією потоку і розміром буфера;
· Отримувати та встановлювати покажчик (індикатор) поточної позиції
При відкритті потоку можуть виникнути такі помилки: зазначений файл, пов'язаний з потоком, не знайдений (для режиму "читання"); диск заповнений або диск захищений від запису і т.п. Необхідно також відзначити, що при виконанні функції fopen () відбувається виділення динамічної пам'яті. При її відсутності встановлюється ознака помилки "Not enough memory" (недостатньо пам'яті). У перерахованих випадках покажчик на потік набуває значення NULL. Зауважимо, що покажчик на потік у будь-якому режимі, відмінному від аварійного ніколи не буває рівним NULL.
Наведемо типову послідовність операторів, яка використовується при відкритті файлу, пов'язаного з потоком:
if ((fp = fopen ("t.txt", "w")) == NULL)
perror ("помилка при відкритті файлу t.txt \ n");
exit (0);
}
Де NULL - нульовий покажчик, визначений у файлі stdio.h.
Відкриті на диску файли після закінчення роботи з ними рекомендується закрити явно. Для цього використовується бібліотечна функція
int fclose (указатель_на_поток);
Відкритий файл можна відкрити повторно (наприклад, для зміни режиму роботи з ним) тільки після того, як файл буде закритий за допомогою функції fclose ().
Коли програма починає виконуватися, автоматично відкриваються п'ять потоків, з яких основними є:
· Стандартного входу (на нього посилаються, використовуючи зумовлений покажчик на потік stdin);
· Стандартний потік виводу (stdout);
· Стандартний потік виводу повідомлень про помилки (stderr).
За замовчуванням стандартному потоку вводу stdin ставиться у відповідність клавіатура, а потокам stdout і stderr відповідає екран дисплея.
Одним з найбільш ефективних способів здійснення введення-виведення одного символу є використання бібліотечних функцій getchar () і putchar (). Прототипи цих функцій мають такий вигляд:
int getchar (void);
int putchar (int c);
Функція getchаr () здійснює введення одного символу. При зверненні вона повертає в викликала її функцію один введений символ.
Функція putchar () виводить у стандартний потік один символ, при цьому також повертає в викликала її функцію тільки що виведений символ.
Зверніть увагу на те, що функція getchar () вводить черговий байт інформації (символ) у вигляді значення типу int. Це зроблено для того, щоб гарантувати успішність розпізнавання ситуації "досягнуть кінець файлу". Справа в тому, що при читанні з файлу за допомогою функції getchar () може бути досягнутий кінець файлу. У цьому випадку операційна система у відповідь на спробу читання символу передає функції getchar () значення EOF (End of File). Константа EOF визначена в заголовному файлі stdio.h і в різних операційних системах має значення 0 або -1. Таким чином, функція getchar () повинна мати можливість прочитати з вхідного потоку не тільки символ, а й ціле значення. Саме з цією метою функція getchar () завжди повертає значення типу int.
У разі помилки при введенні функція getchar () також повертає EOF.
При наборі тексту на клавіатурі коди символів записуються у внутрішній буфер операційної системи, Одночасно вони відображаються (для візуального контролю) на екрані дисплея. Набрані на клавіатурі символи можна редагувати (видаляти і набирати нові). Фактичний перенесення символів з внутрішнього буфера в програму відбувається при натисканні клавіші. При цьому код клавіші також заноситься у внутрішній буфер. Таким чином, при натисканні на (Клавішу 'А' і клавішу (завершення вводу) у внутрішньому буфері виявляються: код символу 'А' і код клавіші.) Про це необхідно пам'ятати, якщо ви розраховуєте на введення функцією getchar () одиночного символу.
Наведемо приклад програму копіювання зі стандартного вводу у стандартний висновок:
# Include
int main ()
{
int c;
while ((c = getchar ())!= EOF)
Putchar (c);
return 0;
}
Для завершення наведеної вище програми копіювання необхідно ввести з клавіатури сигнал переривання Ctrl + C.
Однією з найбільш популярних операцій введення-виведення є операція вводу-виводу рядки символів. У бібліотеку мови Сі для обміну даними через Стандартні потоки вводу-виводу включені функції введення-виведення рядків gets () і puts (), які зручно використовувати при створенні діалогових систем. Прототипи цих функцій мають такий вигляд:
char * gets (char * s) / * Функція введення * /
int puts (char * s) / * Функція виводу * /
Обидві функції мають тільки один аргумент - покажчик s на масив символів. Білі рядок прочитана вдало, функція gets () повертає адресу того масиву s, в який проводився введення рядка. Якщо сталася помилка, то повертається NULL.
Функція puts () у разі успішного завершення повертає останній виведений символ, який завжди є символом '\ n'. Якщо сталася помилка, то повертається EOF.
Форматний введення-виведення.
Для роботи зі стандартними потоками в режимі форматного введення-виведення визначені дві функції:
printf () - форматний вивід;
scanf () - форматний введення.
Прототип функції printf () має вигляд:
int printf (const char * format ,...);
При зверненні до функції printf () можливі дві форми завдання першого параметра:
int printf (* форматна рядок, спісок_аргументов);
int printf (указателъ_на_форматную_строку,. спісок_аргументов);
В обох випадках функція printf () перетворює дані з внутрішнього подання в символьний вигляд відповідно до форматної рядком і виводить їх у вихідний потік. Дані, які перетворюються і виводяться, задаються як аргументи функції printf ().
Значення, що повертається функції printf () - кількість надрукованих символів, а у випадку помилки - негативне число.
Форматная_строка обмежена подвійними лапками і може включати довільний текст, керуючі символи і специфікації перетворення даних. Текст і керуючі символи з рядка формату просто копіюються у вихідний потік. Форматна рядок зазвичай розміщується в списку фактичних параметрів функції, що відповідає першому варіанту виклику функції printf (). Другий варіант припускає, що перший фактичний параметр - це вказівник типу char *, a сама форматна рядок визначена в програмі як звичайна строкова константа або змінна.
До списку аргументів функції printf () включають вираження, значення яких повинні бути виведені з програми. Окремі випадки цих виразів - змінні та константи. Кількість аргументів і їх типи повинні відповідати послідовності специфікацій перетворення в форматної рядку. Для кожного аргументу повинна бути вказана точно одна специфікація перетворення.
Якщо аргументів недостатньо для даної рядка формату, то результат залежить від реалізації (від операційної системи і від системи програмування). Якщо аргументів більше, ніж вказано у ланцюжку формату рядку, "зайві" аргументи ігноруються. Гарантується, що при будь-якій кількості параметрів і будь-якому їх типі після виконання функцій printf () подальше виконання програми буде коректним.
Специфікація перетворення має наступну форму:
% Прапори шіріна_поля. точност' специфікатор
Символ% є ознакою специфікації перетворення. У специфікації перетворення обов'язковими є лише два елементи: ознака% і специфікатор.
Специфікатор Тип аргументу Формат виводу
d int, char, unsigned Десяткове ціле зі знаком
u int, char, unsigned Десяткове ціле без знаку
o int, char, unsigned Вісімкове ціле без знаку
x int, char, unsigned Шістнадцяткове ціле без знаку; при виведенні використовуються символи "0 .. 9a .. f"
X int, char, unsigned Шістнадцяткове ціле без знаку; при виведенні використовуються символи "0 ... 9A ... F"
f double, float Речовий значення зі знаком у вигляді:
Знак_чісла dddd.dddd
де dddd - одна або більше десяткових цифр. Кількість цифр перед десятковою крапкою залежить від величини виведеного числа, а кількість цифр після десяткової точки залежить від необхідної точності. Знак числа при відсутності модифікатора '+' зображається тільки для негативного числа.
Форматний введення з вхідного потоку.
Форматний введення з вхідного потоку здійснюється функцією scanf (). Прототип функції scanf () має вигляд:
int scanf (const char * format, ...);
При зверненні до функції scanf () можливі дві форми завдання першого параметра:
int scanf (форматна рядок, список аргументів);
int scanf (указатель_на_форматную _строку, спісок_аргументов);
Функція scanf () читає послідовності кодів символів (байти) з вхідного потоку та інтерпретує їх відповідно до форматной_строкой як цілі числа, дійсні числа, одиночні символи, рядки. У першому варіанті виклику функції форматна рядок розміщується безпосередньо у списку фактичних параметрів. У другому варіанті виклику передбачається, що перший фактичний параметр - це вказівник типу char *, адресу власної форматну рядок. Форматна рядок у цьому випадку повинна бути визначена в програмі як звичайна строкова константа або змінна.
Після перетворення у внутрішнє представлення дані записуються в області пам'яті, певні аргументами, які слідують за форматної рядком. Кожен аргумент повинен бути покажчиком на змінну, в яку буде записано чергове значення даних і тип якої відповідає типу, зазначеному в специфікації перетворення з рядка формату.
Якщо аргументів недостатньо для даної рядка формату, то результат залежить від реалізації (від операційної системи і від системи програмування). Якщо аргументів більше, ніж потрібно в форматної рядку, "зайві" аргументи ігноруються.
Послідовність кодів символів, яку функція scanf () читає, із вхідного потоку, як правило, складається з полів (рядків), розділених символами проміжку або узагальненими пробільними символами. Поля проглядаються і вводяться функцією scanf () посимвольно. Введення поля припиняється, якщо зустрівся пробільний символ або в специфікації перетворення точно вказано кількість вводяться символу.
Функція scanf () завершує роботу, якщо вичерпана форматна рядок. При успішному завершенні scanf () повертає кількість перетворених і введених полів (точніше, кількість об'єктів, які отримали значення при введенні). Значення EOF повертається при виникненні ситуації "кінець файла"; значення -1 - при виникненні помилки перетворення даних.
Розглянемо форматну рядок функції scanf (): "code:% d% * s% c% s"
Рядок "code:" присутній у вхідному потоці для контролю даних, що вводяться і тому зазначена в форматної рядку. Специфікації перетворення задають наступні дії:
% D - введення десяткового цілого;
% * S - пропуск рядка;
% З - введення одиночного символу;
% S - введення рядка.
Наведемо результати роботи програми для трьох різних наборів вхідних даних.
1.Последовательность символів вихідних даних:
code: 5 поле2 D asd
Результат виконання програми:
i = 5 c = D s = asd ret = 3
Значенням змінної ret є код повернення функц »-scanf (). Число 3 говорить про те, що функція scanf () ввела дані без помилки і було оброблено 3 вхідних поля (рядки "code:" і "поле2" пропускаються при вводі).
Висновок.
У даній роботі були розглянуті особливості операцій введення-виведення в мові програмування Сі / С + +, в яких є багато спільного. Розглянуто поняття «функції» і «потоку», їх види і особливості функціонування у мові програмування.Болле глибоко і детально були розглянуті потоковий ввід-висновок символів, його особливості роботи. У роботі для ілюстрації наведені фрагменти програм з кодом, які показують особливості реалізації тих чи інших функцій вводу-виводу.
Література
1. Подбельський В.В. Програмування на мові С. М.: Фінанси і статистика, 1999.
2. В. В. Подбельський, С. С. Фомін «Мова Сі + +». - М.: Фінанси і статистика, 2003.
3. Павловська Т.О., Щупак Ю.А. С / С + +. Структур-ное програмування (практикум). - Спб.: Пі-тер, 2004.
4. Аляєв Ю.А., Козлов О.А. Програмування. Pascal, C + +, Visual Basic. М.: Фінанси і статистика, 2004.
5. Гуденко Д., Петроченко Д. Збірник завдань з програмування. - Спб.: Пітер, 2003.
6. Культін Н. С / С + + у завданнях і прикладах .. БХВ - Петербург, 2004.
7. Фрідман А., Кландер Л. І ін С / С + +. Алгоритми і приклади. М. Біном, 2003.