1.4.3. Ввод неизвестного количества данных

В приведенных выше разделах мы писали программы, которые суммировали числа от 1 до 10. Логическое усовершенствование этой программы подразумевало бы запрос суммируемых чисел у пользователя. В таком случае мы не будем знать, сколько чисел суммировать. Поэтому продолжим читать числа, пока будет что читать.

#include <iostream>

int main() {

 int sum = 0, value = 0;

 // читать данные до конца файла, вычислить сумму всех значений

 while (std::cin >> value)

  sum += value; // эквивалентно sum = sum + val

 std::cout << "Sum is: " << sum << std::endl;

 return 0;

}

Если ввести значения 3 4 5 6, то будет получен результат Sum is: 18.

Первая строка функции main() определяет две переменные типа int по имени sum и value, инициализируемые значением 0. Переменная value применяется для хранения чисел, вводимых в условии цикла while.

while (std::cin >> value)

Условием продолжения цикла while является выражение

std::cin >> value

Это выражение читает следующее число со стандартного устройства ввода и сохраняет его в переменной value. Как упоминалось в разделе 1.2, оператор ввода возвращает свой левый операнд. Таким образом, в условии фактически проверяется объект std::cin.

Когда объект типа istream используется при проверке условия, результат зависит от состояния потока. Если поток допустим, т.е. не столкнулся с ошибкой и ввод следующего значения еще возможен, это условие считается истинным. Объект типа istream переходит в недопустимое состояние по достижении конца файла (end-of-file) или при вводе недопустимых данных, например строки вместо числа. Недопустимое состояние объекта типа istream в условии свидетельствует о том, что оно ложно.

Таким образом, пока не достигнут конец файла (или не произошла ошибка ввода), условие остается истинным и выполняется тело цикла while. Тело состоит из одного составного оператора присвоения, который добавляет значение переменной value к текущему значению переменной sum. Однажды нарушение условия завершает цикл while. По выходе из цикла выполняется следующий оператор, который выводит значение переменной sum, сопровождаемое манипулятором endl.

Ввод конца файла с клавиатуры

Разные операционные системы используют для конца файла различные значения. Для ввода символа конца файла в операционной системе Windows достаточно нажать комбинацию клавиш <Ctrl+z> (удерживая нажатой клавишу <Ctrl>, нажать клавишу <z>), а затем клавишу <Enter> или <Return>. На машине с операционной системой UNIX, включая Mac OS-X, как правило, используется комбинация клавиш <Ctrl+d>.

Возвращаясь к компиляции

Одной из задач компилятора является поиск ошибок в тексте программ. Компилятор, безусловно, не может выяснить, делает ли программа то, что предполагал ее автор, но вполне способен обнаружить ошибки в форме записи. Ниже приведены примеры ошибок, которые компилятор обнаруживает чаще всего.

Синтаксические ошибки. Речь идет о грамматических ошибках языка С++. Приведенный ниже код демонстрирует наиболее распространенные синтаксические ошибки, снабженные комментариями, которые описывают их суть.

// ошибка: отсутствует ')' список параметров функции main()

int main ( {

 // ошибка: после endl используется двоеточие, а не точка с запятой

 std::cout << "Read each file." << std::endl:

 // ошибка: отсутствуют кавычки вокруг строкового литерала

 std::cout << Update master. << std::endl;

 // ошибка: отсутствует второй оператор вывода

 std::cout << "Write new master." std::endl;

 // ошибка: отсутствует ';' после оператора return

 return 0

}

Ошибки несовпадения типа. Каждый элемент данных языка С++ имеет тип. Значение 10, например, является числом типа int. Слово "привет" с парными кавычками — это строковый литерал. Примером ошибки несовпадения является передача строкового литерала функции, которая ожидает целочисленным аргумент.

Ошибки объявления. Каждое имя, используемое в программе на языке С++, должно быть вначале объявлено. Использование необъявленного имени обычно приводит к сообщению об ошибке. Типичными ошибками объявления является также отсутствие указания пространства имен, например std::, при доступе к имени, определенному в библиотеке, а также орфографические ошибки в именах идентификаторов.

#include <iostream>

int main() {

 int v1 = 0, v2 = 0;

 std::cin >> v >> v2; // ошибка: используется "v" вместо "v1"

 // cout не определен, должно быть std::cout

 cout << v1 + v2 << std::endl;

 return 0;

}

Сообщение об ошибке содержит обычно номер строки и краткое описание того, что компилятор считает неправильным. Исправлять ошибки имеет смысл в том порядке, в котором поступают сообщения о них. Зачастую одна ошибка приводит к появлению других, поэтому компилятор, как правило, сообщает о большем количестве ошибок, чем имеется фактически. Целесообразно также перекомпилировать код после устранения каждой ошибки или небольшого количества вполне очевидных ошибок. Этот цикл известен под названием "редактирование, компиляция, отладка" (edit-compile-debug).

Упражнения раздела 1.4.3

Упражнение 1.16. Напишите собственную версию программы, которая выводит сумму набора целых чисел, прочитанных при помощи объекта cin.