Г. Шилдт - Полный справочник по C++ (1109478), страница 42
Текст из файла (страница 42)
Как упоминалось ранее, применение функции пеев<) может привести к переполнению массива, в который записываются символы, поскольку она не предусматривасз проверки возможного выхола инлскса массива за прелслы допустимого диапазона. При использовании потока ясохо функция говея <) представляет собой разумную альтернативу, поскольку она выполняе~ проверку индекса массива и предотвращает его переполнение. Остается лишь одно неудобство: функпия яоееаО, в отличие от функции деев(), не упадает из файла символ перехола на новую строку, поэтому его необходимо улалять вручную, как показано в следуюшем примере.
№гпс1сс(е <ясс]зо.б> №(пс1ебе <яххьпд.б> хпг гса(п(еоЫ) ( снах ясх(ВО] хпх х; рхьпх((" Введите строку: "') Гдехя<яхх, 10, ясс(ьп]; удаляем символ перси ьдя ис ис'уи строку, если он есть */ — яхх1еп(ясх)-1; 1№(ясх(1]=='~п') зсх(1] = '10'; рх№псх("Результат: Ъя", яхх) хехихп 0; Часть (. Основы языка С+»-: подмножество С Имейте в виду, что потоки веалп, веаопе и веетекк не являются переменными в обшепринятом смысле этого слова и им ничего нельзя присвоить с помошью функции Лорепо.
Кроме того, они открываются и закрываются автоматически, поэтому не следует пытаться их закрывать самостоятельно. Связь с консольным вводом-выводом Между консольным и файловым вводом-выводом существует небольшое различие. функции консольного ваала-вывода, описанные в главе 3, работают с потоками веаз.п или веаопе. По существу, функции консольного ввода-вывода просто являются специальными версиями своих файловых аналогов и включены в язык лишь для улобства программистов.
Как описано в предыдушем разделе, консольный ввод-вывод можно осуществлять с помощью функций файловой системы. Однако для вас может оказаться сюрпризом, что файловые операции ваала-вывода можно выполнять с помощью консольных функций, например функции ркапея()! Это возможно благодаря тому„что консольные функции ввода-вывола работают с потоками вин.п и ее()опе. Если операционная среда позволяет перенаправлять потоки, патоки ведап и еедопе можно связать не с клавиатурой и экраном, а с лругими устройствами. Рассмотрим следуюшую программу.
ВТпс1ис)е <вес)уо.)1> Рпс пайп(тоЫ) ( спет в( с(80); ртзпсг("Введите строку: "); деев(все)г ртлпСГ(ввс); теео сп 0; Предположим, что эта программа называется ТЕБТ. При нормальном выполнении эта про(рамма выводит на экран приглашение, считывает с клавиатуры строку и выводит ее на экран. Однако в среле, допускшошсй перенаправление потоков, стандартные потоки вЫ(п и ввйоае можно связать с файлами. Например, в операционных системах 00$ и ЪЧпс(ов з программу ТЕВТ можно выполнить с помошью следуюшей команлной строки.
я ТЕЯТ > ОЦТРЦТ В этом случае результаты работы тевт будут записаны в файл оцтвцт. Если для запуска программы применить командную строку $ ТЕБТ < 1НРОТ > ООТРЦТ, поток вес)зп булет связан с файлом хнвцт, а результа~ы — направлены в файл ацтвцт. После завершения работы программы потоки возврашаются в стандартное состояние. Применение функции йеорепО для перенаправления стандартных потоков Для перенаправления стандартных потоков можно применять функцию якеореп() .
Зта функция связывает сушествуюший поток с новым файлом. Таким образом, с ее помошью сганлартиый поток можно связать с новым файлом. Ее прототип имеет следующий вна. Глава 9. Файловый вва)ьвывод $ Ртье *гсеореп(сопле ссаг *ымя федю, сопле с)зат *лежке, Ртье 'поток) Здесь параметр имя файла является указателем на строку, содержашую имя фа(гла, связанного с заданным лотокозе Файл открывается в режиме, заданном параметрол1 режим.
который может иметь те же значения, что и параметр режим в функции дорепО. В случае успешного выполнения функция якеореп() возврашает указатель файла лоток, в противном случае она возврашает нулевой указатель. В следуюшеи программе функция якеореп() перенаправляет стандартный поток век)оис в файл оптрпт. ()зпс1цс)е <ввозе.Ь> Тпс гкаап(еоЫ) с)зах все(80!; тхеореп("00ТРПТ", "и", еМоие)г рк(пег("Введиее строку: деев(вг с); рттпст(вет)г геситп 0; ) Как правило, перенаправление стандартных потоков с помошью функции яее- орепО оказывается полезным в особых ситуациях, например„при отладке.
Однако этот способ менее эффективен, чем применение функций деева() и яиз..зсе <). Часть ). Основы языка С++: подмножество С Полный Препроцессор и щмментерии спр 2ВОчник по В 1 ! Ф В программы на языке С/С++ можно включать различные инструкции, регламентируюшие работу компилятора. Эти инструкции называются дирекглиоаеи лрелронесспра (ргергосеззог йгесг1уез).
Хотя они не являются частью языков С или С++, их применение позволяет расширить возможности программ. Кроме этих лиректив. в главе рассглатриваются кол1ментарии, : ~ Препроцессор Прежде чем приступить к описанию препроцессора, вспомним его историю. Препроцессор языка С++ унаследован от языка С. Более того, он практически совпалает с препроцессором языка С.
Единственное различие между ними заключается в степени их важности. В языке С каждая директива препроцессора являешься необходимой В языке С++ некоторые избыточные лирективы компенсируются элементами самого языка. Фактически одной из долговременных целей языка С++ является полное исключение препроцессора.
Однако в настоящее время директивы препроцессора применяются очень часто, и в обозримом будугцем это положение не изменится. Препроцессор содержит следуюшие директивы, ((Двдхпв ввккок $1пе1пйв ев11Е вЕЕ ((11 па ((впй1 Е ((1ЕпгтеЕ НппствЕ (гв1вв е1ЕствЕ $ркаджа Все лирективы препроцессора начинаются со знака Н. Кроме того, каждая директива должна располагаться в отдельной строке программы. Например, фрагмент программы, приведенный ниже, неверен. $ Вьпс1пс(е <ягс(до.н> Вдпс1пг(е <вЫ11Ь.Ь> ~ Директива Фбейпе Вс(еЕЕпе ьВРТ 1 Воегупе К10НТ О Эти директивы вынудят компилятор заменять слова ьжжт и кхант в исходном файле значениями 1 и 0 соответственно.
Например, следуюший оператор выводит на экран Числа О 1 2. й ерсупСЕ( "ес( ес( ег(", Дтопт, ЬКВТ, Г,ВУТ+И; Часть!. Основы языка С++: подмножество С Директива йдвеепв определяет идентификатор и последовазельносзь символов, которая заменяет его в тексте программы. Этот идентификатор называется иненви макроса, а процесс замены — лгакролодсталовкой (тассо гор(асегпепгу Обший вид этой директивы таков.
НпеЕЕпе имл макроса последооглельяость символов Обратите внимание на то, чзо эта лиректива не содержит точки с запятой. Между идентификатором и последовательностью символов может располагаться сколько уголно пробелов, но сама последовательность должна заканчиваться символом перехода на новую строку. Например, если вы хотите использовать вместо единицы слово ьклт, а вместо нуля — слово плант, необходилю обьявить две директивы (ГдеЕ1пе.
Если в програмлзе определено имя макроса, его можно использовать лля определения другого макроса. Например, в приведенном ниже фрагменте программы определяются значения идентификаторов бие, тио н тилле. Вз)егьпе ОИЕ 1 ()г)е1зпе ТИО ОИЕ+ОИЕ Вс)е11пе тНКЕЕ ОИЕ+1ИО Макроподстановка означает простую замену идентификатора последовазельностыо символов, связанной с ним. Следовательно, при необходимости с помошью директивы ()аел1пе можно определить станлартное сообшение об ошибке Вдейьпе Е ИЯ "стандартная ошибка при вводехп" з /* */ ртзпе1(Е ИЯ)з Каждый раз, когда в исходном тексте программы встретится идентификатор е ив, компилятор подставит вместо него строку "стандартная ошибка при вводехп'*.
С точки зрения колзпилятора, приведенный выше вызов функции рк1пеЕ() выглядит следуюшилз образом. $ рг1пс1("стандартная сшибка при ввсдезп") Если идентификатор является частью строки, заключенной в кавычки, макроподстановка не произволится. Например, фрагмент программы Вг)ейзпе ХУЕ это проверка з ртзпе1("ХУЕ")з выведет на экран не строку "ето проверка", а символы ххе. Если последовательность символов занимает несколько строк, в конце каждой из них следует поставить обратную косую черту. ()дейзпе ЬОИО ЯтК1ИО "в этом примере используется очень длинная строка" Для названия идентификаторов программисты обычно используют прописные буквы. Это позволяет легко обнаружнвазь макроподстановки в тексте программ.
Кроме того, лучше помешать все директивы ()з)е11пе в самом начале исходного файла или в отдельном заголовочном файле, а не разбрасывать их по всей программе. Макросы часто применяются лля определения имен констанз, всгречаюшихся в програмлзе. Допустим, в программе определен массив, который используется в нескольких лзодулях. Крайне нежелательно "зашивать*' его разлзер в текст программы. Вместо этого следует применить макроподстановку, используя директиву ((зтеззпе. Тогда лля того, чтобы изменизь размер массива, лостаточно будет модифицировать одну строку программы, содержашую директиву ()беязпе, а не выискивать все ссылки на размер массива в тексте.
После этого программу необхолнмо переколзпилировать. Рассмотрим пример. Фс)еЕзпе ИАХ Я1ЕЕ 100 /* ... */ 11оае Ьа1апсе(ИАХ Я1ЕЕ); / */ 1оз'(з.=Оз з«и/зх ятхез 1++) рх'зпс1('ь1", Ьа1апсе(з))з /* */ йог(1=0з 1«ИАХ Я1ЕЕз 1++) х =+ Ьа1апсе[з)з Поскольку разлзер массива ьа1епсе определяется идентификатором илх Яхве, то лля того, чтобы опрелелнть новый размер массива, достаточно просто молифицировать Глава 10. Препрацессор н комментарии опрелеление макроса. При повторной компиляции программы все последу«ощие ссылки на этот идентификатор будут обновлены автоматически. «~~',~1(зя)зз ~аду В языке с++ есть болев праспюй способ определения канствнп«, основанный на вее<ЬЙЙИ применении ключевого аювв саовс. Он описан в час«пи П.
Определение функций в виде макросов Директива Ме(ее1пе обладает еше одним мощным свойством: макрос может иметь форл)альные аргументы. Каждый раз, когда в тексте программы встречается имя макроса, его формальные аргументы заменяются фактическими. Эгг«т вид макроса называется функциональным (йпспоп-11)«е «пасто). Раасн«стрик«пример. Лзпс1аде <вгдго.п> Лдебзпе ЬВБ(а) (а)<0 ? †(а) « (а) ьпс а«а1п! чоЫ) ( ргьпгб("'а)«в об -1 апд 1« $д вд", АВЯ(-1), АБЯ(1))« При компиляции программы опрелсление макроса а булез заменено значениями — 1 и 1. Скобки, в которые заключен макрос а, гарантируют правильную подстановку.