20.2.1. Строковый ввод
20.2.1. Строковый ввод
Считывание можно производить как в C-строки, так и в объекты класса string. Мы рекомендуем пользоваться последними. Их главное преимущество – автоматическое управление памятью для хранения символов. Чтобы прочитать данные в C-строку, т.е. массив символов, необходимо сначала задать его размер, достаточный для хранения строки. Обычно мы читаем символы в буфер, затем выделяем из хипа ровно столько памяти, сколько нужно для хранения прочитанной строки, и копируем данные из буфера в эту память:
#include iostream
#include string.h
char inBuf[ 1024 ];
try
{
while ( cin inBuf ) {
char *str = new char[ strlen( inBuf ) + 1 ];
strcpy( str, inBuf );
// ... сделать что-то с массивом символов str
delete [] str;
}
}
catch( ... ) { delete [] str; throw; }
Работать с типом string значительно проще:
#include iostream
#include string.h
string str;
while ( cin str )
// ... сделать что-то со строкой
Рассмотрим операторы ввода в C-строки и в объекты класса string. В качестве входного текста по-прежнему будет использоваться рассказ об Алисе Эмме:
Alice Emma has long flowing red hair. Her Daddy says
when the wind blows through her hair, it looks almost
alive, like a fiery bird in flight. A beautiful fiery
bird, he tells her, magical but untamed. " Daddy, shush,
there is no such creature," she tells him, at the same time
wanting him to tell her more. Shyly, she asks, " I mean,
Daddy, is there?"
Поместим этот текст в файл alice_emma, а затем перенаправим на него стандартный вход программы. Позже, когда мы познакомимся с файловым вводом, мы откроем и прочтем этот файл непосредственно. Следующая программа помещает прочитанные со стандартного ввода слова в C-строку и находит самое длинное слово:
#include iostream.h
#include string.h
int main()
{
const int bufSize = 24;
char buf[ bufSize ], largest[ bufSize ];
// для хранения статистики
int curLen, max = -1, cnt = 0;
while ( cin buf )
{
curLen = strlen( buf );
++cnt;
// новое самое длинное слово? сохраним его
if ( curLen max ) {
max = curLen;
strcpy( largest, buf );
}
}
cout " Число прочитанных слов "
cnt endl;
cout " Длина самого длинного слова "
max endl;
cout " Самое длинное слово"
largest endl;
}
После компиляции и запуска программа выводит следующие сведения:
Число прочитанных слов 65
Длина самого длинного слова 10
Самое длинное слово creature,"
На самом деле этот результат неправилен: самое длинное слово beautiful, в нем девять букв. Однако выбрано creature, потому что программа сочла его частью запятую и кавычку. Следовательно, необходимо отфильтровать небуквенные символы.
Но прежде чем заняться этим, рассмотрим программу внимательнее. В ней каждое слово помещается в массив buf, длина которого равна 24. Если бы в тексте попалось слово длиной 24 символа (или более), то буфер переполнился бы и программа, вероятно, закончилась бы крахом. Чтобы предотвратить переполнение входного массива, можно воспользоваться манипулятором setw(). Модифицируем предыдущую программу:
while ( cin setw( bufSize ) buf )
Здесь bufSize – размер массива символов buf. setw() разбивает строку длиной bufSize или больше на несколько строк, каждая из которых не длиннее, чем bufSize - 1.
Завершается такая частичная строка двоичным нулем. Для использования setw() в программу необходимо включить заголовочный файл iomanip:
#include iomanip
Если в объявлении массива buf размер явно не указан:
char buf[] = "Нереалистичный пример";
то программист может применить оператор sizeof, но при условии, что идентификатор является именем массива и находится в области видимости выражения:
while ( cin setw(sizeof( buf )) buf )
Применение оператора sizeof в следующем примере дает неожиданный результат:
#include iostream
#include iomanip
int main()
{
const int bufSize = 24;
char buf[ bufSize ];
char *pbuf = buf;
// если строка длиннее, чем sizeof(char*),
// она разбивается на несколько строк
while ( cin setw( sizeof( pbuf )) pbuf )
cout pbuf endl;
}
Программа печатает:
$ a.out
The winter of our discontent
The
win
ter
of
our
dis
con
ten
t
Функции setw() вместо размера массива передается размер указателя, длина которого на нашей машине равна четырем байтам, поэтому вывод разбит на строки по три символа.
Попытка исправить ошибку приводит к еще более серьезной проблеме:
while ( cin setw(sizeof( *pbuf )) pbuf )
Мы хотели передать setw() размер массива, адресуемого pbuf. Но выражение
*pbuf
дает только один символ, т.е. объект типа char. Поэтому setw() передается значение 1. На каждой итерации цикла while в массив, на который указывает pbuf, помещается только нулевой символ. До чтения из стандартного ввода дело так и не доходит, программа зацикливается.
При использовании класса string все проблемы управления памятью исчезают, об этом заботится сам string. Вот как выглядит наша программа в данном случае:
#include iostream.h
#include string
int main()
{
string buf, largest;
// для хранения статистики
int curLen, // длина текущего слова
max = -1, // максимальная длина слова
cnt = 0; // счетчик прочитанных слов
while ( cin buf )
{
curLen = buf.size();
++cnt;
// новое самое длинное слово? сохраним его
if ( curLen max )
{
max = curLen;
largest = buf;
}
}
cout "Число прочитанных слов " cnt endl;
cout "Длина самого длинного слова " max endl;
cout "Самое длинное слово " largest endl;
}
Однако запятая и кавычка по-прежнему считаются частью слова. Напишем функцию для удаления этих символов из слова:
#include string
void filter_string( string &str )
{
// элементы, подлежащие фильтрации
string filt_elems( "",?." );
string::size_type pos = 0;
while (( pos = str.find_first_of( filt_elems, pos ))
!= string::npos )
str.erase( pos, 1 );
}
Эта функция работает правильно, но множество символов, которые мы собираемся отбрасывать, "зашито" в код. Лучше дать пользователю возможность самому передать строку, содержащую такие символы. Если он согласен на множество по умолчанию, то может передать пустую строку.
#include string
void filter_string( string &str,
string filt_elems = string("",."))
{
string::size_type pos = 0;
while (( pos = str.find_first_of( filt_elems, pos ))
!= string::npos )
str.erase( pos, 1 );
}
Более общая версия filter_string() принимает пару итераторов, обозначающих диапазон, где производится фильтрация:
template class InputIterator
void filter_string( InputIterator first, InputIterator last,
string filt_elems = string("",."))
{
for ( ; first != last; first++ )
{
string::size_type pos = 0;
while (( pos = (*first).find_first_of( filt_elems, pos ))
!= string::npos )
(*first).erase( pos, 1 );
}
}
С использованием этой функции программа будет выглядеть так:
#include string
#include algorithm
#include iterator
#include vector
#include iostream
bool length_less( string s1, string s2 )
{ return s1.size() s2.size(); }
int main()
{
istream_iterator string input( cin ), eos;
vector string text;
// copy - это обобщенный алгоритм
copy( input, eos, back_inserter( text ));
string filt_elems( "",.;:");
filter_string( text.begin(), text.end(), filt_elems );
int cnt = text.size();
// max_element - это обобщенный алгоритм
string *max = max_element( text.begin(), text.end(),
length_less );
int len = max-size();
cout "Число прочитанных слов "
cnt endl;
cout "Длина самого длинного слова "
len endl;
cout "Самое длинное слово "
*max endl;
}
Когда мы применили в алгоритме max_element() стандартный оператор "меньше", определенный в классе string, то были удивлены полученным результатом:
Число прочитанных слов 65
Длина самого длинного слова 4
Самое длинное слово wind
Очевидно, что wind – это не самое длинное слово. Оказывается, оператор "меньше" в классе string сравнивает строки не по длине, а в лексикографическом порядке. И в этом смысле wind – действительно максимальный элемент. Для того чтобы найти слово максимальной длины, мы должны заменить оператор "меньше" предикатом length_less(). Тогда результат будет таким:
Число прочитанных слов 65
Длина самого длинного слова 9
Самое длинное слово beautiful
Упражнение 20.2
Прочитайте из стандартного ввода последовательность данных таких типов: string, double, string, int, string. Каждый раз проверяйте, не было ли ошибки чтения.
Упражнение 20.3
Прочитайте из стандартного ввода заранее неизвестное число строк. Поместите их в список. Найдите самую длинную и самую короткую строку.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Ввод
Ввод Как мы уже видели, присвоение значений переменным может осуществляться явно или с помощью вывода некоторой программы. Команда read предоставляет удобный способ присвоить переменным значения, считанные из стандартного потока ввода. Это может быть строка, введенная
ЛЕКЦИЯ № 5. Строковый тип данных
ЛЕКЦИЯ № 5. Строковый тип данных 1. Строковый тип в Pascal Последовательность символов определенной длины называется строкой. Переменные строкового типа определяются путем указания имени переменной, зарезервированного слова string, и возможно, но не обязательно указания
1. Строковый тип в Pascal
1. Строковый тип в Pascal Последовательность символов определенной длины называется строкой. Переменные строкового типа определяются путем указания имени переменной, зарезервированного слова string, и возможно, но не обязательно указания максимального размера, т. е. длины
Ввод дат
Ввод дат Печатать буквальные значения дат можно почти в любом виде, какой только возможен. Например, допустимо любое из следующих представлений:#09/1/1998##Sep 25, 93##Janua 9 1905Если редактор Visual Basic распознает введенные вами данные как допустимое значение даты, эти данные будут
Ввод мышью
Ввод мышью GetDoubleClickTime Функция GetDoubleClickTime извлекает текущее время двойного щелчка мыши. Двойной щелчок - это серия двух щелчков клавиши мыши; второй щелчок происходит в течение заданного времени после первого. Время двойного щелчка - это максимальное число миллисекунд,
3.4.1. Встроенный строковый тип
3.4.1. Встроенный строковый тип Как уже было сказано, встроенный строковый тип перешел к С++ по наследству от С. Строка символов хранится в памяти как массив, и доступ к ней осуществляется при помощи указателя типа char*. Стандартная библиотека С предоставляет набор функций
Ввод координат
Ввод координат Когда программа AutoCAD запрашивает точку, команда ожидает ввода координат какой-либо точки текущего рисунка. В AutoCAD может быть включен контроль лимитов рисунка, осуществляемый командой LIMITS. В этом случае, если введенная точка выходит за пределы рисунка, AutoCAD
Ввод с клавиатуры
Ввод с клавиатуры Чаще всего эскиз модели (детали, здания) создается на бумаге, а уже в электронный вариант переносится сформировавшаяся идея. Поэтому, работая над новым чертежом на компьютере, необходимо указывать точные координаты элементов модели.Абсолютные
1.1.3 Ввод
1.1.3 Ввод Следующая (довольно многословная) программа предлагает вам ввести число дюймов. После того, как вы это сделаете, она напечатает соответствующее число сантиметров.#include «stream.h»main() (* int inch = 0; // inch – дюйм cout «„ „inches“; cin “» inch; cout «„ inch; cout «« " in = "; cout «« inch*2.54; cout «« «
8.4 Ввод
8.4 Ввод Ввод аналогичен выводу. Имеется класс istream, который предоставляет операцию »» («взять из») для небольшого мнжества стандартных типов. Функция operator»» может опредляться для типа, определяемого
11. Строковый тип в Pascal. Процедуры и функции для переменных строкового типа
11. Строковый тип в Pascal. Процедуры и функции для переменных строкового типа Последовательность символов определенной длины называется строкой. Переменные строкового типа определяются путем указания имени переменной, зарезервированного слова string, и возможно, но не