Структуры, перечисления, объединения. Бинарные файлы

advertisement
Структуры,
перечисления,
объединения.
Бинарные файлы
Алгоритмизация и
программирование
2 триместр, лекция 1
Перечисления
enum [<имя типа>] ′{′<список констант>′}′;
enum Err {ERR_READ, ERR_WRITE, ERR_CONVERT};
Err error;
…
switch (error) {
case ERR_READ: /*операторы*/ break;
case ERR_WRITE: /*операторы*/ break;
case ERR_CONVERT: /*операторы*/ break;
};
//Константам ERR_READ, ERR_WRITE, ERR_CONVERT
//присваиваются значения О, 1 и 2 соответственно.
Значения констант в
перечислении можно задавать…
enum {two=2, three, four=two+2, ten=10, eleven} C;
C = four;
if (C>ten)
cout << "Второй десяток!";
//Константе three присваивается
//значение 3, константе eleven — 11.
Перечисления
enum City {Moskow, Perm, Novosibirsk,
Kirov, Vologda, Minsk, Astana, Kiev};
City X,Y;
X = Moskow;
Y = City(X+2); // Y=Novosibirsk
X = (City)(Y-3); // значение X равно (-1)
// в типе City такого значения нет.
// Но ошибки не произойдет!
cout << X << ′ ′ << Y;
// Будет выведено: -1 2
Перечисления
enum Sex {Man, Woman};
Sex a=Man;
a=Sex(a+1);
if (a==Woman)
cout << "Woman";
else
cout << "Man";
Как вывести значение
перечислимого типа именем
enum Color
{Black,Red,Green,Blue,Yellow,White};
string NamesColor[6] =
{"Черный","Красный", "Зеленый",
"Синий","Желтый","Белый"};
Color Screen = Blue;
cout << NamesColor[Screen];
Перечисления



Имена перечисляемых констант должны
быть уникальными, а значения могут
совпадать.
При выполнении арифметических
операций перечисления преобразуются в
целые значения.
Поскольку перечисления являются
типами, определяемыми пользователем,
для них можно вводить собственные
операции.
Типы, определяемые
пользователем
typedef <тип> <новое имя>
[<размерность>];
typedef unsigned int UINT;
UINT a;
unsigned int a;
Эквивалентные
описания
Типы, определяемые
пользователем
typedef char Msg[100];
Msg str[10];
/*массив из 10 строк по 100
символов каждая*/
Структуры
Имеются данные о студентах в формате:
- ФИО (строка символов)
- курс (целое число)
- средний балл зачетки (вещественное число)
string FIO[100];
int course[100];
double ball[100]
Неудобно сортировать,
высока вероятность
возникновения ошибок!
Задача. Объединить разнотипные
данные в один блок.
Структура – это тип данных,
позволяющий объединить в одно
целое данные различных типов
typedef struct
{
char FIO[40];
int course;
double ball;
}
TStudent;
TStudent X;
Поля
структуры
Имя типа
Описание
переменной типа
структура
Массив структур
typedef struct {
char fio[30];
int date, code;
double salary;
} Worker;
Worker staff[100];
Обращение к полю
структуры (dot-нотация)
<переменная типа структура> . <имя поля>
X.ball = 4.55;
X.course = 3;
staff[0].salary = 34000;
Staff[0].code = 321;
C данными поля можно делать все,
что позволяет тип поля!
Вложенные структуры
Полем структуры так же может быть структура.
struct Date{int day,month,year;};
struct Student {
string FIO;
Date birthday;
bool Has_Tails;
} Nekto;
Nekto.FIO = "Соколов Иван Иванович";
Nekto.birthday.day = 29;
Nekto.birthday.month = 2;
Nekto.birthday.year = 1996;
Nekto.Has_Tails = false;
Перечислимый тип в
структурах
Использование перечислений
делает код нагляднее.
enum Month{Jan, Feb, Mar,
Apr, May, Jun, Jul, Aug,
Sep, Oct, Nov, Dec};
struct Data {
short day;
Month mon;
short year;};

Инициализация структур
struct{
char fio[30];
int date, code;
double salary;
} worker =
{"Страусенко",31,215,3400.55};
Student Nekto =
{"Соколов Иван Иванович",
{29, 2, 1996}, false};
Структуры

