2812

Структура программы и модификаторы типа указателей в ОС MS-DOS

Лекция

Информатика, кибернетика и программирование

Лекция. Структура программы и модификаторы типа указателей в ОС MS-DOS В общем виде программа на языке C состоит из директив препроцессора, объявлений и определений объектов, команд, которые могут быть записаны как в одном, так и в нескольких моду...

Русский

2012-10-19

53.5 KB

4 чел.

Лекция 13

Структура программы и модификаторы типа указателей в ОС MS-DOS

В общем виде программа на языке C состоит из директив препроцессора, объявлений и определений объектов, команд, которые могут быть записаны как в одном, так и в нескольких модулях. В последнем случае при сборке программы создаётся файл проекта, в котором указываются имена всех входящих в проект файлов. Обязательно наличие одной и только одной функции main() в одном из файлов с исходными текстами. Функция main() задаёт точку входа в программу – с этой функции начинается и ей же заканчивается выполнение программы (в общем случае программа может быть завершена использованием системных функций завершения независимо от окончания функции main()).

Загрузочный модуль (типа .exe) ОС MS-DOS имеет структуру, показанную на рисунке 1.

Рис.1

Секция кода – содержит код программы (функции программиста и библиотечные функции).

Секция данных – содержит инициализируемые данные (глобальные и статические переменные) и неинициализируемые данные (константы).

Стек – используется для хранения автоматических объектов, передачи параметров и сохранения адреса возврата при вызове функции.

Ближняя куча (near heap) –динамически выделенная память.

Свободная память – память, не используемая программой.

После загрузки программы на исполнение положение и границы секций кода и данных фиксированы, начало кучи и стека (начало стека располагается снизу, а не сверху) также фиксированы, а их границы изменяются в процессе выполнения в зависимости от действий программы (направление увеличения их размеров показано стрелкой).

Регистр процессора – это ячейка памяти внутри процессора. Процессоры x86 для адресации в реальном режиме работы используют 4 сегментных регистра: CS (регистр кода, по нему происходит адресация кода программы), DS (регистр данных, по нему происходит адресация данных), SS (регистр стека, по нему производится адресация стека) и ES (дополнительный регистр, как правило дублирует регистр данных). Регистр указывает на определённый адрес в памяти, из которого можно обращаться к 64K (размер одного сегмента) ячейкам памяти по смещению относительно сегментного регистра (чтобы адресоваться к ячейкам памяти, лежащим за пределами доступных 64K, необходимо изменять значение сегментного регистра, что при программировании на языке C явно делать крайне нежелательно). Указатель называется ближним (near), если он содержит только значение смещения (сегментный адрес берётся из соответствующего сегментного регистра), данный указатель может адресоваться к 64K ячейкам памяти. Указатель называется дальним (far), если он содержит и сегментный адрес, и смещение относительно сегментного адреса, данный указатель может адресоваться к 1M ячейкам памяти. Указатель может быть указателем типа huge. Отличие указателей типа far от указателей типа huge состоит в том, что при выполнении арифметических операций с указателем типа far изменяется только смещение, сегментная часть остается постоянной, и указатель типа far может адресоваться только к 64K ячейкам памяти, чтобы его сместить, необходимо в программе явно изменять сегментную часть (проводить нормализацию), а при выполнении арифметических операций с указателями типа huge изменяться также будет и сегментная часть, поэтому можно адресоваться к любой ячейке в пределах 1M, такой указатель хранится в памяти в нормализованном виде.

Длину указателя определяет специальный модификатор (near, far или huge), используемый при объявлении указателя.

Следует учитывать, что одна ячейка памяти – это один байт. Если указатель указывает на объект, размер которого отличен от 1 байта, то в пределах одного сегмента указатель может обращаться не к 64K элементам, а к 64K/(размер типа) элементам. Например, указатель типа float в пределах сегмента будет обращаться к 64K/4=16K элементам, которые будут занимать 64K ячеек памяти.

Пример 1

float near *f;

int far *i;

char huge *c;

Модели памяти.

Особенности операционной системы MS-DOS требуют дополнительных уточнений относительно распределения памяти ЭВМ. Для этого определяются 6 моделей памяти.

