Формат чисел и строк
Как это ни странно, у многих студентов вызывают трудности обычные операции чтения данных из файлов. Основными данными при выполнении практических работ являются числа (целые и вещественные) и функции в аналитическом виде (т.е. строки). О работе с функциями говорится в следующем разделе пособия. Рассмотрим работу с числами. Для чтения чисел из текстового файла используются стандартные процедуры или операторы ввода: read(f, x); { Pascal } fscanf(f, format, & x); // C f > > x; // C++ При этом файловая переменная f должна быть связана с входным файлом, а указатель в файле должен находиться перед считываемым числом. В языке Pascal эта связь создается последовательным вызовом функций Assign и Reset, а в C – fopen (библиотека stdio.h). В языке C++ переменная f должна являться экземпляром класса ifstream (библиотека fstream.h) и связывается с файлом либо при вызове конструктора класса, либо при помощи метода open. Тип переменной x должен соответствовать типу считываемого числа. При этом все разделители (пробелы, табуляции, переносы строки) пропускаются автоматически. В языке C тип числа задается явным способом – при помощи текстового параметра format. Для целого числа это обычно «%d» (int) или «%ld» (long), для вещественного числа – «%f» (float) или «%lf» (double). Переменная в этом случае передается в функцию по адресу. Как именно формируется адрес – не важно. Например, адрес ячейки с номером i в массиве-векторе a можно записать как a + i, что эквивалентно & a[i](следовательно, & a[0] эквивалентно просто a). Для записи чисел в текстовый файл используются стандартные процедуры или операторы вывода: write(f, x); { Pascal } fprintf(f, format, x); // C f < < x; // C++ Файловая переменная f должна быть связана с выходным файлом. В языке Pascal эта связь создается последовательным вызовом функций Assign и Rewrite, а в C – также fopen. В языке C++ переменная f должна являться экземпляром класса ofstream (библиотека fstream.h) и связывается с файлом либо при вызове конструктора класса, либо при помощи метода open. При этом вывод можно форматировать. Так, в языке Pascal для форматирования чисел при выводе используется запись x: n, где n – количество позиций для вывода числа. Лишние позиции (не занятые цифрами числа) заполняются пробелами. Это удобно использовать при выводе матриц. Для вещественных чисел можно задавать дополнительный параметр форматирования: x: n: m, где m – количество десятичных знаков после запятой. Функции семейства printf языка C обладают более гибкими возможностями форматирования вывода. Во-первых, поддерживается множество форматов вещественных чисел: · обычный (%f); · экспоненциальный (%e) – числа выводятся всегда с экспонентой; · оптимальный (%g) – автоматически подбирает максимально удобный вид числа. Во-вторых, позволяют задавать ширину поля – %nz, %n.mz (n и m имеют тот же смысл, что и в Pascal, z – требуемый формат). Если использовать запись %0nz или %0n.mz, то неиспользуемые позиции слева заполнятся нулями. Если использовать знак «минус» (%–nz или %–n.mz), то выравнивание происходит не по правой, а по левой границе поля. В языке C++ существуют процедуры для форматирования вывода в поток (например, setw, ios:: flags, ios:: setf, ios:: unsetf, ios:: width, ios:: fill, ios:: precision). Функция setw определена в библиотеке iomanip.h, а класс ios – в библиотеке iostream.h. Все классы потокового ввода-вывода являются его наследниками. В случае необходимости, можно также записать число в требуемом формате в строку процедурой sprintf, а затем уже получившуюся строку подать на выход. Похожим образом обстоит дело и со строками. При чтении строк посредством функции fscanf нужно только помнить, что строковая переменная сама по себе является указателем на область памяти, в которой расположены символы строки, поэтому применение операции извлечения адреса не требуется. Поэтому и объявляться строка должна так же, как массив-вектор. Например: char s1[20]; char s2[] = “qwerty”; char *s3; char *s4 = “error! ”; В первом случае создается строка на 20 символов, во втором – требуемое количество символов подсчитывается компилятором. В данном случае это 7 (добавляется символ конца строки). Эту запись можно представить в том виде, в котором инициализируются числовые массивы: char s2[] = {‘q’, ‘w’, ‘e’, ‘r’, ‘t’, ‘y’, ‘\0’}; В третьем случае строка не создается, объявляется только указатель. Если мы хотим в эту строку что-либо поместить, то нужно предварительно выделить память, а после того, как надобность в ней отпадает, освободить: s3 = new char [20]; // используем s3 delete [] s3; Квадратные скобки явно указывают компилятору на то, что удаляется именно массив. В четвертом случае память не выделена, поэтому приведенная запись ошибочна. Происходит попытка занести данные по неинициированному указателю. Единственной особенностью является то, что Pascal считает разделителем строк символ перевода строки, а C – символ пробела. Поэтому нужно грамотно использовать функции read и readln в языке Pascal, чтобы не считать пустую строку (если указатель в файле находился в конце предыдущей строки). А в C использовать ограничители ввода, если строка может содержать пробелы. Например, формат %[^\n]s в Borland C++ позволит прочитать строку, остановившись на символе конца строки (\n). Другие компиляторы могут иметь свои способы ограничения ввода. При выводе строк действуют практически те же правила форматирования, что и при выводе целых чисел. Т.е. используется запись write(f, s: n) в Pascal или формат %ns в C для вывода строки в поле фиксированной ширины. Кроме того, в C можно использовать формат %-ns, тогда строка выравнивается (по аналогии с выводом числа) по левому, а не правому краю поля. Классы ввода-вывода языка C++ обладают всей функциональностью средств вывода данных языка C, только достигается это не определением формата, а, в основном, вызовом перечисленных выше методов класса ios. Для более подробной информации смотрите справку.
|