Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Форматный ввод - функция scanf

Поиск
Осуществляющая ввод функция SCANF является аналогомPRINTF и позволяет проводить в обратном направлении многиеиз тех же самых преобразований. Функция SCANF(CONTROL, ARG1, ARG2,...) читает символы из стандартного ввода, интерпретирует их всоответствии с форматом, указанном в аргументе CONTROL, ипомещает результаты в остальные аргументы. Управляющий аргу-мент описывается ниже; другие аргументы, каждый из которыхдолжен быть указателем, определяют, куда следует поместитьсоответствующим образом преобразованный ввод. Управляющая строка обычно содержит спецификации преобра-зования, которые используются для непосредственной интерпре-тации входных последовательностей. Управляющая строка можетсодержать:- пробелы, табуляции или символы новой строки ("символы пус- тых промежутков"), которые игнорируются. - Обычные символы (не %), которые предполагаются совпадающи- ми со следующими отличными от символов пустых промежутков символами входного потока.- Спецификации преобразования, состоящие из символа %, нео- бязательного символа подавления присваивания *, необяза- тельного числа, задающего максимальную ширину поля и сим- вола преобразования. Спецификация преобразования управляет преобразованиемследующего поля ввода. нормально результат помещается в пе-ременную, которая указывается соответствующим аргументом.Если, однако, с помощью символа * указано подавление прис-ваивания, то это поле ввода просто пропускается и никакогоприсваивания не производится. Поле ввода определяется какстрока символов, которые отличны от символов простых проме-жутков; оно продолжается либо до следующего символа пустогопромежутка, либо пока не будет исчерпана ширина поля, еслиона указана. Отсюда следует, что при поиске нужного ей вво-да, функция SCANF будет пересекать границы строк, посколькусимвол новой строки входит в число пустых промежутков. Символ преобразования определяет интерпретацию поля вво-да; согласно требованиям основанной на вызове по значениюсемантики языка "с" соответствующий аргумент должен бытьуказателем. Допускаются следующие символы преобразования:D - на вводе ожидается десятичное целое; соответствующий ар- гумент должен быть указателем на целое.O - На вводе ожидается восьмеричное целое (с лидирующим ну- лем или без него); соответствующий аргумент должен быть указателем на целое.X - На вводе ожидается шестнадцатеричное целое (с лидирующи- ми 0X или без них); соответствующий аргумент должен быть указателем на целое.H - На вводе ожидается целое типа SHORT; соответсвующий ар- гумент должен быть указателем на целое типа SHORT.C - Ожидается отдельный символ; соответствующий аргумент должен быть указателем на символы; следующий вводимый символ помещается в указанное место. Обычный пропуск сим- волов пустых промежутков в этом случае подавляется; для чтения следующего символа, который не является символом пустого промежутка, пользуйтесь спецификацией преобразо- вания %1S.S - Ожидается символьная строка; соответствующий аргумент должен быть указателем символов, который указывает на массив символов, который достаточно велик для принятия строки и добавляемого в конце символа \0.F - Ожидается число с плавающей точкой; соответствующий ар- гумент должен быть указателем на переменную типа FLOAT.Е - символ преобразования E является синонимом для F. Формат ввода переменной типа FLOAT включает необязательный знак, строку цифр, возможно содержащую десятичную точку и нео- бязательное поле экспоненты, состоящее из буквы E, за ко- торой следует целое, возможно имеющее знак. Перед символами преобразования D, O и X может стоять L,которая означает, что в списке аргументов должен находитьсяуказатель на переменную типа LONG, а не типа INT. Аналогич-но, буква L может стоять перед символами преобразования Eили F, говоря о том, что в списке аргументов должен нахо-диться указатель на переменную типа DOUBLE, а не типа FLOAT. Например, обращениеINT I;FLOAT X;CHAR NAME[50];SCANF("&D %F %S", &I, &X, NAME); со строкой на вводе 25 54.32E-1 THOMPSON приводит к присваиванию I значения 25,X - значения 5.432 иNAME - строки "THOMPSON", надлежащим образом законченнойсимволом \ 0. эти три поля ввода можно разделить столькимипробелами, табуляциями и символами новых строк, сколько выпожелаете. Обращение INT I; FLOAT X; CHAR NAME[50]; SCANF("%2D %F %*D %2S", &I, &X, NAME); с вводом 56789 0123 45A72 присвоит I значение 56, X - 789.0, пропустит 0123 и поместитв NAME строку "45". при следующем обращении к любой процеду-ре ввода рассмотрение начнется с буквы A. В этих двух приме-рах NAME является указателем и, следовательно, перед ним ненужно помещать знак &. В качестве другого примера перепишем теперь элементарныйкалькулятор из главы 4, используя для преобразования вводафункцию SCANF: #INCLUDE MAIN() /* RUDIMENTARY DESK CALCULATOR */ \(DOUBLE SUM, V; SUM =0; WHILE (SCANF("%LF", &V)!=EOF) PRINTF("\T%.2F\N", SUM += V); \) выполнение функции SCANF заканчивается либо тогда, когда онаисчерпывает свою управляющую строку, либо когда некоторыйэлемент ввода не совпадает с управляющей спецификацией. Вкачестве своего значения она возвращает число правильно сов-падающих и присвоенных элементов ввода. Это число может быть использовано для определения количества найденных элементовввода. при выходе на конец файла возвращается EOF; подчерк-нем, что это значение отлично от 0, что следующий вводимыйсимвол не удовлетворяет первой спецификации в управляющейстроке. При следующем обращении к SCANF поиск возобновляетсянепосредственно за последним введенным символом. Заключительное предостережение: аргументы функции SCANFдолжны быть указателями. Несомненно наиболее распространен-ная ошибка состоит в написании SCANF("%D", N); вместо SCANF("%D", &N);

