Попробуйте часть кода до слова main заменить на #include "stdafx.h" //1 #include <iostream> //2 using namespace std; //3 |
Системные данные текстового типа
4.3. Ввод текстовых данных во время работы программы
4.3.1. Форматный ввод
Список форматных указателей функции scanf предусматривает возможность ввода значений односимвольных ( %c ) и многосимвольных ( %s ) переменных:
#include <stdio.h> void main() { char ch1,ch2; char str1[10]; scanf("%c %c",&ch1,&ch2); scanf("%s",str1); ....................
Обратите внимание на то, что для ввода данных в скалярные переменные ch1 и ch2 в списке ввода необходимо указывать их адреса ( &ch1, &ch2 ), а при вводе в массив str1 – достаточно написать его имя. Дело в том, что имя массива одновременно выполняет роль адреса своего первого элемента. Поэтому str1 и &str1[0] указывают на один и тот же адрес.
Ввод значений символьных переменных ch1 и ch2 можно организовать одним из двух способов. Во-первых, в строке ввода можно набрать два требуемых символа либо слитно, либо разделяя их хотя бы одним пробелом и нажать клавишу Enter. Во-вторых, можно набрать первый символ, предназначенный для переменной ch1, и нажать клавишу Enter. Затем повторить аналогичным образом ввод следующего символа.
Значение, предназначенное для строковой "переменной" str1, не должно содержать более 9 символов (признак конца строки система добавляет автоматически) и среди них не должен присутствовать пробел. Дело в том, что пробел при форматном вводе воспринимается как разделитель данных. Это не означает, что среди символов строки пробел вообще не допустим, просто для организации ввода в строку нескольких слов надо использовать другие средства.
Довольно неожиданно, но с помощью задания ширины поля ввода и одного форматного указателя %с можно за один прием ввести несколько символов в элементы символьного массива:
char q[20]; ............ scanf("%20c",q); //ввод 20 символов в массив q
В отличие от ввода по форматному указателю %s в массив q здесь не записывается признак конца строки – вводятся только запрашиваемые символы, которые набираются в одной строке с последующим нажатием клавиши Enter.
Функция scanf предусматривает еще два интересных форматных указателя, которые обеспечивают ввод либо тех символов, которые указаны в заданном множестве, либо всех символов, которые не принадлежат заданному множеству. Например, для ввода цифр из диапазона от 0 до 9 такой указатель имеет вид %[0-9], а для ввода символов, не являющихся цифрами – %[^0-9]. Рассмотрим следующий пример, который не только демонстрирует ввод по таким форматным указателям, но и содержит непредвиденный пассаж, связанный с использованием "грязного" буфера ввода.
#include <stdio.h> #include <conio.h> void main() { char str[10]; int j; printf("Enter 123ABC\n"); scanf("%[0-9]",str); printf("str=%s\n",str); for(j=0; j<10; j++) printf("%3x",str[j]); printf("\nEnter DEF123\n"); scanf("%[^0-9]",str); printf("str=%s\n",str); for(j=0; j<10; j++) printf("%3x",str[j]); getch(); } //=== Результат работы === Enter 123ABC str=123 31 32 33 0 0 1 0 0 1 0 Enter DEF123 str=ABC DEF 41 42 43 a 44 45 46 0 1 0
После ввода первой строки программе были переданы символы '123', вслед за которыми в массив str был записан нулевой байт – признак конца строки. Однако в буфере ввода остались невостребованными символы 'ABC' и код клавиши Enter (код 0xa ). После набора второй строки к содержимому буфера ввода добавились еще три символа 'DEF' и т.к. все семь первых символов не являются кодами цифр, то все они были переданы в массив str. При выводе первые три отобразились в одной строке, затем сработал управляющий код 0xa и три следующие символа были выведены в следующей строке. Для наглядности содержимое массива после каждого вывода по формату %s отображалось еще и в шестнадцатеричном формате. Значения байтов, начиная с str[4], объясняются тем, что массив str является локальным, и под него выделяется "грязная память". Если его описание вынести за пределы main, то он станет глобальным и будет расписан нулями.
Чтобы не пострадать от непредвиденного ввода символов, задержавшихся в буфере ввода, рекомендуется после обращения к функции scanf чистить буфер ввода с помощью функции fflush(stdin). Если бы мы включили в предыдущий пример обращение к функции fflush, то после ввода второй строки в массиве str оказались бы только символы 'DEF'.
4.3.2. Потоковый ввод
Потоковый ввод в символьные и "строковые" переменные организуется следующим образом:
#include <iostream.h> void main() { char ch1,ch2; char str1[10]; cin >> ch1 >> ch2; cin >> str1; ....................
Набор вводимой информации на клавиатуре осуществляется точно таким же образом, как и при форматном вводе.
4.3.3. Специальные функции ввода текстовых данных
Специальные функции ввода символьных данных getch() и getche() упрощают их набор (не приходится дополнительно нажимать клавишу Enter) и предоставляют дополнительные возможности. Ниже приводится программа и результат ее работы после нажатия на цифровую клавишу 5.
#include <stdio.h> #include <conio.h> void main() { char ch[4]={'1','2','3'}; ch[1]=getch(); printf("ch[0]=%c ch[1]=%c ch[2]=%c",ch[0],ch[1],ch[2]); getch(); return; } //=== Результат работы === ch[0]=1 ch[1]=2 ch[2]=3
Функция getch (от get character – дай символ) организует ввод кода символа без эхо-сигнала, т.е. без отображения на экране знака, соответствующего нажатой клавише. Такая возможность может оказаться полезной при вводе секретных данных (пароль) или в ситуации, когда отображение символа нажатой клавиши может повредить текущее содержимое экрана. Очень часто эту функцию используют в качестве задержки работы программы до нажатия какой-либо клавиши.
Функция getche обеспечивает ввод символа, соответствующего нажатой клавише с выдачей эхо-сигнала.
Обе функции обращаются к буферу клавиатуры. Если к этому моменту буфер пуст, то происходит ожидание нажатия клавиши. Считанный символ из буфера клавиатуры выталкивается. Однако клавиши на клавиатуре разные. Большая их часть связана с отображаемыми символами – буквами, цифрами, знаками препинания и т.п. После их нажатия обращение к функциям getch/getche приводит к считыванию соответствующего кода ASCII. В частности, к "отображаемым" клавишам относятся клавиши Esc (код 27), Enter (код 13), комбинация Ctrl+Z (код 26 – признак конца файла). Но на клавиатуре присутствует ряд клавиш, с которыми ассоциируются управляющие символы, не представленные в таблице ASCII. К ним, в частности, относятся функциональные клавиши F1, F2, ..., стрелки управления курсором, клавиши Insert и Delete и др. От их нажатия в буфер клавиатуры поступает двухбайтовый код, содержащий в старшем байте 0, а в младшем байте так называемый scan-код (некий порядковый код, приписанный каждой клавише). В этом случае первое обращение к функциям getch/getche приводит к считыванию нулевого кода, а повторное обращение возвращает scan-код ранее нажатой клавиши. Таким образом, для анализа кода нажатой управляющей клавиши к функциям getch/getche приходится обращаться дважды (предварительно следует убедиться в том, что первое обращение возвратило 0).
Функция gets (от get string – дай строку) позволяет ввести в символьный массив текстовое значение, содержащее пробелы:
#include <stdio.h> #include <conio.h> void main() { char str[80]; gets(str); printf("\nstr=%s",str); getch(); }
При потоковом вводе со стандартного устройства stdin можно запросить заданное количество k символов, среди которых может встретиться и пробел:
cin.getline(str,k);
При этом можно ввести не более чем k-1 символ, т.к. нужно помнить о резервном байте для признака окончания строки. Если строка, набираемая пользователем, содержит более чем k-1 символ, то продолжение строки будет проигнорировано. И даже последующий оператор ввода не сможет им воспользоваться. Если строка ввода содержит меньше, чем k-1 символ, то она будет введена целиком. Более того, с помощью еще одного параметра, – символа завершения операции, можно досрочно прекратить ввод:
cin.getline(str,k,'Q');
Если в строке ввода будет досрочно обнаружен символ 'Q', то он уже не вводится.
Следует упомянуть еще одну функцию форматного ввода cscanf, ориентированную на работу с конкретным устройством – клавиатурой. Обращаются к ней точно так же как и к функции scanf, но они не дублируют друг друга. И вот почему. Дело в том, что стандартные устройства ввода ( stdin ) и вывода ( stdout ) могут быть подменены другими носителями информации (например, файлами или принтером). А ввод с клавиатуры и вывод на экран дисплея, образующих в совокупности консоль (пульт) оператора, переназначить нельзя.