Модель TINY.

Общий объём памяти для кода, данных и стека – 64K. Все указатели – ближние.

Модель SMALL.

Общий объём памяти для кода – 64K, для данных и стека – 64K. Все указатели по умолчанию – ближние, но для данных могут использоваться и дальние указатели. Начиная с этой модели в программе появляется возможность использования дальней кучи (far heap) для динамического использования памяти. К дальней куче могут обращаться только дальние указатели.

Модель MEDIUM.

Рекомендуется для больших программ с малым количеством статических данных. Общий объём памяти для кода каждого модуля – 64K, для данных и стека – 64K. Указатели данных по умолчанию – ближние, указатели функций по умолчанию – дальние.

Модель COMPACT.

Рекомендуется в случае с малым объёмом кода, но большим объёмом данных. Общий объём памяти для кода – 64K, для данных – 64K, для стека – 64K. Указатели данных по умолчанию – дальние, указатели функций по умолчанию – ближние. Начиная с этой модели отсутствует ближняя куча.

Модель LARGE.

Общий объём памяти для кода каждого модуля – 64K, для данных – 64K, для стека – 64K. Все указатели – дальние.

Модель HUGE.

Общий объём памяти для кода каждого модуля – 64K, для данных каждого модуля – 64K, для стека – 64K. Все указатели – дальние.

Данные модели памяти используются в среде Borland C++ 3.1 для ОС MS-DOS. Установка модели осуществляется в диалоговом окне Code Generation, вызываемом командой меню Options>Compiler>Code Generation.

Динамическое распределение памяти

Динамическое распределение памяти используется для выделения памяти для хранения данных в процессе работы программы, когда общий объём данных и сами данные на этапе написания программы не известны, а становятся известны лишь на этапе выполнения программы. Динамическое распределение памяти позволяет получить необходимый объём памяти для ближней или дальней кучи, в зависимости от типа указателя и модели памяти. Для этого существуют специальные библиотечные функции, описанные в файле alloc.h.

Процесс работы с динамической памятью:

  •  получение динамической памяти заданного объёма;
  •  работа с данными, распределяемыми в динамической памяти (если необходимо, то возможно перераспределение выделенного объёма памяти с сохранением находящихся в нём данных);
  •  освобождение динамической памяти по окончании работы с данными.

Для получения блока динамической памяти используются функции malloc() и calloc(). Прототипы функций:

void* malloc(size_t size);

void* calloc(size_t nitems, size_t size);

Функция malloc() в качестве аргумента принимает размер запрашиваемого блока в байтах. Функция calloc() в качестве первого аргумента принимает число элементов, под которые необходимо выделить память, в качестве второго аргумента – размер одного элемента в байтах. Тип size_t аналогичен типу unsigned int. Функции в случае успешного выделения возвращают указатель на тип void, содержащий адрес выделенного блока, который нужно явно преобразовать к указателю на необходимый тип данных. В случае ошибки (как правило связанной с тем, что такого объёма свободной памяти нет) функции возвращают значение NULL. NULL – это стандартная константа языка C, которая обозначает нулевой указатель. После выполнения динамического распределения памяти необходимо обязательно проверять, какое значение возвратили функции. Если значения указателя – NULL, то работа с памятью невозможна (в большинстве случаев следует завершить программу).

Для перераспределения уже выделенного объёма памяти используется функция realloc(). Прототип функции:

void* realloc(void* block, size_t size);

Функция изменяет размер ранее выделенного блока, сохраняя его содержимое. В качестве первого аргумента функция принимает адрес ранее выделенного блока, в качестве второго аргумента – новый размер блока, при этом новый блок может оказаться в другом месте кучи. Функция в случае успешного выделения возвращает указатель на тип void, содержащий адрес нового блока, который нужно явно преобразовать к указателю на необходимый тип данных. Функция возвращает NULL, если размер нового блока больше размера старого блока, и в памяти нет свободного места для размещения нового блока.

Для освобождения блока динамической памяти используется функция free(). Прототип функции:

void free(void* block);