7.5. Форматное преобразование в памяти

От функции SCANF и PRINTF происходят функции SSCANF иSPRINTF, которые осуществляют аналогичные преобразования, нооперируют со строкой, а не с файлом. Обращения к этим функ-циям имеют вид: SPRINTF(STRING, CONTROL, ARG1, ARG2,...) SSCANF(STRING, CONTROL, ARG1, ARG2,...) Как и раньше, функция SPRINTF преобразует свои аргументыARG1, ARG2 и т.д. В соответствии с форматом, указанным вCONTROL, но помещает результаты в STRING, а не в стандартныйвывод. KОнечно, строка STRING должна быть достаточно велика,чтобы принять результат. Например, если NAME - это символь-ный массив, а N - целое, то SPRINTF(NAME, "TEMP%D", N); создает в NAME строку вида TEMPNNN, где NNN - значение N. Функция SSCANF выполняет обратные преобразования - онапросматривает строку STRING в соответствии с форматом в ар-гументе CONTROL и помещает результирующие значения в аргу-менты ARG1, ARG2 и т.д.эти аргументы должны быть указателя-ми. В результате обращения SSCANF(NAME, "TEMP%D", &N); переменная N получает значение строки цифр, следующих заTEMP в NAME. Упражнение 7-2 -------------- Перепишите настольный калькулятор из главы 4, используядля ввода и преобразования чисел SCANF и/или SSCANF.

Доступ к файлам

