Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебник Моя первая программа на С++.docx
Скачиваний:
3
Добавлен:
01.07.2025
Размер:
6 Мб
Скачать
☆

Будьте осторожны при использовании scanf()

Во многих системах символы, входящие во входной поток, помещаются в область памяти, называемую бу- фером. Если функция scanf() прерывает работу преждевременно, символы не будут внесены в значение переменной, а останутся в буфере. Существует опасность, что при следующей процедуре ввода данных функция начнет чтение символов с тех, которые уже содержатся в буфере, а не с тех, которые вводятся в ответ на новый запрос.

Поэтому функцию scanf() следует использовать с осторожностью. Лучше всего вводить только один набор данных с одной функцией и использовать подсказки, четко объясняющие пользователю, какой именно ввод от него ожидается.

Ввод в Си++

Компиляторы языка Си++ поддерживают функции gets(), getchar() и scanf(), о которых мы говорили в этой главе. Кроме того, Си++ имеет собственное многоцелевое средство ввода для всех типов данных. Стандартный поток ввода cin в сочетании с двумя символами «больше» (>>), которые называются опера- тором извлечения*, служит для считывания данных с клавиатуры. Программа

int count;

cin >> count;

вносит целочисленные данные с клавиатуры в значение переменной count. Стандартный поток ввода cin не требует указания адреса переменной для числовых и символьных данных, указывается только имя пе- ременной.

При использовании cin нет необходимости определять формат с помощью указателей формата. Поток вво- да cin имеет возможность определять тип данных самостоятельно на основании вводимой информации.

Это свойство называется перегрузкой. Из-за этой особенности оператора cin большинство программистов предпочитают использовать именно его, а не функцию scanf().

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

  • В оригинале extraction operator. (Прим.перев.)

Рис. 5.11. Оператор вставки и оператор извлечения

cin >> amount >> count >> age >> name;

Возможно, первое время вы будете испытывать затруднения в использовании операторов извлечения >> и вставки <<. На рис.5.11 показан простой способ запоминания этих операторов, изображенных в виде стрелок, которые указывают направление вперед или назад относительно переменной из списка данных.

Оператор извлечения >> изображен в виде стрелки, направленной в сторону переменной. Это означает, что данные поступают к ней в виде ввода. Когда вы применяете cin для ввода данных, пользуйтесь опера- тором, который как бы указывает направление к переменной.

Оператор вставки << изображен в виде стрелки, направленной от переменной. Это значит, что данные выводятся из переменной на экран. Со стандартным потоком вывода cout используйте, соответственно, тот оператор, который как бы указывает направление от переменной.

Неинициализированные переменные

Может получиться так, что переменной, которая определена в тексте программы, так никогда и не при- сваивается никакое значение. Это может произойти по причине того, что функция scanf() прервала рабо- ту, либо потому, что вы забыли написать инструкцию ввода значения для этой переменной. Могут быть и другие причины. Если переменную, которой не присвоено значение, использовать в инструкциях вывода данных, компилятор может не сообщить об ошибке, но отображенная на дисплее информация будет ли- шена смысла. Почему это происходит?

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

Чтобы избежать неприятностей, многие программисты присваивают начальные значения всем перемен- ным. Можно присвоить ноль в качестве начального значения числовой переменной и пробел символьной и строковой переменным:

int count = 0; char initial = ' '; float rate = 0.0;

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

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

В табл. 5.1 собраны все средства ввода данных, о которых говорилось в этой главе.

Таблица 5.1. Основные средства ввода данных в языке Си/Си++.

Используемые алгоритмы ввода

Алгоритмом называют способ выполнения определенной задачи. Изучая программирование, вы в то же время учитесь разрабатывать алгоритмы, то есть определять, каким именно образом решить ту или иную задачу, используя язык Си. Может показаться, что существует бесчисленное множество способов реше- ния, столько же, сколько и задач, но на самом деле есть основной набор алгоритмов, которые использу- ются в 90 процентах случаев. Изучив наиболее часто используемые алгоритмы, вы сможете легко проек- тировать программы, основываясь на уже известных вам методах.

Один из таких алгоритмов используется для изменения значения переменной. Речь идет о присваивании нового значения переменной, которая уже инициализирована. Если использовать просто функцию ввода и имя переменной в качестве параметра, исходное значение при вводе нового будет потеряно. А что делать, если вы не хотите, чтобы оно пропало? Например, вам нужно сравнить старое и новое значения (соответ- ствующие примеры приведены в главе8). Один из возможных способов— это ввести дополнительную пе- ременную для сохранения прежнего значения:

cache = amount;

Здесь значение переменной amount передается в переменную cache, и до тех пор, пока в amount не запи- сана новая информация, обе переменные имеют одну и ту же величину. Переменная cache обеспечивает хранение значения в памяти, пока в нем не возникнет необходимость. Когда оно вам потребуется, исполь- зуйте переменную, которая служила для хранения.

В программе, приведенной в Листинге 5.2, показан пример присваивания переменной нового значения (в следующих главах вы увидите различные варианты практического применения этой процедуры).

Листинг 5.2. Программа присваивания переменной нового значения с сохранением старого.

/*storage.c*/ main()

{

¶a++ae æepcue u+uru æɵuyye+a sneuwpo++ɵu usgawenacwæou "Books-shop".

Pacupocwpa+e+ue, upogaua, uepesauuca ga++on u+uru unu ee ¬acwen 3AMPE[EHª.

O æcex +apyue+uex upoca6a coo6yawa uo agpecy piracy@books-shop.com

int number, storage;

puts("Введите значение переменной"); scanf("%d", &number); storage = number; puts("Введите значение переменной"); scanf("%d", &number);

printf("Исходное значение: %d\n", storage); printf("Новое значение: %d", number);

}

Рис. 5.12. Присваивание переменной нового значения Ввод значения переменной number обеспечивается следующими инструкциями: puts("Введите значение переменной");

scanf("%d", &number);

Сохранение значения переменной number в переменной storage выполняет инструкция:

storage = number;

Для ввода второго значения переменной number используются точно такие же инструкции, как и в первом случае. Оба значения, старое и новое, позже могут быть отражены на экране. Прежнее содержимое пере- менной не было утеряно просто потому, что было сохранено в другой области памяти, как показано на рис.5.12.