Для переменных одного и того же структурного
типа определена операция присваивания, при
этом происходит поэлементное копирование.
struct Group {
string name;
int count_student;
};
Group PMI12={"ПМИ-1,2",23},PMI34;
PMI34 = PMI12;
PMI34.name = "ПМИ-3,4";
Структуры
Поля разных структур могут иметь одинаковые имена,
поскольку у них разная область видимости. Более
того, можно объявлять в одной области видимости
структуру и другой объект с одинаковыми именами.
int a;
struct А
struct В
a=33;
х[0].а.а
х[1].х =
{int а; double х;};
{А а; double х;} х[2];
= 1;
0.1;
Битовые поля




Это особый вид полей структуры.
Они используются для плотной упаковки
полей данных, например, флажков типа
«да/нет».
Используются для целей экономии памяти
(минимальная адресуемая ячейка памяти 1
байт, а для хранения флажка достаточно 1
бита).
Код программы (машинный), использующей
битовые поля всегда длиннее, по сравнению с
той программой, которая их не использует.
При описании битового поля
после имени через двоеточие
указывается длина поля в битах
struct Options{
bool centerX:1;
bool centerY:1;
unsigned int shadow:2;
unsigneg int palette:4;
}
Любая последовательность элементов структуры типа
int или unsigned, в которой за каждым именем элемента
следует двоеточие и целая константа размещаются в
отдельном машинном слове в виде групп битов
(битовых полей). Константа определяет размерность
битового поля.
Допускается использование
безымянных полей, которые в таком
случае оказываются недоступными
struct man
{
char name[20];
unsigned dd:5;
unsigned mm:4;
unsigned yy:7;
char *address;
int xx:3;
int :5;
int zz:3;
} A;
A.dd = 12; A.mm = A.dd | 5; A.yy = 96 & A.dd;
A.dd++; A.zz = 6; A.xx = A.zz ^ 7;
Объединения






Объединение (union) представляет собой частный
случай структуры, все поля которой
располагаются по одному и тому же адресу.
Формат описания такой же, как у структуры,
только вместо ключевого слова struct
используется слово union.
Длина объединения равна наибольшей из длин
его полей.
В каждый момент времени в переменной типа
объединение хранится только одно значение.
Ответственность за его правильное
использование лежит на программисте.
Объединения применяют для экономии памяти в тех
случаях, когда известно, что больше одного поля
одновременно не требуется
Объединения
enum paytype {CARD, CHECK}:
paytype ptype;
union payment{
char card[25];
long check;
} info;
/* присваивание значений info и ptype */
switch (ptype){
case CARD: cout << "Оплата no карте: " <<
info.card; break;
case CHECK: cout << "Оплата чеком: " <<
info.check; break;
}
Объединение часто
используют в качестве поля
структуры
при этом в структуру удобно
включить дополнительное поле,
определяющее, какой именно
элемент объединения используется
в каждый момент.
 Имя объединения можно не
указывать, что позволяет
обращаться к его полям напрямую

Структура, использующая
объединение
enum paytype {CARD, CHECK}:
struct{
paytype ptype;
union{
char card[25];
long check;
};
} info;
... /* присваивание значения info */
switch (info.ptype){
case CARD: cout << "Оплата no карте: " <<
info.card; break;
case CHECK: cout << "Оплата чеком: " <<
info.check; break;
}
Объединения применяются также для
разной интерпретации одного и того
же битового представления:
struct Options{
bool centerX:1;
bool centerY:1;
unsigned int shadow:2;
unsigned int palette:4;
};
union{
unsigned char ch;
Options bit;
} option = {OxC4};
cout << option.bit.palette;
option.ch &= OxFO;
cout << option.bit.palette;
Размещение полей
объединения в памяти



В структуре (как и в массиве) элементы
расположены последовательно, а в
объединении «параллельно».
Для их размещения выделяется общая
память, в которой они перекрывают друг
друга и имеют в ней общий адрес.
Размерность объединения определяется
максимальной размерностью элемента
объединения.
Если записать в один элемент объединения
некоторое значение, то через другой
элемент прочитать это же значение можно
уже в другой форме
union memo
{
long ll;
int ii[2];
char cc[4];
int xx;
} MEM;
char z;
MEM.ll = 0x12345678;
Z = MEM.cc[2];
Объединение
может инициализироваться только
значением его первого элемента;
 не может содержать битовые поля;
 не может содержать виртуальные
методы, конструкторы, деструкторы
и операцию присваивания;
 не может входить в иерархию
классов.

Бинарные файлы
бинарный файл позволяет записать
содержимое внутренней памяти на
диск без преобразования - «байт в
байт»;
 это файл произвольного доступа – мы
можем одной командой переместиться
на любую позицию в файле;
 бинарный файл может быть
одновременно открыт на чтение и на
запись.