Все до сих пор написанные программы читали из стандарт-ного ввода и писали в стандартный вывод, относительно кото-рых мы предполагали, что они магическим образом предоставле-ны программе местной операционной системой. Следующим шагом в вопросе ввода-вывода является написа-ние программы, работающей с файлом, который не связан зара-нее с программой. одной из программ, которая явно демонстри-рует потребность в таких операциях, является CAT, котораяобъединяет набор из нескольких именованных файлов в стандар-тный вывод. Программа CAT используется для вывода файлов натерминал и в качестве универсального сборщика ввода дляпрограмм, которые не имеют возможности обращаться к файлампо имени. Например, команда CAT X.C.Y.C печатает содержимое файлов X.C и Y.C в стандартный вывод. Вопрос состоит в том, как организовать чтение из имено-ванных файлов, т.е., как связать внешние имена, которымимыслит пользователь, с фактически читающими данные операто-рами. Эти правила просты. Прежде чем можно считывать из неко-торого файла или записывать в него, этот файл должен бытьоткрыт с помощью функции FOPEN из стандартной библиотеки.функция FOPEN берет внешнее имя (подобное X.C или Y.C), про-водит некоторые обслуживающие действия и переговоры с опера-ционной системой (детали которых не должны нас касаться) ивозвращает внутреннее имя, которое должно использоваться припоследующих чтениях из файла или записях в него. Это внутреннее имя, называемое "указателем файла", фак-тически является указателем структуры, которая содержит ин-формацию о файле, такую как место размещения буфера, текущаяпозиция символа в буфере, происходит ли чтение из файла илизапись в него и тому подобное. Пользователи не обязаны знатьэти детали, потому что среди определений для стандартноговвода-вывода, получаемых из файла STDIO.H, содержится опре-деление структуры с именем FILE. Единственное необходимоедля указателя файла описание демонстрируется примером: FILE *FOPEN(), *FP; Здесь говорится, что FP является указателем на FILE иFOPEN возвращает указатель на FILE. Oбратите внимание, чтоFILE является именем типа, подобным INT, а не ярлыку струк-туры; это реализовано как TYPEDEF. (Подробности того, каквсе это работает на системе UNIX, приведены в главе 8). Фактическое обращение к функции FOPEN в программе имеетвид: FP=FOPEN(NAME,MODE); Первым аргументом функции FOPEN является "имя" файла, кото-рое задается в виде символьной строки. Второй аргумент MODE("режим") также является символьной строкой, которая указы-вает, как этот файл будет использоваться. Допустимыми режи-мами являются: чтение ("R"), запись ("W") и добавление("A"). Если вы откроете файл, который еще не сущетвует, для за- писи или добавления, то такой файл будет создан (если этовозможно). Открытие существующего файла на запись приводит котбрасыванию его старого содержимого. Попытка чтения несу-ществующего файла является ощибкой. Ошибки могут быть обус- ловлены и другими причинами (например, попыткой чтения из файла, не имея на то разрешения). При наличии какой-либо ошибки функция возвращает нулевое значение указателя NULL(которое для удобства также определяется в файле STDIO.H). Другой необходимой вещью является способ чтения или за-писи, если файл уже открыт. Здесь имеется несколько возмож-ностей, из которых GETC и PUTC являются простейшими.функцияGETC возвращает следующий символ из файла; ей необходим ука-затель файла, чтобы знать, из какого файла читать. Таким об- разом, C=GETC(FP) помещает в "C" следующий символ из файла, указанного посред-ством FP, и EOF, если достигнут конец файла. Функция PUTC, являющаяся обращением к функции GETC, PUTC(C,FP) помещает символ "C" в файл FP и возвращает "C". Подобно фун-кциям GETCHAR и PUTCHAR, GETC и PUTC могут быть макросами, ане функциями. При запуске программы автоматически открываются три фай-ла, которые снабжены определенными указателями файлов. Этимифайлами являются стандартный ввод, стандартный вывод и стан-дартный вывод ошибок; соответствующие указатели файлов назы-ваются STDIN, STDOUT и STDERR. Обычно все эти указатели свя-заны с терминалом, но STDIN и STDOUT могут быть перенаправ-лены на файлы или в поток (PIPE), как описывалось в разделе7.2. Функции GETCHAR и PUTCHAR могут быть определены в терми-налах GETC, PUTC, STDIN и STDOUT следующим образом:#DEFINE GETCHAR() GETC(STDIN) #DEFINE PUTCHAR(C) PUTC(C,STDOUT)При работе с файлами для форматного ввода и вывода можно ис-пользовать функции FSCANF и FPRINTF. Они идентичны функциямSCANF и PRINTF, за исключением того, что первым аргументомявляется указатель файла, определяющий тот файл, который бу-дет читаться или куда будет вестись запись; управляющаястрока будет вторым аргументом. Покончив с предварительными замечаниями, мы теперь всостоянии написать программу CAT для конкатенации файлов.Используемая здесь основная схема оказывается удобной вомногих программах: если имеются аргументы в командной стро-ке, то они обрабатываются последовательно. Если такие аргу-менты отсутствуют, то обрабатывается стандартный ввод. Этопозволяет использовать программу как самостоятельно, так икак часть большей задачи. #INCLUDE MAIN(ARGC, ARGV) /*CAT: CONCATENATE FILES*/ INT ARGC; CHAR *ARGV[]; \(FILE *FP, *FOPEN(); IF(ARGC==1) /*NO ARGS; COPY STANDARD INPUT*/ FILECOPY(STDIN); ELSE WHILE (--ARGC > 0) IF ((FP=FOPEN(*++ARGV,"R"))==NULL) \(PRINTF("CAT:CAN'T OPEN %\N",*ARGV); BREAK; \) ELSE \(FILECOPY(FP); FCLOSE(FP); \) \) FILECOPY(FP) /*COPY FILE FP TO STANDARD OUTPUT*/ FILE *FP; \(INT C; WHILE ((C=GETC(FP))!=EOF) PUTC(C, STDOUT); \) Указатели файлов STDIN и STDOUT заранее определены в библио-теке ввода-вывода как стандартный ввод и стандартный вывод;они могут быть использованы в любом месте, где можно исполь-зовать объект типа FILE*.они однако являются константами, ане переменными, так что не пытайтесь им что-либо присваи-вать. Функция FCLOSE является обратной по отношению к FOPEN;она разрывает связь между указателем файла и внешним именем,установленную функцией FOPEN, и высвобождает указатель файладля другого файла.большинство операционных систем имеют не-которые ограничения на число одновременно открытых файлов,которыми может распоряжаться программа. Поэтому, то как мыпоступили в CAT, освободив не нужные нам более объекты, яв-ляется хорошей идеей. Имеется и другая причина для примене-ния функции FCLOSE к выходному файлу - она вызывает выдачуинформации из буфера, в котором PUTC собирает вывод. (Принормальном завершении работы программы функция FCLOSE вызы-вается автоматически для каждого открытого файла).


Поделиться:


Последнее изменение этой страницы: 2016-08-26; просмотров: 253; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.216.26.104 (0.007 с.)