Строится синоним имени с помощью ключевого слова typedef.

Примеры:

typedef int INT //INT-синоним типа int

INT x, y;

typedef unsigned size_t;

size_t x, y; //переменная типа unsigned

typedef char string[225];

string array; //char array[225];

1. Функция typedef даёт имена типам данных.

2. Выполняется компилятором.

3. Более гибка, чем #define.

Испоьзование типа real вместо float:

typedef float real;

real x, y[5], *px;

если определение расположено внутри функции, то область действия локальна, вне функции глобальна.

typedef char* STRING //STRING-идинтификатор указателя на тип char.

STRING name, sign; //char*name,*sign;

Определение именнованных констант

Существуют 3 вида именнованных констант:

- имя любого массива или функции;

- имена членов перечисления;

- любое имя любого типа, в определении которого присутствует модификатор const.

const i = 5;

const char *ip = &i;

Поскольку модификация такого объекта-константы запрещена, он должен быть инициализирован.

const int *ip; //константой является объект, на который указывает указатель;

int* const ip; //сам указатель является константой

const char *pc = "Это строка";

pc[2] = 'a'; //ошибка

pc = "Это другая строка"; //верно

char* const pc = "Это строка";

pc[2] = 'a'; //верно

pc = "Это другая строка"; //ошибка

Использование const предпочтительнее по сравнению с #define, так как использование константы контролирует компилятор.

Перечисления

Спецификатор 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);

}

}

18.  ДИНАМИЧЕСКОЕ ВЫДЕЛЕНИЕ ПАМЯТИ

До сих пор в программе использовались переменные и массивы, создаваемые компилятором языка. Однако при этом не рационально расходуется память.

В отличие от статических и автоматических данных, память под которые распределяется компилятором, динамически распределяемая память выделяется программой самостоятельно. Время жизни таких объектов также определяется программой. Память выделяется по мере необходимости и должна освобождаться, как только данные, содержащиеся в ней больше не нужны. Доступ к ней осуществляется при помощи указателей.

Функции создания динамических переменных и массивов объявлены в заголовочных файлах <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 Кбайта - размера одного сектора.

Операция 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, будучи ключевым словом, не нуждается в прототипе.

Операция new с массивами

Если "имя" это массив, то возвращаемый new указатель указывает на первый элемент массива. При создании с помощью new многомерных массивов следует указывать все размерности массива:

mat_ptr = new int[3][10][12]; // так можно

mat_ptr = new int[3][][12]; // нельзя

...

delete [] mat_ptr; //освободить память, занятую массивом,

//на который указывает mat_ptr

Инициализаторы с операцией new

Другим преимуществом операции new по сравнению с malloc является возможность инициализации. При отсутствии явных инициализаторов объект, создаваемый new, содержит непредсказуемые данные ("мусор"). Объекты, распределяемые new, за исключением массивов, могут инициализироваться соответствующим выражением в скобках:

int_ptr = new int(3);

Для очистки выделенной памяти операцией new можно использовать функцию meset(), объявленную в <mem. h>. Ей передаются 3 параметра: адрес очищаемой памяти, символ для очистки, количество байт.

#include <string. h>

#include <stdio. h>

#include <mem. h>

int main(void) {

char buffer[] = "Hello world\n";

printf("Буфер до memset: %s\n", buffer);

memset(buffer, '*', strlen(buffer) - 1);

printf("Буфер после memset: %s\n", buffer);

return 0;

}

Проблемы, возникающие при использовании динамичски распределяемой памяти

1). Недоступные блоки - блоки памяти, указатели на которые потеряны.

2). Висящие ссылки - указатели на освобожденные блоки памяти.

3). Повторное освобождение динамической памяти. Недоступные блоки возникают после выделения памяти при присваивании указателю какого - либо другого значения или при уничтожении локального указателя после выхода из области видимости.

Пример 1:

int *a1, *a2;

a1 = new int[1000]; //выделили память

... //что-то делаем

a1 = a2; //ошибка - присвоение а1 другого

//значения - память недоступна

Пример 2:

void func(void)

{

int * a1;

a1 = new int[1000];

...

} //ошибка - при выходе из функции автоматически

//уничтожен a1,а память, тем не менее, осталась

Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9 10 11 12