Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 152
Текст из файла (страница 152)
Нужно или проверять состояние потока ввода Я 21.3 3) перед использованием предположительно считанных данных, или задечйсгвовать исключения Я 21.7). Формат ввода учитывает национальные особенности Я 21.7). По умолчанию значения !гие и/а(зе для типа Ьоо( представляются соответственно как 1 и О. Целые числа и числа с плавающей точкой должны быть в том виде, как принято в программах на С++. Заданием ЬазеЯеЫ Я 21.4.2), можно прочесть 0123 как восьмеричное число с десятичным значением !Ц, а Ох/)скак шестнадцетеричное число с десятичным значением 255.
Формат для считывания указателей полностью зависит от реализации (посмотрите, как зто делается в вашей реализации). Удивительно, но нет функции-члена» для чтения символа. Причина здесь в том, что» для символов можно реализовать при помощи операции ввода символа де!() Глава 21. Потоки 682 (з 21.3А), так что ей нет необходимости быть членом.
Из потока лзы можем считать символ в символьный тип, ассоциированный с данным потоком. Если это символьч ный тип сЬаг, мы можем также считать данные в з!апет! сЬаги ипзщпег(сЬаг. 1етр1а!е<с1авв СЬ, с!авя Тг Ьавк !з!геат<СЬ, Тг>й орете!ог» (Ьавк !з!геат<СЬ, Тг й, СЬ&); !етр1а!е<с1авв Тг> Ьаз!с !з!геат<сЬаг, Тг>& орега!ог» (Ьаз!с 1з!геат<сааг, Тг й, ипз!еле<(сЬаг&); !етр1а!е<с1азз Тг Ьазк !зйеат<сЬаг, Тг>& орега!ог» (Ьав!с !з!геат<сЬаг, Тг>й, в!ппег! сЬаг&) С точки зрения пользователя не важно, является ли операция» членом или нет. Как и остальные операторы», зти функции пропускают символы-разделители.
Например: ооЫ/() ( сЬаг с, ст» с, Таким образом в с будет помещен первый символ не-разделитель из свп. Кроме того, мы можем считывать в массив символов: !етр!а!е<с!азв СЬ, с!азя Тг Ьаз!с Ы!гзат<сЬог, Тг>йорега!ог» (Ьавк !з!геат<СЬ, Тг>й, СЬ'); !егир!а!е<с1авв Тг> Ьаз!с !з!геат<сЬаг, Тг>йорегагог» (Ьаз!с !з!геат<сЬиг, Тг>&, ипз(еле<(сЬаг'), !етр(а!я<с!авв Тг Ьавк 1з!геат<сЬаг, Тг й орега!ог» (Ьаз!с !з!геат<сЬаг, Тг>й,з!апет(сЬаю ); Эти операции сначала пропускают символы-разделители. Потом они считывают в массив-операнд, пока не встретят символ-разделитель или конец файла. И наконец, они вставляют признак конца строки — О.
Ясно, это открывает широкие возможности для переполнения, так что обычно лучше считывать в строку я!г!пд'(~ 20.3.5). Однако вы можете определить максимальное число символов, считываемых оператором»: !ззв!О!Ь (п) определяет, что следую!цее» над !з считает в массив максимум и — 1 символов. Например: ооЫд () ( сЬаг о(4); с!и кЫЬЬ (4), с!п»о, сои! « "о= «о «еп<!1; Таким образом в о счгпается не более трех символов, и добавится признак конца строки О. Установка юЫ!Ь () для 1з!геат влияет только на непосредственно следующую за ней опереди!о» считывания в массив и не затрагивает считывание в переменные других типов.
ббЗ 21.3. Ввод 21.3.3. Состояние потока Каждый поток (!з1геат или оз1 еат) имеет связанное с ним состояние. Установкой и соответствующей проверкой этого состояния вылавливаются ошибки и нестандартные условия. Состояние потока вводится в баас !оз, базовом классе класса Ьаяс к(геат, в <гозгч 1етр!а1е с!акк СЬ, с1акк те = суаг 1га!!к<С!г» с1аккуаис гок:риЫ!с!ок Ьазе( риЫ!с //- Ьоо(увод () сопк1; //следуюи1ая операция можепг выполниться Ьоо! ео/() сопк1; //виден конец ввода Ьоо!/а1! () сопЯ; // следующая операция не виполнится Ьоо! Ьад () сопк1; //поток испорчен гоЯаге гдк1а1е () сопк1; // получение флагов соспгояния ввода/вывода ооЫс!еаг(1окга1е/=апас(Ь!(у Оустановкофлиговгостоянияввода/завода ооЫке1к1и1е(!озги1е/) //добавление/кфлагомготпояния ( с!еаг (гдк1а1е () )/); ) орега1огиоиГ () сопЯ; // не ноль, если !/а!! О Ьоо! ореги1од () сопк1( ге1игп/а!1(); ) //.— ); Если установилось состояние даос! (), значит предыдущие операции успешно выполнились.
Если установилось состояние хгоог! (), может выполниться следующий ввод, в противном случае он не выполнигся. Применение операции ввода к потоку, находящемуся не в состоянии даос( (), — это нулевая операция по отношению к считываемой переменной. Если мы пытаемся прочитать в переменную о, и операция не выполняется, значение и должно остаться неизменным (оно не изменяется, если о — это переменная одного пз тех типов, которые обрабатываготся функциями-членами классов !з1геат или оз1геагп).
Различие между состояниями/а!! () н Ьагг () очень незна пп ельно. Когда поток в состоянии /а(! (), но одновременно не в Ьас((), считается, что он не испорчен (но символы могут быть потеряны). Когда он в состоянии Ьас( (), ни в чем нельзя быть уверенным. Состояние потока представляется набором флагов. Как и большинство констант, выражающих поведение потока, зти флаги определены в !оз базе — базовом классе класса Ьаз!с гока с!аккгок Ьаке( риЫгс 1уреде/!тр!етепгааоп г/еугпей2 !оЯа1е; к1аг!с сопз1 !оЯа1е ЬадЫ1, // поток испорчен ео/Ы1, //виден конец файла /а1!Ы1, //следующая операция невиполнится уоодЫ1; // уоодЫ1==0 Глава 21. Потоки 684 Флагами состояния ввода/вывода можно непосредственно манипулировать.
Например: оойЩ ( лоз Ьаяез!оя!а1е з = с1п.гдя1а1е (); // возвращает набор битов // состояния вводо/вывода (~ (я й !оз ЬаяезЬадЫ1) ( // возлюхсно, символы в сгп потеряны Когда поток используется как условие, состояние потока проверяется функциями орега1ог ооИ* () или орега1ой (). Проверки считаются успев!ными, только если со- стояние потока есть (/а!! () и/а!! () соответственно. Например, универсальную функ- цию копирования можно написать так: 1етр1а1е<с!азя Т> оо!д !опору (!з1геатй !з, оз1геатй оз) ( Т Ьи/; тЫ!е (1з> Ьи/) оя«Ьи/« "чп'; Операция !з»Ьи/ возврагдает ссылку на 1з, которая проверяется вызовом Ьв орега1ог оо(ал* (). Например: оо!д/(!я!ге а т й ! 1, Игеа т й л2, (ясгеатй !8, !з1геа т & л4) ( 21.3.4.
Ввод символов Оператор» предназначен также для форматированного ввода, то есть для считыва- ния обьектов ожидаемого типа и в ожидаемом формате. Там, где зто нежелательно, и мы хотим считывать символы как символы, а потом проверять их, мы пользуемся функциями уе1 (): 1етр!а1е<с!аяз СЬ, с!аяя Тг= сЬаг !га11з<СЬ > с!аяя Ьая!с !ясгеат, Ыг!иа! риЫ1с Ьаис лоз<СЬ, Тг> ( риЫлс: //-. // нефорллатарованный ввод: // число символов, считанных последней уе!(! // считывание одного СЬ // считывпнис одного СЬ в с ) 0- сгп.яе1яга1е (1оя базе: Ха1!Ь!!); 0- !осору<сотр!ех> (!1, сои!) 1осору<доиЫе> (с2, сои!).
юсору<сЬаг> (!3, сои!); 1осору<явтпу (л4, сои!) з1геатя1яе усоип1 () сопя!; лп1 1уре уе1 (); бал!с 1яггеатй уе! (СЬ& с); // копирование коллплексных чисел // копирование чисел типо до И!е // копировпние сваи // копирование слов, разделенных //сил!вололш-разделшпелями 685 21.3. Ввод Ьа ' !я1 еатйуе1(СЬ'р,я1геатя!ееп); //завершающий символ — новая строка Ьая1с шп еатй уе1 (СЬ'р, яггеатя!ее и, СЬ 1егт); Ьая!с !я1геатйде1!1пе (СЬ'р,я1геатя!зеп) //завершиющийсинвол — новпльтроко Ьая!с !яггеатй ае1 (СЬ* р, яггеатя!зе и, СЬ 1егт); Ьаясс !яггеатй !апоге (з1геатяиее и = 1, тг 1уре1 = Тт.:.ео/(!) Ьая!с !яггеатйгеад(СЬ*р, я1геатя!ее и); //чтение не более п снмволов Кроме того, в <я1г(лйь» предлагается функция де1/!пе () для стандартных строк (ч 20.3.15).
Функции уе1 () и йе1!!пе () обращаются с символами-разделителями точно так же, как н с другими символами. Они предназначены для операций ввода, где заранее не предполагается, что означают введенные символы. Функция 1я1геат::уе1 (сйагй) считывает один символ в свой аргумент. Например, программу посимвольного копирования ввода можно написать так: 1п1 та!и () ( айаг с; шЫ!е (с! пуе! (с)) сои1ри1 (с) сбаг Ьи/(100). с!и» ЬиХ //не очень хорошо: когда-нибудь переполнится сглаз! (ЬиЯ 100, '~п'); //безопасно Если функции де1 () или уе1!!пе () не удается считать и удалить из потока хотя бы один символ, вызывается яе1я1а1е (/а!!Ы1), так что последующее чтение из потока завершится неудачей [или генерацией исключения, ~ 2Е3.6). Если встречен завершающий символ, он остается первым несчитанным символом в потоке.
Никогда не обращайтесь к де1 () два раза подряд, не удалив завершающий символ. Например: оо!6яиЫ!е еггог() ( сбаг Ьи/(266); тЫ!е (сьп) ( с1п.уе1 (Ьи!; 266); сои! «Ьи/ //считывание строки О вывод строки. Ошибка: забыли удолшпь '~п' из ст // следующий вызов ае! !) будет неудачен ) Функция с тремя аргументами я.уе1(р, и, 1егт) считывает не более и-1 символов в р[0)..р[п-2). Вызов уе1 () всегда помещает 0 после размещенных в буфере символов, так что р должен указывать на массив, содержащий не менее чем п символов. Третий аргумент, 1егт, определяет завершающий символ. Типичное использование функции де1() с тремя аргументами — считывание «строки» в буфер фиксированного размера для дальнейшего анализа.
Например: оо!д/'() ( 686 Глава 21. Потоки Этот пример показывает, что лучше использовать Хе!1!пе (), а не де1 (). Функция де!1!не () ведет себя так же, как и соответствующая ае1 (), но удаляет из !з1геат встреченный завершакпцнй символ.
Например: оо!д/() с!ьагюогд(МАХ %0ЯЩ (МАХ ЕЕй!Е~! //МАХ 1ГгОЕдмассив изМАХ Е!ХЕ /! символов в каждом !п1 1=0; тЫ!е (с!п.ае1!!пе (свогд!!»ч),МАХ Е!й!Е, '~п') 8,8 !<МАХ !»»ОИ!), //- Когда эффективность не играет большой роли, лучше считывать в строку запад(ез 3.6. 8 20,3.15). Тогда не возникнет обычных проблем с распределением памяти и переполнением. Однако функции йе1 (), де1Ипе () и геас( () нужны, чтобы реализовать такие возможности высокого уровня. Относительно запутанный интерфейс — это цена, которую мы платим за скорость, за избавление от необходимости повторно просматривать вход, выясняя, чем закончилась операция ввода, за возможность надежного ограничения числа считываемых символов и т. д.
Обращение к геас((р, и) считывает максимум и символов в р,'О)..р(п-1). Функция геас( () не полагается на завершающий символ и не ставит в конец полученной строки О. Следовательно, она действительно может считать и символов (а не п-! ). Другими словами, она просто считывает символы и не пытается превратить считанное в С-строку. Функция !Хаосе () считывает символы так же, как и ! еас! (), но нигде не хранит их. Как и геас( (), она на самом деле считывает и символов (а не п-1).