Битовые поля
Перечисления
Спецификатор enum позволяет программисту создавать собственные типы.
enum weekDays {Monday, Tuesday, Wensday, Thursday, Friday};
Идентификаторы перечисления представляют собой целочисленные переменные, которые по умолчанию имеют значения 0,1,..., если не указаны другие значения.
weekDays days;
Переменная days теперь может принимать одно из 5 значений.
days = Wensday;
Пример 2.
enum colors {Red=2, Green=3, Grey};
Если задано значение впереди стоящему члену перечисления, то Grey по умолчанию будет равен 4.
Пример 3.
enum VIDEO_BASE_ADDRES { VGA_EGA=0xA000000, CGA=0xB800000,
MONO=0xB000000};
В некоторыя задачах для экономии памяти необходимо упаковывать несколько объектов в одно машинное слово. В Си для этого определяются поля и доступ к ним. Поле – это последовательность битов внутри одного целого значения.
struct { unsigned a:8;
unsigned b:6;
unsigned c:2;}d;
Определяем структуру d, содержащую поле а – 8 битов, поле b – 6 битов, с – 2 бита. Поля описываются как unsigned, чтобы подчеркнуть, что это величины без знака. Отдельные поля теперь обозначаются как d.a, d.b, d.c. С полями можно выполнять различные операции.
|
|
d.a= d.b=(d.c<<2)+6;
Поля не могут переходить за границу слова в ЭВМ. Если же очередное поле не помещается в частично заполненное слово, то под него выделяется новое слово. Поля могут быть безымянными. Используются как заполнители. Для принудительного перехода на новое слово используется специальный размер 0.
struct {unsigned a:8;
:2;
unsigned b:6;
:0;
unsigned c:12;} d;
Битовые поля и объединения можно применять для неявного преобразования типов.
Пример 1.
struct DOS_DATE { unsigned int day:5;
unsigned int month:4;
unsigned int year:7;};
union DATE_CONV { unsigned int packed_date;
struct DOS_DATE unpacked_date;};
typedef union DATE_CONV DATE
void main(void) {
struct ffblk ff; //структура в которую читается информация о
//файле из каталога, описана в <dir.h>
int done=findfirst(“*.*”, &ff,0); //ищет первый файл в каталоге
if(!done) {
DATE d;
d.packed_date=ff.ff_date;
printf(%2d/%2d/%4d”, d.unpacked_date.day, d.unpacked_date.month, d.unpacked_ date.year+1980);
}
}
До сих пор в программе использовались переменные и массивы, создаваемые компилятором языка. Однако при этом не рационально расходуется память.
В отличие от статических и автоматических данных, память под которые распределяется компилятором, динамически распределяемая память выделяется программой самостоятельно. Время жизни таких объектов также определяется программой. Память выделяется по мере необходимости и должна освобождаться, как только данные, содержащиеся в ней больше не нужны. Доступ к ней осуществляется при помощи указателей.
Функции создания динамических переменных и массивов объявлены в заголовочных файлах <alloс.h>, <stdlib.h>.
1. Функция void* malloc(размер) - выделяет в «куче» n байтов и возвращает указатель на 1-й байт, иначе возвращает 0. Необходимо делать преобразование типов.
|
|
void main(void){
char *original=”Исходная строка”;
char *copy;
copy=(char*)malloc(strlen(original)+1);
if(copy==NULL) {
puts(“Ошибка выделения памяти”);
exit(1);
}
strcpy(copy,original);
cout<<copy<<endl; cout<<original<<endl;
free(copy);
}
При выделении памяти она не очищается. Размер указывается в байтах.
2. Функция void* calloc(n,size type);
long* newmas = (long*)calloc(100,sizeof(long));
первый параметр - количество требуемых ячеек памяти;
второй параметр - размеp каждой ячейки.
Функция calloc() обнуляет выделенную память.
#define SIZE 128
void main(void) {
char *str=(char *)calloc(1,SIZE);
if(str==NULL) {
puts(“Ошибка выделения памяти”);
exit(1);
}
else {
cout<<”Введите строку”;
gets(str);
cout<<str;
free(s);
}
}
3. void* realloc(void *, n) - изменяет размер ранее выделенного блока памяти. Если дополнительная память выделяется в новом месте оперативной памяти, то уже введенная информация переписывается в новое место.
ptr = realloc(nptr, size);
где nptr - указатель на ранее выделенный блок; size размер выделяемой памяти.
void main(void) {
char *p1, *p2;
puts(«Выделяем 128 байт»);
p1=malloc(128);
if(p1) {
puts(“Изменяем размер блока на 256 байтов”);
p2=realloc(p1,256); //блок теперь равен 256 байтам
}
if(p2)
free(p2);
else
free(p1);
}
4. void free(void *ptr) - освобождение выделенной памяти. Количество выделенной
динамически памяти не может превышать 64 Кбайта - размера одного сектора.
18.1 Операция new и delete в С++
В С++ появились операции выделения динамической памяти и удаления (освобождения) динамической памяти.
Операции new и delete выполняют динамическое распределение и отмену распределения памяти, аналогично, но с более высоким приоритетом, нежели стандартные библиотечные функции семейства malloc и free.
Упрощенный синтаксис:
указатель-имени = new имя <инициализатор-имени>;
...
delete указатель-имени;
Имя может быть любого типа.
new пытается создать объект с типом "имени", распределив (при возможности) sizeof(имя) байт в свободной области памяти (которую также называют "кучей"). Продолжительность существования в памяти данного объекта - от точки его создания и до тех пор, пока операция delete не отменит распределенную для него память.
В случае успешного завершения new возвращает указатель нового объекта. Пустой указатель означает неудачное завершение операции (например, недостаточный объем или слишком большая фрагментированность кучи). Как и в случае malloc, прежде чем пытаться обращаться к новому объекту, следует проверить указатель на наличие пустого значения. Возвращаемый указатель будет иметь правильный тип, "указатель имени", без необходимости явного приведения типов.
name *nameptr // name может иметь любой тип, кроме функции
...
if (!(nameptr = new name)) {
errmsg("Недостаточно памяти для name");
exit (1);
}
...
delete nameptr; //удаление name и отмена выделения
//sizeof(name) байтов памяти
new, будучи ключевым словом, не нуждается в прототипе.