Борис Пахомов Санкт Петербург бхв петербург 2013 удк 004. 4 Ббк 32. 973. 26018. 2 П
Скачать 17.38 Mb.
|
Стандартный ввод/вывод При запуске любой программы автоматически открываются сразу три файла файл стандартного ввода. Его указатель называется stdin ; файл стандартного вывода. Его указатель называется stdout ; файл стандартного вывода ошибок. Его указатель называется При работе с файлами мы можем использовать эти указатели, чтобы направлять данные в стандартные потоки, в которых по умолчанию ввод идет с клавиатуры, а вывод — на экран. Например, чтобы ввести строку с клавиатуры, можно применить функцию fgets() в виде а для вывода строки на экран — функцию в виде Из приведенного выше перечня функций, обслуживающих ввод/вывод, мы видели, что существуют функции getc(fp) , putc(c,fp) , которые, соответственно, вводят один символ из файла с указателем fp и пишут один символ в файл с указателем fp . Если вместо указателя fp , который имеет тип FILE , в эти функции поместить указатели стандартного потока, то они станут, соответственно, вводить один символ с клавиатуры и выводить его на экран. Оказывается, что ранее применяемые нами в примерах функции getchar() , putchar() связаны в файле stdio.h со стандартными потоками следующим образом #define getchar() getc(stdin) #define putchar() Поэтому, подключив файл stdio.h к своей программе, мы спокойно работали с этими функциями, а фактически — с символическими константами. Функции стандартного ввода/вывода Функция Формат Вводит с клавиатуры один символ и выдает его. Обращаться к этой функции можно так char или int c; Функция Формат putchar(char c); Глава 9. Вводи вывод в языках Си С Выводит значение переменной с (один символ) на стандартное выводное устройство. Обращение Функция Формат Функция форматного вывода. Выводит на экран содержимое arg1,arg2,...,argn и возвращает количество выводимых байтов. Здесь Control — управляющая символьная строка, в которой находятся форматы вывода на экран для соответствующих аргументов arg1,arg2,...,argn , те. первый формат — для вывода arg1 , второй — для arg2 и т. д. Все символы, находящиеся между форматами, выводятся один к одному (те. не форматируются, что дает возможность вывода дополнительного текста для улучшения читаемости результата вывода. Форматы вывода задаются так любой формат начинается с символа % и заканчивается одним из символов форматирования d — аргумент преобразуется к десятичному виду (с учетом знака o — аргумент преобразуется к восьмеричному беззнаковому виду x — аргумент преобразуется в беззнаковую шестнадцатеричную форму с символами a , b , c , d , e , f ); Х — аргумент преобразуется в беззнаковую шестнадцатеричную форму с символами А, B , C , D , E , F ); U — аргумент преобразуется в беззнаковую десятичную форму с — аргумент рассматривается как отдельный символ s — аргумент рассматривается как строка символов символы строки печатаются до тех пор, пока не будет достигнут нулевой символ или не будет напечатано количество символов, указанное в спецификации точности (о спецификаторе точности скажем далее е — аргумент рассматривается как переменная типа float или double и преобразуется в десятичную форму в экспонентном виде [-]m.nnnnnn e[+-]xx , где длина строки из n определяется указанной точностью. По умолчанию точность равна 6; E — тоже, что и e , нос для экспоненты f — аргумент рассматривается как переменная типа float или double и преобразуется в десятичную форму в виде [-]mmm.nnnnnn , где длина строки из определяется указанной точностью. По умолчанию точность равна 6; g — используется либо формат %e , либо %f : выберется тот формат, который даст изображение числа меньшим количеством знаков с учетом заданной точности. Незначащие нули не печатаются 174 Часть I. Изучение языка С/С++ G — тоже, что и g , нос для экспоненты, если используется формат e ; n — указатель на целое со знаком p — входной аргумент выводится как указатель. Формат зависит от модели используемой памяти. Он может быть вида XXXX:YYYY или YYYY (только смещение. Между границами формата вывода находятся флажки ширина точность квадратные скобки означают, что элемент, входящий в них, может отсутствовать для какого-то формата. Например, если выводится десятичное число, то точность для него не имеет смысла флажки определяют выравнивание выводимого значения (по правому или полевому краю поля вывода, знаки числа, десятичные точки, конечные нули, восьмеричные и шестнадцатеричные префиксы. Флажки имеют следующий смысл выравнивание результата полевому краю поля вывода (число будет прижато клевой границе поля вывода) и заполнение поля вывода справа пробелами. Если этот флаг не задан, то результат выравнивается по правому краю поля вывода, а оставшееся слева пространство заполняется пробелами или нулями + — преобразование результата к виду со знаком результат всегда начинается со знака "+" или "–"; пробел — если значение неотрицательное, то вместо плюса выводится пробел. Для отрицательных чисел выводится минус # — указывает, что аргумент должен быть преобразован с использованием альтернативной формы. Это означает, что если флажок # используется вместе с символом преобразования (форматирования, то при преобразовании аргумента для символов c , s , d , u , i , o , x , X символ # не влияет на результат. Для символов e , E , f результат всегда будет содержать десятичную точку, даже если заточкой не следует никаких цифр (обычно десятичная точка появляется, если за ней следует цифра. Для символов g , результат будет как для символов e , E , нос тем отличием, что хвостовые нули не будут удаляться. Если заданы и пробели знак "+", то преимущество имеет знак "спецификатор ширины определяет размер поля для выходного значения. Ширину можно задать двумя способами напрямую — строкой десятичных цифр косвенно — через символ * (в этом случае аргумент должен иметь тип int ). Если для задания ширины используется символ * (звездочка, то спе- Глава 9. Вводи вывод в языках Си С цификация ширины указывается не в строке Control , а в списке аргументов перед соответствующим аргументом. Спецификаторы ширины n — в этом случае выведется не менее n символов. Если в выводимом числе символов меньше, чем n , то оставшаяся часть поля заполнится пробелами справа (если задан флажок, и слева — в противном случае например, 04 ) — будет выведено не менее символов. Если в выводимом числе символов меньше, чем n , то оставшаяся часть поля заполнится слева нулями * для формата d ) — если для задания ширины используется символ * , то спецификация ширины указывается не в строке Control , а в списке аргументов перед тем аргументом, для которого она определена. Причем ширина представляет собой отдельный аргумент. Например, выводим число по функции printf("%*d\n",5,i); . Результат будет пппп2 (где п — пробел. Здесь ширина задана равной 5 и указана в списке аргументов отдельно, но перед тем аргументом, для которого она определена спецификатор точности задает число выводимых символов после точки дробная часть числа. Задание спецификатора точности всегда начинается со знака точки (чтобы отделить его от спецификатора ширины. Как и спецификатор ширины, точность может задаваться двумя способами напрямую — заданием числа косвенно — указанием символа * . Если вы используете * для спецификатора точности, то спецификация точности должна указываться не в строке Control , а в списке аргументов перед соответствующим аргументом как отдельный аргумент (через запятую. Аргумент, для которого указывается спецификация точности, может быть только вещественного типа. Например: float nn=12.567; printf("%.*f\n",2,nn); вывести 2 знака после точки Результат: модификаторы размера, задаваемые в формате, определяют, как функция интерпретирует аргумент. Действие модификаторов показано в табл. 9.1. Таблица 9.1. Действие модификаторов размера Значение Формат Интерпретация h d, i, o, u, x, X short int l d ,i ,o, u, x, X long int 176 Часть I. Изучение языка С/С++ Таблица 9.1 (окончание) Значение Формат Интерпретация l e, E, f, g,G double L e, E, f, g,G long double L d ,i ,o, u, x, X __int64 h c, C 1 символьный байт l c, C 2 символьных байта h s, S 1 строка символов по байту на символ l s, S 1 строка символов по байта на символ Например, если мы выводим данные типа long , то должны задавать вместе с форматом d и модификатор типа l , те. общий вид формата будет Функция Формат Функция форматного ввода с клавиатуры. Осуществляет посимвольный ввод данных с клавиатуры, преобразует их для каждого значения в соответствии с форматом, указанным в управляющей (форматной) символьной строке Control , и результат преобразования записывает в аргументы arg1, Смысл строки Control тот же, что и для функции Так как arg1, arg2,..., argn — это выходные параметры функции, то при обращении к функции они должны задаваться своими адресами имена массивов именами (т. к. имена массивов — это указатели на их первые элементы, а те аргументы, что не являются указателями, задаются как Форматная строка — это символьная строка, содержащая три типа объектов незначащие символы, значащие символы и спецификации формата. Незначащие символы — это пробел, знак табуляции ( \t ), символ перехода на новую строку ( \n ). Как только функция встречает незначащий символ в строке формата, она считывает (ноне сохраняет) все последующие незначащие символы до тех пор, пока не встретится первый значащий символ (те. пропускает незначащие символы. Значащие символы — это все символы кода ASCII, кроме символа % . Если функция встречает в форматной строке значащий символ, она его считывает, ноне сохраняет. Спецификация формата функции имеет вид %[*] ширина [F/N] [h/l] символ формата После символа начала формата % в определенном порядке следуют остальные спецификации. Глава 9. Вводи вывод в языках Си С [*] — это необязательный символ подавления ввода весь входной поток функция рассматривает как совокупность полей ввода значащих символов. Если в спецификации указан символ * , то все поле, которое должно в данный момент обрабатываться функцией по заданному формату, пропускается. Ввод происходит так в соответствии со спецификатором ширины первого формата из входного потока выбирается очередное поле ввода (те. значащие символы до первого незначащего, которое интерпретируется в соответствии с форматом и записывается в соответствующий аргумент. Если при этом запрошенная ширина оказалась меньше поля ввода, то остаток поля обрабатывается функцией последующему формату. Если запрошенная ширина оказалась больше поля ввода, то все поле ввода обрабатывается поданному формату. Если же в объявлении формата присутствовал символ подавления ввода * , то все поле, предназначенное для обработки данным форматом, пропускается. Модификаторы размера аргумента и символы форматирования функции аналогичны модификаторами символам форматирования функции Рассмотрим пример работы функции Допустим, задано int i; float x; char На клавиатуре набираем последовательность 56789 0123 45а72 Выполняем: scanf("%2d %f %*d %2s", Как будет идти ввод В примере имеются три поля ввода 56789 , 0123 и а. Наберем их на клавиатуре и нажмем клавишу ( %2d ) выбирает из первого поля первые два символа. Функция интерпретирует их как десятичное число и присваивает значение первому аргументу i = В первом поле остались необработанными символы 789 . Они попадают в работу функции по второму формату %f . Второй аргумент получит значение x = Далее должно обрабатываться поле 0123 по третьему формату, нов нем есть символ подавления. Поэтому поле пропускается и начинает обрабатываться поле а по формату %2s . Из этого поля будут выбраны только первые два символа и строка m получит значение Функция Формат sprintf(string,Control,arg1,arg2,...,argn); 178 Часть I. Изучение языка С/С++ Эта функция аналогична printf() , за исключением того, что результат своей работы она выводит не на стандартное устройство вывода, а в строку string . Это позволяет собирать в одну строку данные совершенно разных типов. Функция Формат Эта функция аналогична scanf() , за исключением того, что входные данные для ее работы поступают не со стандартного устройства ввода, а из строки Это позволяет выделять в строке различные группы данных совершенно разных типов и помещать их в отдельные переменные. Функция Формат Вводит строку символов с клавиатуры и записывает ее в строку s , которая может быть объявлена как char *s или char Функция Формат Выводит содержимое строки s на устройство стандартного вывода (экран) ( s может быть объявлена как char *s или char s[] ). Ввод/вывод в С++ Общие положения Ввод и вывод в Сорганизован с помощью так называемых поточных классов, содержащих данные и методы работы с файлами по вводу/выводу. Поточные классы происходят от общего предка — класса ios и потому наследуют его функциональность. Чтобы начать писать программу с использованием ввода/вывода на языке С, следует обязательно выполнить в программе #include Класс fstream является потомком классов istream , ostream . Эти же классы являются родителями классово. Класс fstream используется для организации ввода/вывода (те. чтения/записи) в один и тот же файл. Классы ifstream , о используются для организации, соответственно, ввода (те. чтения файла) и вывода (те. записи в файл. В свою очередь, экземплярами классов istream , ostream являются cin , cout , cerr , с помощью которых осуществляется так называемый стандартный ввод/вывод — ввод со стандартного вводного устройства (которым по умолчанию является кла- Глава 9. Вводи вывод в языках Си С виатура) и вывод на стандартное выводное устройство (которым по умолчанию является экран. Таким образом, включение в программу класса fstream оказывается достаточным для организации как стандартного, таки файлового ввода/вывода. Файловый ввод/вывод организован с помощью переопределенных в поточных классах операций включения ( << ) и извлечения ( >> ). Ранее мы видели, что это операции сдвига влево и сдвига вправо битов в переменной типа int , нов поточных классах Сони обрели новую функциональность. Чтобы работать с файлом, его сначала следует открыть связать со специальной структурой, в которой задаются характеристики файла (размер буфера ввода вывода, состояние файла, последняя прочитанная запись и т. п. Связь эта выполняется с помощью функции open() , входящей в один из классов, который определяет ввод/вывод ( fstream , istream , ostream ). Поэтому, чтобы выполнить такую функцию, следует сначала создать экземпляр соответствующего класса (для получения доступа к этой функции. Если мы, например, хотим выполнять вывод в файл те. запись в него, то следует создать экземпляр класса ostream : ostream и затем выполнить функцию exp.open() . В скобках должны быть параметры этой функции имя открываемого файла и способ открытия файла, в котором задаются сведения о том, как собирается пользователь работать с файлом (читать его, писать в него или делать что-то еще. После того как файл открыт, собственно для чтения или записи уже используют операции включения/извлечения ( << , >> ). Если использовать пример с экземпляром exp класса ostream , то можно записать так exp << "строка текста" << i << j << Здесь i, j — некоторые переменные (например, int i; float j; ), endl — конец вывода и переход на новую строку. После того как работа с файлом закончена, следует закрыть файл, чтобы разорвать связь стой структурой, с которой файл был связан при его открытии. Это необходимо, чтобы дать возможность другим файлам "открываться. Этот акт выполняется с помощью метода close() того же экземпляра класса, который мы создавали, чтобы выполнить функцию open() . В нашем случае следовало бы написать exp.close(); Ввод/вывод с использованием разных классов Итак, мы определили, что поточные классы — это поставщики инструментов для работы с файлами. В поточных классах хранятся структуры, обеспечивающие открытие/закрытие файлов функции (методы) открытия/закрытия файлов другие функции и данные, обеспечивающие, как мы увидим далее, собственно ввод/вывод. 180 Часть I. Изучение языка С/С++ Пространства имен Многие серьезные приложения состоят из нескольких программных файлов (с исходным текстом программ, которые создаются и обслуживаются отдельными группами программистов. И только после этого все файлы собираются в общий проект. Но как быть стем фактом, что в таких файлах могут быть одинаково объявлены некоторые разные переменные В С+ это неудобство разрешается с помощью так называемых пространств имен, которые вводят в каждый составляющий единый проект текстовый программный файл с помощью директивы Namespace имя пространства имен (идентификатор в эти скобки заключается весь программный текст} Когда идет сборка общего проекта, тов итоговом тексте пишут директиву using namespace:: идентификатор пространства имен; Это обеспечивает в итоговом проекте доступ к переменным файла сданным пространством имен. При использовании поточных классов языка Св основной программе требуется писать директиву using В противном случае программа не пройдет компиляцию. В листинге 9.3 приводится пример использования директив пространства имен, результат работы программы показан на рис. 9.2. Листинг 9.3 // 9.3_2011.cpp // #include "stdafx.h" #include #include { float x = 9; } namespace G { using namespace F; здесь само пространство G использует пространство F ив нем же объявляется еще одно пространство INNER_G */ float y = 2.0; namespace INNER_G { Глава 9. Вводи вывод в языках Си С float z = 10.01; } } // G int main() { using namespace G; эта директива позволяет пользоваться всем, объявленным в G*/ using namespace G::INNER_G; /* эта директива позволяет пользоваться всем, объявленным только в INNER_G */ float x = 19.1; локальное объявление переопределяет предыдущее */ std::cout << "x = " << x << std::endl; std::cout << "y = " << y << std::endl; /* y берется из пространства F */ std::cout << "z = " << z << std::endl; /* z берется из пространства INNER_G */ _getch(); } Рис 9.2. Результат работы программы листинга 9.3 std::cout — это стандартный вывод. Его мы рассмотрим чуть позже. Здесь показано, что объект cout принадлежит пространству имен std . Мы могли бы в основной программе записать using Тогда бы вместо std::cout можно было бы писать просто Итак, при составлении программы с использованием поточных файлов вначале основной программы следует записать директиву using namespace Работа с классом Члены этого класса позволяют открыть файл, записать в него данные, переместить указатель позиционирования (указатель, показывающий, в каком месте файла мы находимся, прочитать данные. Этот класс имеет такие основные функции (методы open() — открывает файл close() — закрывает файл 182 Часть I. Изучение языка С/С++ is_open() — если файл открыт, то функция возвращает true , иначе — false ; rdbuf() — выдает указатель на буфер ввода/вывода. Параметры функции open() : имя открываемого файла способ открытия файла. Способ открытия файла задается значением перечислимой переменной enum open_mode Эта переменная определена в базовом классе ios , поэтому обращение к перечислимым значениям в классе fstream , с экземпляром которого мы работаем, должно идти с указанием класса-родителя: ios::app, ios::binary и т. д. Назначение способов открытия файла app — открыть файл для дозаписи в его конец binary — открыть файл в бинарном виде (такие файлы были записаны по определенной структуре данных и поэтому должны читаться по этой же структуре in — открыть файл для чтения из него out — открыть файл для записи в него сего начала. Если файл не существует, он будет создан trunc — уничтожить содержимое файла, если файл существует (очистить файл ate — установить указатель позиционирования файла на его конец. При задании режимов открытия файла можно применять оператор логического ИЛИ ( | ), чтобы составлять необходимое сочетание режимов открытия. В листинге 9.4 приведен пример программы работы с классом fstream , результат работы показан на рис. 9.3. Листинг 9.4 // 9.4_2011.cpp #include "stdafx.h" #include #include #include #include { using namespace std; /* Используется стандартное пространство имен. Создание двунаправленного (чтение/запись водном и том же файле) объекта экземпляра) */ fstream inout; inout.open("fstream.out",ios_base::in | ios_base::out | ios_base::trunc); Глава 9. Вводи вывод в языках Си С // вывод в файл inout << "This is the story1 of a man" << endl; inout << "This is the story2 of a man" << endl; inout << "This is the story3 of a man" << endl; char p[100]; // установка указателя файла (позиционирование) в его начало inout.seekg(0); // чтение й строки (длиной не более 100 символов) inout.getline(p,100); // вывод й строки на экран (stdout) cout << endl << "String1 :" << endl; cout << p; // запоминание текущей позиции в файле после го вывода fstream::pos_type pos = inout.tellg(); // чтение й строки из файла inout.getline(p,100); // вывод й строки на экран (stdout) cout << endl << "String2 :" << endl; cout << p; // чтение й строки из файла inout.getline(p,100); // вывод й строки на экран (stdout) cout << endl << "String3 :" << endl; cout << p; // установка указателя перед й строкой inout.seekp(pos); // запись на место й строки inout << "This is the story2 of a man" << endl; // запись на место й строки inout << "This is the story3 of a man" << endl; // установка на начало файла inout.seekg(0); // вывод всего содержимого потока на экран (stdout) cout << endl << endl << inout.rdbuf(); inout.close(); system("DEL FSTREAM.OUT"); _getch(); } Алгоритм примера ясен из комментария к тексту программы три строки записываются в файл, затем оттуда читаются и выводятся на экран. После этого на место й и й строк пишутся новые данные (на самом деле — те же самые) и снова содержимое файла выводится на экран. 184 Часть I. Изучение языка С/С++ Рис. 9.3. Результаты работы программы листинга Работа с классом Этот класс предназначен для организации работ по выводу (записи) в файл с помощью методов этого класса open() — открывает файл для записи в него информации is_open() — возвращает true , если файл открыт, ив противном случае put() — записывает в файл один символ write() — записывает в файл заданное число символов skeep() — перемещает указатель позиционирования в заданное место файла tellp() — выдает текущее значение указателя позиционирования close() — закрывает файл rdbuf() — выдает указатель на буфер вывода (этот буфер находится в структуре, с которой связывается файл при его открытии. В листинге 9.5 приведен пример использования класса Листинг 9.5 #include FILE.open("a.txt"); вызываем метод открытия файла if(FILE ==NULL) return(0); неудачное открытие файла for(int i=0; i<2; i++) FILE << "string " << i << endl; вывод в файл FILE.close(); закрытие файла Глава 9. Вводи вывод в языках Си С Работа с классом Этот класс предназначен для организации работ по вводу (чтению) из файла с помощью следующих методов open() — открывает файл для чтения из него информации is_open() — возвращает true , если файл открыт, ив противном случае get() — читает из файла один символ read() — читает из файла заданное число символов eof() — возвращает ненулевое значение, когда указатель позиционирования достигает конца файла peek() — выдает очередной символ потока, ноне выбирает его (не сдвигает указатель позиционирования данного в файле seekg() — перемещает указатель позиционирования в заданное место файла tellg() — выдает текущее значение указателя позиционирования close() — закрывает файл rdbuf() — выдает указатель на буфер ввода (этот буфер находится в структуре, с которой связывается файл при его открытии. Пример использования класса приведен в листинге 9.6. Листинг 9.6 #include FILE.open("a.txt"); вызываем метод открытия файла if(FILE ==NULL) return(0); неудачное открытие файла while(!FILE.eof()) проверка на признак конца файла { FILE >> p; чтение из файла cout << p << endl; // вывод прочитанных данных на экран } FILE.close(); закрытие файла В листинге 9.7 приведен пример использования классов ofstream и ifstream оба находятся в fstream ), результат работы программы показан на рис. 9.4. Листинг 9.7 // 9.5_2011.cpp #include "stdafx.h" #include 186 Часть I. Изучение языка С/С++ #include #include #define DelKey 's' этот символ будет удаляться из потока #define maxline 1000 int main() { using namespace std; // используется стандартное пространство имен Проверка вывода ofstream FILE; FILE.open("c:\\a.txt",ios::out); char p[maxline]; int i,pos; for(i=0; i<2; i++) FILE << "string " << i; /* << endl; endl вводить не надо, иначе и выводить его надои цикл будет длиннее */ FILE.close(); Проверка ввода (чтения по записям) ifstream FILE1; FILE1.open("c:\\a.txt"); FILE1.seekg(0); /* указатель — в начало(он итак будет вначале, но это, чтобы посмотреть, как работает seekg()) */ if(FILE1 == NULL) так надо проверять на ошибку открытия файла return(0); while(!FILE1.eof()) так проверяется конец файла { FILE1 >> p >> i; cout << p << i << endl; } FILE1.close(); _getch(); Проверка посимвольного чтения ifstream FILE2; char c; FILE2.open("c:\\a.txt"); if(FILE2 == NULL) так надо проверять на плохое открытие return(0); while(!FILE2.eof()) так проверяется конец файла { c=FILE2.peek(); смотрит, какой следующий символ будет считан, но указатель позиционирования при этом не сдвигается остается на этом символе */ Глава 9. Вводи вывод в языках Си С streamoff cgp=FILE2.tellg(); /* так определяется текущая позиция в файле if(c==DelKey) выбрасываются все символы DelKey из читаемого потока */ { pos= cgp + 1; // готовимся пропустить символ по seekg() FILE2.seekg(pos); передвинули указатель позиционирования на один символ дальше, чтобы пропустить символ */ continue; // на продолжение цикла } FILE2.get(c); чтение символа в с cout << c; } //while cout << endl; FILE2.close(); _getch(); system("DEL C:\\A.TXT"); // удаление рабочего файла } //main() Рис 9.4. Результат работы программы листинга Работа с бинарным файлом Бинарные файлы, в отличие от потоковых, создаются в определенной логической структуре и поэтому должны читаться в переменную той же структуры. Пример программы приведен в листинге 9.8, результат работы программы показан на рис. 9.5. Листинг 9.8 // 9.6_2011.cpp #include "stdafx.h" #include #include #include #include { using namespace std; /* используется стандартное пространство имен */ 188 Часть I. Изучение языка С/С++ данные о сотрудниках struct Blocknotes { char name[30]; char phone[15]; int age; }b[2]={ "Smit", "123456",45, "Kolly", "456789",50 }; инициализация массива структур запись данных в файл ofstream FILE; FILE.open("Block",ios::binary); for(int i=0; i<2; i++) FILE.write((char *)&b[i],sizeof(b[i])); FILE.close(); чтение данных из файла ifstream FILE1; FILE1.open("Block",ios::binary); Blocknotes bb[2]; int i=0; while(!FILE1.eof()) { if(i==2) goto m; FILE1.read((char *)&bb[i],sizeof(bb[i])); cout << "string" << i << " " << bb[i].name << " " << bb[i].phone <<" " << bb[i].age << endl; i++; } m: FILE1.close(); system("DEL BLOCK"); _getch(); } Рис 9.5. Результат работы программы листинга Пояснений требуют следующие моменты FILE.write((char *)&b[i],sizeof(b[i])) ; Здесь для записи используется функция буферизированного вывода write() , где первым аргументом является указатель на структуру, из которой мы должны за Глава 9. Вводи вывод в языках Си Списывать данные. Этот указатель равен адресу структуры, те. Нов потоке все данные хранятся побайтно, поэтому тип указателя char (здесь идет принудительное преобразование типа. Второй аргумент — длина записи, она определяется стандартной функцией sizeof() ; system("DEL BLOCK"); — этой функцией удаляется рабочий файл оператор goto применен для подстраховки от превышения индекса массива Стандартный ввод/вывод в С++ Общие положения Стандартный ввод/вывод является частным случаем файлового ввода/вывода. При файловом вводе/выводе мы объявляли экземпляры соответствующих поточных классов, а затем пользовались методами и операциями << , >> . Но как мы видели вначале этой главы, классы istream , ostream , лежащие в основе поточных классов, содержат стандартные объекты-экземпляры классов с именами cout (экземпляр класса для стандартного ввода, cin (экземпляр класса для стандартного вывода) и с (экземпляр класса для стандартного вывода сообщений об ошибках. При запуске любой программы на языке С+ эти стандартные потоки определены открыты) и по умолчанию назначены на стандартное вводное устройство — клавиатуру, на стандартное выводное устройство — экран ( cout и cerr ). Причем все эти устройства синхронно связаны с соответствующими указателями stdin , stdout , stderr . Так что работа со стандартным вводом/выводом сводится к тому, что вместо задаваемых пользователем имен экземпляров соответствующих классов задаются имена стандартных экземпляров классов cin , cout . Открывать ничего не надо, нужно только использовать операции << , >> и операции форматирования. Если мы пишем имена переменных, из которых выводятся или в которые вводятся данные, то по умолчанию для ввода/вывода используются определенные форматы. Например, запишем cout << В этом случае значение i выведется на экран в формате, определенном по умолчанию для типа i ив минимальном поле. Запишем cin >> i >> j >> где i , j , s описаны, соответственно, как int , float , char . В записи невидно форматов, но при вводе значений этих переменных с клавиатуры (после ввода каждого значения надо нажимать клавишу , объявленным в файле stdio.h. По умолчанию стандартные потоки Си С+ синхронизированы Часть I. Изучение языка С/С++ При выводе данные могут быть отформатированы с помощью функций-членов класса или манипуляторов. Их перечень приводится в табл. 9.2. Манипуляторы, начинающиеся си т. п.), имеют обратное действие по отношению к манипуляторам с такими же именами, но без приставки "no". В графе "Описание" у таких манипуляторов проставлены пробелы. Таблица 9.2. Манипуляторы и функции стандартного ввода/вывода в С++ Манипуляторы Функции - члены класса Описание showpos setf(ios::showpos) Выдает знак плюсу выводимых положительных чисел noshowpos unsetf(ios::showpos) showbase setf(ios::showbase) Выдает базу системы счисления в выводимом числе в виде префикса noshowbase unsetf(ios::showbase) uppercase setf(ios::uppercase) Заменяет символы нижнего регистра на символы верхнего регистра в выходном потоке nouppercase unsetf(ios::uppercase) showpoint setf(ios::showpoint) Создает символ десятичной точки в сгенерированном потоке с плавающей точкой (в выводимом числе unsetf(ios::showpoint) boolalpha setf(ios::boolalpha) Переводит булевый тип в символьный noboolalpha unsetf(ios::boolalpha) unitbuf setf(ios::unitbuf) Сбрасывает буфер вывода после каждой операции вывода nounitbuf unsetf(ios::unitbuf) internal setf(ios::internal, ios::adjustfield) Добавляет символы- заполнители к определенным внутренним позициям выходного потока (речь идет о выводе числа в виде потока символов. Если такие позиции не определены, поток не изменяется left setf(ios::left,ios::adjustfield) Добавляет символы- заполнители с конца числа (сдвигая число влево setf(ios::right,ios::adjustfield) Добавляет символы- заполнители сначала числа (сдвигая число вправо Глава 9. Вводи вывод в языках Си С Таблица 9.2 (окончание) Манипуляторы Функции - члены класса Описание dec setf(ios::dec,ios::basefield) Переводит базу вводимых или выводимых целых чисел в десятичную (введенные после этого манипулятора данные будут выводиться как десятичные setf(ios::hex,ios::basefield) Переводит базу вводимых или выводимых целых чисел в шестнадцатеричную (введенные после этого манипулятора данные будут выводиться как шестнадцатеричные) Переводит базу вводимых или выводимых целых чисел в восьмеричную (введенные после этого манипулятора данные будут выводиться как восьмеричные setf(ios::fixed,ios::floatfield) Переводит выход с плавающей точкой в выход с фиксированной точкой scientific setf(ios::scientific,ios:: floatfield) Выдает числа с плавающей точкой в виде, используемом в научных целях например, число 23450000 будет записано как 23.45e6 setbase(int base) Преобразует ввод целых чисел в тип base, где параметр base может быть одним из чисел 8, 10 или 16 fill(c) setfill(char_type c) Задает символ заполнения при выводе данных precision(n) setprecision(int n) Задает точность вывода данных количество цифр после точки n) width(n) Задает ширину поля для выводимых данных (количество символов Вставляет символ новой строки ( '\n' ) в выходную последовательность символов и сбрасывает буфер ввода ends Вставляет символ 'в выходную последовательность символов flush flush( ) Сбрасывает буфер вывода ws Задает пропуск пробелов при вводе Значения по умолчанию precision() — 6; width() — 0; fill() — пробел. 192 Часть I. Изучение языка С/С++ В листинге 9.9 приведен пример программы с применением объекта все пояснения можно найти в комментариях. Результат работы программы представлен на рис. 9.6. Листинг 9.9 // 9.7_2011.cpp #include "stdafx.h" #include #include #include // пример использования cout void main ( ) { using namespace std; int i; float f; cout << "Enter i and f >" << endl; // чтение целого числа и числа с плавающей точкой с устройства stdin cin >> i >> f; // вывод целого и переход на новую строку cout << i << endl; // вывод числа с плавающей точкой и переход на новую строку cout << f << endl; // вывод в шестнадцатеричной системе cout << hex << i << endl; // вывод в восьмеричной и десятичной системах cout << oct << i << dec << i << endl; // вывод i с указанием его знака cout << showpos << i << endl; // вывод i в шестнадцатеричной системе cout << setbase(16) << i << endl; вывод i в десятичной системе и дополнение справа символом @ до ширины в 20 символов (заполнение начинается от правой границы клевой. Если вы вводите, например, 45, то выведется 45@@@@@@@@@@@@@@@@@@ */ cout << setfill('@') << setw(20) << left << dec << i; cout << endl; // вывод того же результата в том же формате, // нос использованием функций вместо манипуляторов cout.fill('@'); cout.width(20); cout.setf(ios::left, ios::adjustfield); Глава 9. Вводи вывод в языках Си С cout.setf(ios::dec, ios::basefield); cout << i << endl; // вывод f в научной нотации с точностью 10 цифр cout << scientific << setprecision(10) << f << endl; // изменение точности до 6 цифр cout.precision(6); // выводи возврат к нотации с фиксированной точкой cout << f << fixed << endl; _getch(); } //main() Рис 9.6. Результат работы программы листинга Стандартный ввод Объект (экземпляр класса) cin управляет вводом из буфера, связанного с объектом stdin , объявленным в файле stdio.h. По умолчанию стандартные потоки в языках Си С+ синхронизированы. При вводе используется часть тех функций и манипуляторов, которые определены для cout . Это такие манипуляторы, как dec , hex , oct , ws и др. Пример программы с использованием объекта cin приведен в листинге 9.10, результат работы программы — на рис. 9.7. Листинг 9.10 // 9.8_2011.cpp #include "stdafx.h" #include #include #include 194 Часть I. Изучение языка С/С++ // й пример использования cin void main ( ) { using namespace std; int i; float f; char c; ввод целого числа, числа с плавающей точкой и символа с stdin cout << "Enter i,f,c and then input the string >" << endl; cin >> i >> f >> c; // выводи на stdout cout << i << endl << f << endl << c << endl; // // й пример использования cin // char p[50]; // приказ на удаление из ввода всех пробелов cin >> ws >> p; cout << p << endl; // чтение символов с stdin, пока не будет нажата клавиша // или не будут прочтены 49 символов cin.seekg(0); cin.getline(p,50); // вывод результата на stdout cout << p << endl; _getch(); } Рис 9.7. Результат работы программы листинга 9.10 ЧАСТЬ II Приложения Windows Глава Продолжение изучения среды Visual Глава Компоненты, создающие интерфейс между пользователем и приложением |