- •1.1 Перші кроки
- •1.2 Змінні й арифметичні вирази
- •1.3 Твердження for
- •1.4 Символічні константи
- •1.5 Ввід і вивід знаків
- •1.5.1 Копіювання файла
- •1.5.2 Відлік символів
- •1.5.3 Відлік рядків
- •1.6 Масиви
- •1.7 Функції
- •1.8 Аргументи - виклик за значенням
- •1.9 Символьні масиви
- •1.10 Зовнішні змінні й область дії
- •2.1 Назви змінних
- •2.2 Типи даних і розміри
- •2.3 Константи
- •2.4 Оголошення
- •2.5 Арифметичні операції
- •2.6 Реляційні та логічні оператори
- •2.7 Перетворення типів
- •2.8 Оператори приросту та спаду
- •2.9 Розрядні оператори
- •2.10 Оператори та вирази присвоєння
- •2.11 Вирази умов
- •2.12 Пріоритет і послідовність обчислення
- •3.1 Вирази та блоки
- •3.3 Else if
- •3.4 Switch
- •3.5 Цикли while та for
- •3.6 Цикли do-while
- •3.7 Break і continue
- •3.8 Goto та мітки
- •4.1 Основні знання про функції
- •4.2 Функції, які не повертають цілих
- •4.3 Зовнішні змінні
- •4.4 Правила області дії
- •4.5 Файли заголовка
- •4.6 Статичні змінні
- •4.7 Регістрові змінні
- •4.8 Структура блоків
- •4.10 Рекурсія
- •4.11 Препроцесор c
- •4.11.1 Включення файлів
- •4.11.2 Заміна макросів
- •4.11.3 Обумовлене включення файлів
- •5.1 Покажчики й адреси
- •5.2 Покажчики й аргументи функцій
- •5.3 Покажчики та масиви
- •5.4 Арифметика адрес
- •5.5 Покажчики на символи та функції
- •5.6 Масив покажчиків; покажчики на покажчики
- •5.7 Багатовимірні масиви
- •5.8 Ініціалізація масиву покажчиків
- •5.9 Покажчики в порівнянні з багатовимірними масивами
- •5.10 Аргументи командного рядка
- •5.11 Покажчики на функції
- •5.12 Складні оголошення
- •6.1 Основні поняття про структури
- •6.2 Структури та функції
- •6.3 Масиви структур
- •6.4 Покажчики на структури
- •6.5 Структури зі зворотнім звертанням
- •6.6 Пошук по таблиці
- •6.7 Typedef
- •6.8 Сполуки
- •6.9 Розрядні поля
- •7.1 Стандартний ввід і вивід
- •7.2 Форматований вивід - printf
- •7.3 Списки аргументів довільної довжини
- •7.4 Форматований ввід - scanf
- •7.5 Доступ до файлів
- •7.6 Обробка помилок - stderr і exit
- •7.7 Ввід і вивід рядків
- •7.8 Додаткові функції
- •7.8.1 Операції з ланцюжками
- •7.8.2 Перевірка і перетворення класів символів
- •7.8.3 Ungetc
- •7.8.4 Виконання команд
- •7.8.5 Керування пам'яттю
- •7.8.6 Математичні функції
- •7.8.7 Генератор випадкових чисел
- •8.1 Дескриптори файлів
- •8.2 Низькорівневий ввід/вивід - read і write
- •8.3 Open, creat, close, unlink
- •8.4 Довільний доступ - lseek
- •8.5 Приклад: втілення fopen і getc
- •8.6 Приклад - перелік вмісту каталогів
- •8.7 Приклад - розподільник пам'яті
1.5 Ввід і вивід знаків
Ми розглянемо групу споріднених програм для опрацьовування символьних даних. Ви зрозумієте пізніше, що багато програм — це просто розширені версії прототипів, які ми обговорюватимемо тут.
Модель вводу та виводу, підтримувана стандартною бібліотекою, — досить проста. Текстовий ввід або вивід, незалежно від того звідки він походить або куди направлено, розглядається як потік знаків. Текстовий потік — це послідовність знаків, розділених на рядки, де кожний рядок складається з нуля або більше символів з наступним знаком нового рядка. Це залишається відповідальністю бібліотеки — добитися того, щоб кожний потік вводу або виводу відповідав цій моделі. C-програміст не повинен перейматись тим, як представлені рядки поза межами програми.
Стандартна бібліотека передбачає декілька функцій читання по одному знаку за раз, з якихgetchar і putchar являються найпростішими. Кожний раз як її викликано, getchar зчитує наступний введений знак із текстового потоку та повертає цей знак як власне значення. Тобто, після
c = getchar();
змінна c міститиме наступний знак вводу. Знаки, як правило, надходять з клавіатури; ввід з файлів ми обговоримо в Розділі 7.
Функція putchar виводить один знак кожного разу як її викликано:
putchar(c);
виводить як знак вміст цілочисельної змінної c; типово вивід надходить на екран. Викликиputchar і printf можна чергувати; вивід з'являтиметься в тій послідовності, в якій здійснено виклики.
1.5.1 Копіювання файла
Маючи getchar і putchar ви можете написати дивовижну кількість корисного коду, не знаючи більше нічого про ввід і вивід. Найпростіший приклад — це програма, що копіює свій ввід до власного виводу по одному знаку за раз: прочитати знак while (знак не є вказівником кінця файла)
вивести щойно прочитаний знак прочитати наступний знак
Переклад цього у C дасть нам:
#include <stdio.h>
/* копіює ввід до виводу; 1-а версія */
main()
{
int c;
c = getchar();
while (c != EOF) {
putchar(c);
c = getchar();
}
}
Порівнювальний оператор != означає «не дорівнює».
Те, що здається знаком на клавіатурі або екрані, звичайно як і все інше, зберігається внутрішньо, як послідовність бітів. Тип char спеціально призначений для зберігання таких знакових даних, хоча для цього можна використати будь-який тип цілого. Ми скористалися int з тонких але важливих міркувань.
Проблема полягає у відокремленні кінця вводу від чинних даних. Розв'язання її пов'язане з фактом, що getchar повертає відмінне значення, коли немає більше вводу — значення, яке не можна плутати з якимось дійсним знаком. Воно називається EOF, що походить від «end of file». Ми повинні оголосити c такого типу, який би був досить великим для збереження будь-якого значення, поверненого getchar. Ми не можемо скористатися char, оскільки c повинна бути досить місткою, щоб втримати EOF, окрім звичайних символів. Саме тому, ми вдалися до int.
EOF — це ціле, визначене в <stdio.h>. Його типова величина не настільки важлива, доки вона не збігається зі значенням якогось знака. Використовуючи символічну константу EOF, ми також переконуємося, що нічого в програмі не залежить від певного числового значення.
У досвідчених програмістів, програма копіювання виглядатиме стисліше. В мові C, будь-яке присвоєння на кшталт
c = getchar();
є виразом і має значення, що дорівнюватиме значенню з лівого боку після присвоєння. Це означає, що присвоєння може з'являтися як частина більшого виразу. Якщо присвоєння символу змінній c помістити в тестову частину циклу while, програму копіювання можна написати так:
#include <stdio.h>
/* копіює ввід до виводу; 2-а версія */
main()
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
Цикл while добуває символ, присвоює його c, потім перевіряє, чи цей символ не був вказівником кінця файла. Якщо ні, виконується корпус while, виводячи символ. Після цьогоwhile повторюється. По досягненню кінця вводу, while завершується; так само main.
Ця версія централізує ввід — існує тільки одне посилання на getchar, і це робить програму стислішою. Отримана в результаті програма, компактніша і, як тільки ви оволодієте ідіомою, легше читається. Ви часто зустрінете цей стиль. (Існує проте небезпека захопитися, і створити непроникний для розуміння код; ми намагатимемось уникати цієї тенденції.)
Дужки навколо присвоєння всередині умови обов'язкові. != має більший пріоритет за =, що означає, що за відсутності дужок порівняльна перевірка != відбулася би до присвоєння. Тож, вираз
c = getchar() != EOF
рівнозначний
c = (getchar() != EOF)
Останнє призводить до небажаного ефекту присвоєння c значень 0 або 1, залежно від того, чи повернув виклик getchar кінець файла, чи ні. (Більше про це можна знайти в Розділі 2.)
Вправа 1-6. Перевірте, чи вираз getchar() != EOF дорівнює 0 або 1.
Вправа 1-7. Напишіть програму, яка би виводила значення EOF.
