Тема 3
Разработка сложных программных продуктов
Лекция 3.6.
Обработка данных со сложной структурой .
Литература
Основная:
Подбельский В.В., Фомин С.С. Программирование на языке Си: Учеб. пособие. – М.: Финансы и статистика, 2004.
Дополнительная:
С/ C ++ Структурное программирование. Практикум. Программирование на языке высокого уровня. Питер, 2004.
Юркин А. Задачник по программированию. Гриф МО. Учебное пособие, Питер, 2002.
Шмидт Г. Самоучитель Си++. СПб.: БХВ – Петербург, 2004.
Вопросы:
1. Строковые типы данных и их обработка.
2. Записи и работа с ними.
3.Файлы и работа с ними.
1. Строковые типы данных и их обработка.
Для представления текстовой информации используются:
- символы;
- строки;
- символьные переменные.
Для отображения отдельных знаков используют символьные константы, которые состоят из изображения символов и ограничивающих апострофов. Например, ‘d’ , ‘D’ , ‘ 0 ’ , ’ 9 ’ , ’+’ .
Внутри апострофа можно записать любой символ, имеющийся на клавиатуре. Для задания символов, отсутствующих на клавиатуре (например, символа перевода строки), используют специальные коды – управляющие последовательности. Управляющая последовательность начинается с апострофа, обратной косой черты, за которой идет специальный символ или специальный код.
Примеры управляющей последовательности:
‘ \n’ – перевод строки;
‘ \t’ – горизонтальная табуляция;
‘ \’’ – апостроф (одинарная кавычка)
и другие.
Специальный код задается в виде ‘\ddd’ либо ‘\xhh’ или ‘\Xhh’ .
ddd – восьмеричное представление символа. Здесь – d восьмеричная цифра от 0 до 7. Например, ‘\ 127 ’ ;
xhh или Xhh – шестнадцатеричное представление символа. Здесь h – шестнадцатеричная цифра. Например, ‘\x 2 F’ .
Коды символов обычно приведены в приложениях к книгам по программированию.
В частности, ‘\ 077 ’ соответствует вопросительному знаку, ‘\x 2 F’ – наклонной черте « /».
Символьные константы имеют целый тип, их можно использовать в качестве целочисленных операндов в арифметических выражениях.
Числовое кодирование символов позволяет проводить их упорядочение.
Для символьных данных введен базовый тип char .Описание символьных переменных:
char список имен_переменных ;
Например char s1, z;
Переменные этого типа могут принимать значения в диапазоне от 0 до 255. Переменные этого типа можно рассматривать целочисленные и как символьные переменные.
Например, фрагмент программы:
char z;
for (z=‘0’; z z++ )
printf (“ \ n%c - %d”, z, z);
Приведет к отображению
0 – 48
1 – 49 и т.д.
В программе строки записываются в виде последовательности символов, заключенных в кавычки, например
“ Zadacha 1 \ nZadacha 2”
Длина строки произвольная, в том числе пуста строка, строка из одного символа. Для обозначения конца строки компилятор в ее конец добавляет символ ‘\0’ - признак ее окончания.
Переменных для задания символьных строк нет. Строку можно рассматривать как массив символов типа char[] . Количество символов в таком массиве всегда на 1 больше, чем в отображении строковой константы за счет «нулевого» байта. Пример объявления массива символов
char x1[]=“ Пример массива символов ”;
Для работы со строками есть специальные библиотеки функций. Для их использования надо подключить файлы string.h, stdlib.h.
2. Записи и работа с ними
Записи (структуры)
Структурный тип объединяет в единое целое совокупность поименованных компонентов различных типов, в отличие от массива, который объединяет однотипные данные.
Применение структур позволяет упорядочить представление информации о сложном объекте, упростить разработку сложных программ на основе объектно-ориентированного программирования.
Объявление структур выполняется в два этапа:
- Описание типа структуры;
- Объявление конкретных объектов с указанной структурой.
Описание типа структуры
Пример
struct disz
{
char name [20]; //*Наименование дисциплины
int aud ; // Аудиторные занятия
int self ; // Самостоятельная работа
float sr _ ball ; // Средний балл
char otchet [10]; // Отчетность
};
В этом описании:
struct является спецификатором структурного типа (служебное слово);
dis z – выбранное программистом наименование структурного типа;
в фигурных скобках расположены описания элементов, которые будут входить в каждый объект типа dis z .
Описание заканчивается точкой с запятой.
Конструкция struct имеет то же значение, что и указание типа простых переменных. Само описание структуры не означает объявление соответствующей переменной, память на размещение элементов структуры не выделяется.
Объявление конкретных объектов с указанной структурой:
struct disz mathem , phil ;
После такого объявления структур mathem и phil им выделяется память (назначение сочетания слов struct disz подобно, например, объявлению типа int для переменных).
Операции над структурами
Прямое присваивание :
mathem = phil ;
Сравнение
Структуры нельзя непосредственно сравнивать друг с другом. Сравнение разрешено проводить только поэлементно.
Доступ к элементам структур производится с помощью уточненных имен – имени структуры и имени элемента, разделенных точкой. В обращении перед точкой стоит не название структурного типа, а наименование конкретной структуры
имя_структуры. имя_элемента
Например, обращение к элементу, содержащему название учебной дисциплины в структуре mathem
mathem . name
Тип результата обращения к элементу структуры соответствует типу этого элемента.
Уточненные имена можно использовать в выражениях, в операторах присваивания, в качестве фактических параметров при обращении к функциям, т.е. практически везде, где могут размещаться имена обычных объектов
mathem.aud = 100 – mathem.self*2;
scanf("\n%f",&mathem.sr_ball);
printf("\n Назв. дисциплины :%s", mathem.name);
Массивы как элементы структур и массивы структур
Массивы, в том числе и символьные массивы, могут быть элементами структур наравне с другими компонентами данных, что и было использовано при задании имени учебной дисциплины name . Обращение к элементу массива из состава структуры требует задания индекса, подобно обращению к элементу обычного массива, например
mathem.name[0]='M';
mathem.name[1]='a';
. . .
mathem . name [10]='\0';
Массивы структур
Определяются подобно объявлению массивов других типов, например
struct disz kurs 1[17];
Это объявление определяет kurs1 как массив из 17 структур типа disz . Элементами массива будут структуры kurs1[0] , kurs1[1] , …, kurs1[16] . Доступ к элементам массива структур осуществляется посредством уточненных имен, например
обращение к имени 6-й дисциплины:
kurs 1[5]. name
обращение к первому символу имени 6-й дисциплины:
kurs 1[5]. name [0]
Объединения
Объединения рассматривают как подобие структуры, все элементы которой имеют нулевое смещение от ее начала – содержимое одного и того же участка памяти интерпретируется по-разному в зависимости от целей. Доступ к такому компоненту осуществляется с помощью переменных или элементов массива разных типов. Описание объединения производится с помощью атрибута union .
Объединение можно задать в виде
union имя_типа
{
определения элементов объединения
};
Пример описания объединения как типа данных
union bt
{
int ao1;
char c1[2];
};
В данном примере bt соответствует типу данных , а не конкретному объединению. На основе такого определения типа вводится конкретное объединение а1
union bt a 1;
Именно конкретному объединению выделяется память. Размер выделяемой памяти определяется самым "большим" элементом объединения.
Приведенный пример объединения позволяет наряду с идентификатором целого числа ао1 применять идентификаторы с1[0] и с1[1] для работы со старшим и младшим байтом этого числа соответственно. Обращение к элементу объединения производится подобно обращению к элементу структуры, в частности обращение к старшему байту числа оформляется как
а1.с[0]
где а1 – имя конкретного объединения. При адресации допускается применение указателей.
Константы перечисляемого типа
enum название { список именованных констант };
где enum – служебное слово;
название – необязательный идентификатор;
список именованных констант – список идентификаторов или именованных констант вида имя или имя = значение . Примеры записи констант перечисляемого типа
enum holiday { Sunday , Saturday };
enum quart { one =3, two , three };
Если в списке нет элементов со знаком "равно", то значение первой константы будет равно нулю, для следующих элементов списка значение увеличиваются на единицу слева направо.
В первом примере константа " Sunday " равна нулю, " Saturday " имеет значение 1.
Во втором примере константа " one " получает значение 3, " two " – значение 4, " three " – значение 5.
3. Файлы и работа с ними
В языке Си все файлы рассматриваются как неструктурированная последовательность байтов. Такой подход позволяет единообразно представить информацию при обмене с различными типами устройств. Одни те же функции языка применяют при файловом обмене и обмене данными с устройствами. Виды обмена данными:
- потоковый ввод и вывод, в том числе обмен с консолью оператора;
- ввод и вывод нижнего уровня;
- обмен с портами компьютера.
Обмен нижнего уровня и обмен с портами компьютера реализуется различно в разных операционных системах и рассматриваться не будет.
Потоковый обмен производится побайтно, что характерно для печатающих устройств, работающих в тестовом режиме, клавиатуры. Но такой вид обмена не вполне соответствует принципам работы поблочных устройств, в частности, обмену с магнитными дисками. Обмен с магнитными дисками производится блоками:
при чтении информации с диска блок данных помещается в буфер ОС, а затем побайтно данные передаются программе пользователя;
при выводе данные накапливаются в буфере, и по мере формирования блока ОС записывает блок на диск.
Работа с потоком включает:
- открытие и закрытие потока;
- ввод и вывод символов, строк, форматированных данных;
- анализ ошибок обмена, ситуации конца файла;
- управление размером буфера, процессом буферизации;
- получение и установка указателя текущей позиции в потоке.
Стандартные средства, обеспечивающие потоковый обмен данными, содержатся в файле stdio . h . Работа с потоком начинается с его открытия (инициализации). Конкретный поток связывается в исполняемой программе со структурой FILE (слово записывается большими буквами). Определение этой структуры находится в файле stdio . h . Структура FILE содержит компоненты, обеспечивающие работу с потоком, в частности, указатели на буфер, на поток, текущей позиции и т.п. Объявление указателя
FILE *pf;
Конкретное значение указатель на поток приобретает при выполнении функции открытия потока
pf = fopen ( имя файла , режим открытия );
Указатель идентифицирует поток в последующих операциях. Имя файла задают как текстовая константа в виде имени и расширения, заключенного в двойные кавычки. Режим открытия обозначается одним или несколькими символами, заключенными в кавычки:
"а" – открытие существующего файла или создание нового, если файла с заданным именем нет, для добавления в него новой информации. Добавление производится в конец файла;
"а+" – открытие существующего файла или создание нового, если файла с заданным именем нет, для внесения данных в любое место файла или для чтения из любого места файла. В этом режиме можно дописывать символы и в конец файла;
" r " – открытие существующего файла только для чтения;
" r +" – открытие существующего текстового файла для чтения и для записи в любое место файла. Запись в конец файла невозможна, т.е. увеличение размера файла не допускается;
" w " – открытие файла для записи. Если файл существовал, то его содержимое уничтожается (файл создается заново);
" w +" – открытие файла для записи и последующих исправлений. Если файл существовал, то его содержимое уничтожается (файл создается заново). После открытия разрешается запись и чтение из любого места файла, в том числе, разрешена запись в конец файла.
Итак, символ " + " указывает на открытие потока для изменений. Смена режима в таком потоке (переход от чтения к записи или наоборот) должна осуществляться только после установки указателя потока в нужную позицию.
При открытии потока возможно появления различного рода ошибок: не найден файл (для режима чтения); диск защищен от записи или заполнен (для режима записи или внесения исправлений); недостаточно основной памяти для выделения буферного участка и т.д. Подобные ошибки приводят к тому, что указатель на поток приобретает значение, соответствующее константе NULL . Если ошибок нет, то указатель приобретает значение, отличное от значения NULL .
Типичная совокупность операторов открытия файла
if (( pf = fopen (" uch . txt "," ab "))== NULL )
{
perror ("\ n ошибка открытия файла uch . txt \ n ");
exit (0);
}
При возникновении ошибки ОС выдает сообщение, например, « Ошибка защиты от записи диск А », и предоставляет на выбор три варианта решения: А ( Abort ) – завершение программы, R ( Retry ) – повторение операции, F ( Fail ) – сброс ошибки. Оператор должен ответить, набрав латинскую букву, соответствующую желаемому варианту действий. В ответ на выбор варианта Fail будет выполняться стандартная библиотечная функция perror () , которая выводит указанную строку символов. Содержание и формат системного сообщения об ошибке определяется конкретной операционной системой.
После открытия с файлом можно работать, т.е. выполнять операции, разрешенные выбранным режимом.
Завершив работу с файлом, его следует закрыть, используя функцию fclose . Аргументом функции является указатель на файл, например
fclose(pf);
Обмен данным с дисками осуществляется аналогично стандартным потокам ввода и вывода. Функции поддержки такого обмена:
fprintf () – форматированный вывод в файл;
fscanf () – форматированное чтение из файла;
fputs () – запись строки в файл;
fgets () – чтение строки из файла.
Форматированный обмен осуществляется практически идентично обмену для стандартного потока с помощью функций scanf () и printf () соответственно. Различие заключается только в необходимости задания указателя на поток. Прототипы функций
int fscanf ( указатель на поток, форматная строка, список адресов переменных );
int fprintf ( указатель на поток, форматная строка, список переменных );
Примеры записи функций форматированного обмена
fscanf ( pf ,"% d ",& n );
fprintf(pf,"%s", name);
Рассмотренные средства позволяют читать из файла и записывать в файл информацию строго последовательно – операции обмена начинаются с текущей позиции в потоке. Начальная позиция устанавливается при открытии потока. При открытии потока в режиме " а " указатель устанавливается в конец файла за последним байтом, а при открытии в режимах " r " и " w " – на начальный байт. В ходе обмена указатель текущей позиции перемещается на новую позицию в соответствии с количеством переданных символов.

Обработка данных со сложной структурой (194.5 KB)

