246071-Либерти-Освой-самостоятельно-С-за-21-день (852741), страница 85
Текст из файла (страница 85)
В следующей строке данныеобъектазаносятсявфайл.В строке 37 файл закрывается, после чего повторно открывается для чтения в двоичномрежиме в строке 39. Создается второй объект Animal, значения обоих переменных-членовкоторого равны 1. В строке 51 данные из файла считываются в новый объект Animal, замещаясобойтекущиезначенияобъекта.Установкапараметровввода-выводаспомощьюкомманднойстрокиМногие операционные системы, такие как DOS и UNIX, позволяют пользователювыполнятьустановкинекоторыхпараметровпризапускепрограммы.Этиустановкиназываютсяопциямикоманднойстрокии,какправило,отделяютсядруготдругапробелами,например:SomeProgramParam1Param2Param3Эти параметры не передаются напрямую в функцию main(). Вместо этого функция main()программы может принимать два других параметра. Первый — это целочисленное значение,указывающее число аргументов командной строки с учетом имени программы.
Поэтомуминимальное значение этого параметра равно единице (задается по умолчанию). Дляпоказанной выше командной строки значение параметра будет равно четырем. (ИмяSomeProgramплюстрипараметравсуммедаютчетыреаргументакоманднойстроки.)Второй параметр, передаваемый функции main(), — это массив указателей на строкисимволов. Так как имя массива является постоянным указателем на первый элемент массива,можно объявить этот аргумент как указатель на указатель типа char, указатель на массивсимволовилимассивмассивовсимволов.Обычнопервыйаргументназываетсяargc(argumentcount—количествоаргументов),однаковы можете присвоить ему любое имя, которое вам нравится. Второй аргумент зачастуюназывается argv (argument vector — вектор аргументов), однако это имя также не являетсяобязательным.Как правило, с помощью argc проверяется количество установленных аргументовкоммандной строки, после чего для доступа к ним используется argv. Обратите внимание:argv[0] — это имя программы, а argv[1] — первый аргумент коммандной строки.
Еслипрограммапринимаетвкачествеаргументовдвачисловыхзначения,нужнобудетпреобразоватьихвстроки.Назанятии21выузнаете,каквыполнитьэтопреобразованиеспомощьюсредств,предоставляемых стандартными библиотеками функций. В листинге 16.19 показан примериспользованияаргументовкоманднойстроки.Листинг16.19.Использованиеаргументовкоманднойстроки1:#include<iostream.h>2:intmain(intargc,char*>argv)3:{4:cout<<"Received"<<argc<<"arguments...\n";5:for(inti=0;i<argc;i++)6:cout<<"argument"<<i<<":"<<argv[i]<<endl;7:return0;8:}Результат:TestProgramTeachYourselfC++In21DaysReceived7arguments...argument0:TestProgram.exeargument1:Teachargument2:Yourselfargument3:C++argument4:Inargument5:21argument6:DaysПримечание: Вам придется либо запустить этот код из командной строки DOS, либоустановить параметры командной строки с помощью компилятора (см.
документациюкомпилятора).Анализ: В функции main() объявляются два аргумента: argc — целочисленное значение,указывающеечислоаргументовкоманднойстроки,иargv—указательнамассивстрок.Каждыйэлемент этого массива представляет аргумент командной строки. Обратите внимание, argvможно также объявить как char *argv[] или char[][]. Программист может выбрать вариант,которыйемуболееподуше.Дажеесливпрограммеэтотаргументбудетобъявленкакуказательна указатель, для доступа к определенным элементам можно воспользоваться индексомсмещенияэлементаотначаламассива.В строке 4 массив argv используется для вывода числа установленных аргументовкоманднойстроки.Всегоихоказалосьсемь,включаяимяпрограммы.В строках 5 и 6 задается цикл for, который выводит значения всех аргументов команднойстрокипоотдельности,обращаяськнимпоименимассиваargvсуказаниемсмещения[i].Длявыводазначенийаргументовиспользуетсяобъектcout.Листинг 16.20 является переписанной версией листинга 16.18, в которой имя файлазадаетсякакаргументкоманднойстроки.Листинг16.20.Использованиеаргументовкоманднойстроки1:#include<fstream.h>2:3:classAnimal4:{5:public:6:Animal(intweight,longdays):itsWeight(weight),itsNumberDaysAlive(days)(}7:~Animal(){}8:9:intGetWeight()const{returnitsWeight;}10:voidSetWeight(intweight){itsWeight=weight;}11:12:longGetDaysAlive()const{returnitsNumberDaysAlive;}13:voidSetDaysAlive(longdays){itsNumberDaysAlive=days;}14:15:private:16:intitsWeight;17:longitsNumberDaysAlive;18:};19:20:intmain(intargc,char*argv[])//возвращает1вслучаеошибки21:{22:if(argc!=2)23:{24:cout<<"Usage:"<<argv[0]<<"<filename>"<<endl;25:return(1);26:}27:28:ofstreamfout(argv[1],ios::binary);29:if(!fout)30:{31:cout<<"Unabletoopen"<<argv[1]<<"forwriting.\n";32:return(1);33:}34:35:AnimalBear(50,100);36:fout.write((char*)&Bear,sizeofBear);37:38:fout.close();39:40:ifstreamfin(argv[1],ios::binary);41:if(!fin)42:{43:cout<<"Unabletoopen"<<argv[1]<<"forreading.\n";44:return(1);45:}46:47:AnimalBearTwo(1,1);48:49:cout<<"BearTwoweight:"<<BearTwo.GetWeight()<<endl;50:cout<<"BearTwodays:"<<BearTwo.GetDaysAlive()<<endl;51:52:fin.read((char*)&BearTwo,sizeofBearTwo);53:54:cout<<"BearTwoweight:"<<BearTwo.GetWeight()<<endl;55:cout<<"BearTwodays:"<<BearTwo.GetDaysAlive()<<endl;56:fin.close();57:return0;58:}Результат:BearTwoweight:1BearTwodays:1BearTwoweight:50BearTwodays:100Анализ:ОбъявлениеклассаAnimalаналогичнопредставленномувлистинге16.18.Однаков этом случае пользователю не предлагается ввести имя файла, а используется аргументкомандной строки.
В строке 2 объявляется функция main(), принимающая два параметра:количество аргументов командной строки и указатель на массив символов, в которомсохраняютсяаргументыкоманднойстроки.В строках 22—26 проверяется, соответствует ли установленное число аргументовожидаемому.Еслипользовательзабылввестиимяфайла,товыводитсясообщениеобошибке:UsageTestProgram<имяфайла>Послеэтогопрограммазавершаетсвоюработу.Обратитевнимание,чтопривыводеименипрограммы используется не константная строка, а значение argv[0] .
Данное выражение будетправильновыводитьимяпрограммы,дажееслионобудетизмененопослекомпиляции.В строке 28 программа пытается открыть двоичный файл с указанным именем. Однако,вместо того чтобы копировать и хранить имя файла во временном массиве, как это было влистинге16.18,егоможнозадатьвкоманднойстрокеизатемвозвратитьизargv[1].Точно так же имя файла возвращается в строке 40, где этот файл открывается для вводаданных,ивстроках25и31приформированиисообщенийобошибкахоткрытияфайлов.РезюмеСегодня вы познакомились с потоками и глобальными объектами cout и cin. Основноепредназначениеобъектовistreamиostreamсостоитвинкапсулированиибуферизированоговводаивыводаданныхнастандартныеустройстваввода-вывода.Вкаждойпрограммесоздаетсячетырестандартныхпотоковыхобъекта:cout,cin,cerrиclog.Однаковбольшинствеоперационныхсистемэтиобъектыможнопереадресовывать.Объектcinклассаistreamиспользуетсядлявводаданныхобычновместесперегружаемымоператором ввода (>>).
Объект cout класса ostream используется для вывода данных вкомбинациисоператоромвывода(<<).Стандартные объекты ввода-вывода включают много других функций-членов, напримерget() и put(). Поскольку эти методы возвращают ссылки на объект потока, несколько вызововфункцийможнообъединятьводномвыражении.Длянастройкиработыобъектовпотокаиспользуютсяманипуляторы.Сихпомощьюможноустанавливать не только опции форматирования и отображения, но и многие другие атрибутыобъектовпотока.Обмен данными с файлами осуществляется с помощью классов fstream, производных откласса iostream.
Кроме обычных операторов ввода и вывода, эти классы поддерживаютиспользованиефункцийread()иwrite(),позволяющихсчитыватьизаписыватьцелыеобъектывдвоичныефайлы.ВопросыиответыКак определить, когда использовать операторы ввода и вывода, а когда другие функциичленыклассовпотока?Вцеломоператорывводаивыводапрощевиспользовании,поэтомувбольшинствеслучаевлучше обращаться именно к ним.
В некоторых других случаях, когда эти операторы несправляются со своей работой (например, при вводе строки из слов, разделенных пробелами),можноприбегнутькиспользованиюдругихфункций.Какоеотличиемеждуcerrиclog?Объект cerr не буферизируется? Другими словами, все данные, поступающие в cerr,немедленновыводятсянаэкран.Этоотличноподходитдлявыводаошибокнаэкран,однакодорогообойдетсяпризаписирегистрационнойинформациинадиск.Объектclogбуферизируетсвойвывод,поэтомувпоследнемслучаеможетбытьболееэффективным.Зачем создавать потоки, если отлично работает функция printf()? Функция printf() неконтролирует строго типы выводимых данных, чего требуют стандарты C++.
Кроме того, этафункциянеподдреживаетработусклассами.Когдаследуетприменятьметодputback()?Этот метод весьма эффективен в тех случаях, когда для определения соответствиявведенного символа установленным ограничениям используется одна операция считывания, адля записи символа в буфер используются некоторые другие операций. Наиболее часто этонаходит применение при анализе синтаксических конструкций файла, например при созданиикомпиляторов.Когдаследуетиспользоватьфункциюignore()?Наиболее часто она используется после функции get(). Поскольку последняя оставляет вбуфересимволразрывастроки,иногдазавызовомфункцииget()следуетвызовignore(1,'\n');.Этафункция,какиputback(),используется,какправило,присинтаксическомразборефайлов.Мои друзья используют в своих программах на C++ функцию printf(). Можно ли и мне ееиспользовать?Конечноже,можно.Однако,хотяэтафункцияболеепростависпользовании,выутратитестрогийконтрользатипамифайловизатруднитеработусобъектамиклассов.КоллоквиумВэтомразделепредлагаютсявопросыдлясамоконтроляиукрепленияполученныхзнанийи приводится несколько упражнений, которые помогут закрепить ваши практические навыки.Попытайтесьсамостоятельноответитьнавопросытестаивыполнитьзадания,апотомсверьтеполученные результаты с ответами в приложении Г.