Ddoc

$(DERS_BOLUMU $(IX ввод) Чтение со стандартного ввода)

$(P
Все что считывает программа должно быть куда-то сохранено.

К примеру, программа считывающая количество учеников в классе, должна сохранить эту информацию в какую-нибудь переменную.

Типом этой переменной мог бы быть $(C int).
)

$(P
Как мы помним из предыдущей главы, если нужно что-то отправить на вывод, вовсе необязательно писать $(C stdout).

К тому-же, то что должно быть распечатано передается аргументом.

И так, чтобы распечатать значение, хранящееся в $(C studentCount), достаточно написать $(C write(studentCount)).

Подведем итог:
)

$(MONO
поток: stdout
действие: write
данные: значение переменной studentCount
получатель: обычно это окно терминала
)

$(P
$(IX readf) $(C write) записывает в стандартный вывод; $(C readf) обратная ей функция, она читает из стандартного ввода.

Буква "f" в конце названия, от английского слова "formatted" означающего - в каком-либо заранее определенном виде; то что считывает эта функция, всегда должно соответствовать какому-либо шаблону.
)

$(P
Из предыдущей главы нам известно что $(C stdin) это стандартный поток ввода.
)

$(P
При чтении данных не хватает одной части головоломки - куда же сохранять прочитанные данные.

Подведем итог:
)

$(MONO
поток: stdin
действие: readf
данные: что-либо
получатель: ?
)

$(P
Куда будут сохранены прочитанные данные определяется адресом переменной.

Адрес переменной - это то место в памяти, в котором хранится значение переменной.
)

$(P
$(IX &, получение адреса) Знак $(C &) написанный перед именем означает адрес того что представляет имя.

К примеру, $(C &studentCount) это адрес переменной $(C studentCount).

Так $(C &studentCount) можно прочесть как "адрес $(C studentCount)" - это и есть искомая часть головоломки:
)

$(MONO
поток: stdin
действие: readf
данные: что-либо
получатель: место в памяти, на которое указывает переменная studentCount
)

$(P
Написание знака $(C &) перед каким-либо именем означает $(I указание) на то что представляется этим именем.

Это основа того что называется ссылки и указатели. Мы поговорим об этом в других главах.
)

$(P
Позже я расскажу подробней про $(C readf). А пока будем считать, что первым аргументом $(C readf) должна быть строка $(STRING "%s"):
)

---
readf("%s", &studentCount);
---

$(P
$(C readf) вполне может работать и без знака $(C &):
)

---
readf("%s", studentCount); // тоже что и в примере выше
---

$(P
Хотя без использования знака $(C &) код лучше и безопасней, все же я продолжу применять $(C readf) к указателям, отчасти для того чтобы подготовить вас к встрече с $(LINK2 /ders/d.en/value_vs_reference.html, ссылками) и $(LINK2 /ders/d.en/function_parameters.html, особыми параметрами функций в виде ссылок).
)

$(P
Строка $(STRING "%s") указывает на то что данные должны быть автоматически преобразованы в значение, соответствующее типу переменной.

Так, при считывании знаков '4' и '2' в переменную типа $(C int), они преобразуются в число 42.
)

$(P
Следующая программа "спрашивает" у пользователя сколько учеников в его классе.

Когда укажите количество учеников, нажмите ENTER:
)

---
import std.stdio;

void main() {
write("Сколько у вас в классе учеников? ");

/* Объявляем переменную для хранения информации
* прочитанной из стандартного ввода. */
int studentCount;

// Сохраняем в нашу переменную данные введенные пользователем.
readf("%s", &studentCount);

writeln("Кол-во учеников: ", studentCount, ".");
}
---

$(H5 $(IX %s и пробельные знаками) $(IX пробельные знаки) Пропуск пробельных знаков)

$(P
Когда мы вводим данные и нажимаем ENTER, в поток $(C stdin) попадают введенные данные и специальный код клавиши ENTER.

Ведь иногда полезно знать каков был ввод - однострочный или многострочный.
)