Функция выполняет освобождение блока памяти, адрес которого принимает в качестве аргумента. Все блоки динамической памяти должны быть освобождены по окончании работы с ними, иначе они так и останутся занятыми по окончании работы программы до перезагрузки системы, что приведёт к утечке оперативной памяти.

В среде Borland C++ 3.1 для работы с дальней кучей необходимо использовать дальние указатели и соответствующие функции, но с приставкой far.

Пример 2

#include <stdio.h>

#include <alloc.h>

#include <stdlib.h>

void main(void)

{

int n,m;

printf("Input string number\n");

scanf("%d",&n);

printf("Input column number\n");

scanf("%d",&m);

float *f,sum=0;

if((f=(float*)malloc(n*m*sizeof(float)))==NULL)

{

 printf("System do not have free memory\n");

 exit(1);

}

printf("Input matrix");

for(int i=0;i<n;i++)

 for(int j=0;j<m;j++)

 {

  printf("\nmatrix[%d][%d]=",i,j);

  scanf("%f",(f+i*m+j));

 }

if((f=(float*)realloc(f,(n+1)*m*sizeof(float)))==NULL)

{

 printf("System do not have free memory\n");

 exit(1);

}

for(int t=0;t<m;t++,sum=0)

{

 for(int j=0;j<n;j++)

  sum+=*(f+j*m+t);

 *(f+n*m+t)=sum;

}

for(int k=0;k<n+1;k++)

{

 printf("\n");

 for(int j=0;j<m;j++)

  printf("%f\t",*(f+k*m+j));

}

free(f);

}


 

А также другие работы, которые могут Вас заинтересовать

83375. Созданию информационного сайта для студенческого клуба ИАТЭ «Грот» 1.09 MB
  База данных включает в себя три таблицы. Таблица «активисты» хранит имена фамилии и должности участников студенческого направления. Таблица «направление» хранит названия студенческих направлений. Структура сайта Верхний блок сайта – шапка сайта. Блок меню содержит пункты меню и вход...
83377. Оптимизация электронных средств 450.5 KB
  При проектировании РЭУ большое внимание уделяется определению статистических характеристик аппаратуры. Так как номиналы всех компонентов устройства подвержены случайному разбросу, любые характеристики ИС и устройства в целом имеют вероятностный характер.
83379. Сущность и правовые основы социального обеспечения военнослужащих 63.12 KB
  Статус военнослужащего есть совокупность его прав свобод обязанностей и ответственности военнослужащих установленных законодательством и гарантированных государством. Государство берет на себя обязанности по социальной защите военнослужащих.
83380. Разработка рекомендаций и совершенствование современных миграционных процессов в Краснодарском крае 1.2 MB
  Для описания столь сложной многофакторной миграционной реальности необходим методологический подход исследователя, который бы определил свой предмет и метод исследования, основанный на синтезе знаний, достигнутых многими научными дисциплинами и, прежде всего социологией.
83381. Разработка СППР для ООО «УК ДомМонтажСервис Плюс» 2.21 MB
  Система поддержки принятия решений СППР компьютерная автоматизированная система целью которой является помощь людям принимающим решение в сложных условиях для полного и объективного анализа предметной деятельности. СППР возникли в результате слияния управленческих информационных систем и систем...
83382. ТЕХНОЛОГИЯ РАЗРАБОТКИ И ЗАЩИТЫ БАЗ ДАННЫХ: УЧЕБНО – МЕТОДИЧЕСКОЕ ПОСОБИЕ 1.26 MB
  Учебно-методическое пособие содержит методические рекомендации и основные теорические положения, необходимые для выполнения курсовой работы по дисциплине «Технология разработки и защиты баз данных», а также образец выполнения и оформления двух разделов курсовой работы.
83383. Полезные свойства кефирных грибков и особенности их применения в молочной промышленности 291.31 KB
  Существует 2 группы кисломолочных продуктов: продукты молочнокислого и смешанного молочнокислого и спиртового брожения. Благодаря образованию молочной кислоты обладающей бактерицидными свойствами и углекислого газа в качестве конечных продуктов при молочнокислом брожении кефир возбуждает аппетит...