Операции с бинарными
файлами
ifstream f("in.dat“, ios::binary);
Открыть
на
чтение
ifstream f;
f.open("in.dat“, ios::binary);
ofstream f("out.dat“, ios::binary);
ofstream f;
f.open("out.dat“, ios::binary);
Открыт
ь на
запись
Операции с бинарными
файлами
Открыть
fstream f("a.dat“,
ios::in|ios::out|ios::binary);
fstream f;
f.open("a.dat“,
ios::in|ios::out|ios::binary);
на чтение
и на
запись
Запись
в файл
f.write((char*)<адрес>, <количество байт>)
Чтение
из
f.read((char*)<адрес>, <количество байт>)файла
Операции с бинарными
Переместить
файлами
указатель
для чтения
f.seekg(<смещение>, <позиция в файле>)
Переместить
указатель
для записи
f.seekp(<смещение>, <позиция в файле>)
ios::beg
ios::cur
ios::end
Возможные
значения
позиции в
файле
Операции с бинарными
файлами
Возвращает число
f.gcount()
f.peek()
f.eof()
f.close()
прочитанных
байтов
Возвращает содержимое
очередного байта без
перемещения указателя
Возвращает логическое
значение «был ли прочитан
символ конца файла
Закрыть файл
Чтение «до конца файла»
while (!f.eof())
{
<читаем из файла>
}
while (f.peek() != EOF)
{
<читаем из файла>
}
«Последнее»
значение будет
прочитано
дважды
Корректное
чтение из файла
неопределенной
длины
Верно так же и для текстовых файлов!!!
Определение корректно ли
произошла операция
открытия файла
fstream f;
f.open("a.dat",ios::in|ios::binary);
if (!f)
{
cout << "Файл открыть невозможно!\n";
}
Создать бинарный файл, в котором
сохранить последовательность
натуральных чисел вводимых
пользователем. Признак
окончания ввода – число 0.
Задача
ofstream f("a.dat",ios::binary);
int x;
while (1)
{
cout << "Введите число (0 - для выхода) ";
cin >> x;
if (!x) break;
else f.write((char*)&x,sizeof(x));
}
f.close();
Что хранится в файле?
Мы ввели
Так отобразит
Блокнот
16-ричные коды данных в файле
Распечатать содержимое бинарного
файла, в котором находится
последовательность натуральных
чисел.
Задача
ifstream f("a.dat",ios::binary);
int x;
while (f.peek()!=EOF)
{
f.read((char*)&x, sizeof(x));
cout << x << endl;
}
Как прочитать в файле целых
чисел элемент с номером K?
ifstream f("a.dat",ios::binary);
int x;
Смещение задается в байтах
f.seekg(sizeof(int)*(k-1),ios::beg);
f.read((char*)&x,sizeof(x));
cout << x;
Как прочитать последний
элемент в файле?
ifstream f("a.dat",ios::binary);
int x;
f.seekg(sizeof(int)*(-1),ios::end);
f.read((char*)&x,sizeof(x));
cout << x;
Как изменить K-ый
элемент в файле?
cin >> k;
f.seekg((k-1)*sizeof(int),ios::beg);
f.read((char*)&x,sizeof(x));
x = x*2;
f.seekp((k-1)*sizeof(int),ios::beg);
f.write((char*)&x,sizeof(x));
Как узнать сколько
элементов в файле?
При записи в
typedef struct{
бинарные
char FIO[80];
файлы в
int kurs;
структуре не
}
должны
TStud;
использоваться
...
указатели!!
ifstream F("stud.dat",ios::binary);
TStud tek[100];
int N;
F.read((char*)tek,sizeof(tek));
N = F.gcount()/sizeof(TStud);
Файлы бывают:
Текстовые
файлы
Последовательного доступа (N-ый
элемент можно почесть только
тогда, когда прочитаны
предыдущие элементы (N-1) штук)
 Произвольного доступа (N-й
элемент можно прочесть сразу же
не считывая предыдущие
элементы)

Бинарные
файлы
Преимущество бинарных
файлов
Прямой доступ к элементам => высокая
скорость работы
 Чтение и запись больших объемов
данных возможна «одной» командой.
 Можно одновременной «читать» и
«писать».
 Простейший вариант «шифрования»
данных

Преимущество текстовых
файлов
Можно редактировать содержимое
в текстовом редакторе.
 Часто используются, например,
для передачи данных по сети
Internet требуются именно
текстовые файлы.
 Данные в текстовых файлах легко
переносимы для программ на
других языках и платформах.

Download