$(P
Иногда специальные коды полезны, но в основном они нас не интересуют, и потому должны быть отфильтрованы от ввода.

Иначе они $(I заблокируют) ввод, и не дадут прочесть оставшиеся данные.
)

$(P
Что бы увидеть как это бывает, рассмотрим задачу когда нужно прочесть два значения - к ученикам добавить еще и учителей:
)

---
import std.stdio;

void main() {
write("Сколько у вас в классе учеников? ");
int studentCount;
readf("%s", &studentCount);

write("Сколько у вас в классе учителей? ");
int teacherCount;
readf("%s", &teacherCount);

writeln( "Кол-во учеников: ", studentCount, ",",
" кол-во учителей: ", teacherCount, ".");
}
---

$(P
К сожалению, если нужно дважды подряд получить значение типа $(C int), то это код не подойдет:
)

$(SHELL
Сколько у вас в классе учеников? 100
Сколько у вас в классе учителей? 20
$(SHELL_NOTE_WRONG Здесь выброшено исключение)
)

$(P
Когда пользователь ввел число 100 и нажал ENTER, то в поток ввода попало представление клавиши ENTER, и не смотря на то что потом в качестве числа представляющего количество учителей пользователь ввел 20, поток уже заблокирован.

И теперь поток ввода походит вот на что:
)

$(MONO
100$(HILITE [КодКлавишиEnter])20[КодКлавишиEnter]
)

$(P
Код клавиши ENTER что мешает вводу выделен.
)

$(P
И так, чтобы указать что код клавиши ENTER перед числом учителей не важен, нужно поставить знак пробела перед $(STRING %s): $(STRING " %s").

Пробелы в строке формата, указывают на то что нужно отсеять один и более невидимых знаков, что попадают в поток ввода.

К таким знакам относятся сам пробел, коды клавиши ENTER, знак табуляции, и т.п., а называются они $(I пробельные знаки) $(I (whitespace characters)).
)

$(P
При чтении из ввода, почти для всех данных можно писать $(STRING " %s").

Вот что нужно поменять чтобы программа заработала как надо:
)

---
// ...
readf(" %s", &studentCount);
// ...
readf(" %s", &teacherCount);
// ...
---

$(P
Вывод:
)

$(SHELL
Сколько у вас в классе учеников? 100
Сколько у вас в классе учителей? 20
Кол-во учеников: 100, кол-во учителей: 20.
)

$(H5 Дополнительно)

$(UL
$(LI
$(IX комментарии) $(IX /*) $(IX */) Строки, начинающиеся с последовательности $(COMMENT //) хорошо подходят для однострочных комментариев.

Если нужно написать один комментарий на нескольких строках, то такой комментарий нужно окружить знаками $(COMMENT /*) и $(COMMENT */).

$(P
$(IX /+) $(IX +/) А если нужно закомментировать другой комментарий, то окружите комментарий знаками $(COMMENT /+) и $(COMMENT +/):
)

---
/+
// Комментарий в одну строку

/*
Комментарий занимающий
несколько строк
*/

/+
В таком комментарии могут быть даже вложенные /+ комментарии +/
+/

Комментарий что включает в себя другие комментарии
+/
---
)

$(LI
Многие из пробельных знаков не значимы в исходном коде.

Длинные строки принято разбивать на несколько меньших строк.

Несмотря на это, всю программу можно записать в одну строку с наименьшим количеством пробелов, не нарушая правил языка:

---
import std.stdio;void main(){writeln("Сложно понять!");}
---

$(P
Если в коде мало пробельных знаков, его бывает сложно понимать.
)))

$(PROBLEM_TEK
$(P
Программа "рассчитывает" что вы введете числа, ну а вы введите что-нибудь другое, и убедитесь, что программа не сможет правильно отработает.
))

Macros:
SUBTITLE=Чтение со стандартного ввода

DESCRIPTION=Получение информации со стандартного ввода

KEYWORDS=язык программирования d учебник книга read stdin

MINI_SOZLUK=

Внимание! Этот перевод, возможно, ещё не готов.
Его статус: перевод редактируется

Переведено на Нотабеноиде
http://notabenoid.org/book/71439/398917

Переводчики: dlang