911 Динамическое распределение памяти
Block1 |
Block2 |
Block3 |
Рис. 2
После выполнения оператора fre
e(block2) куча будет иметь вид
0х0007 |
0х90EF |
… |
0x0008 |
0x0000 |
…. |
0x0008 |
0x9116 |
Block1 |
Block2 |
Block3 |
Рис. 3
Замечание 1. Особенность динамических символьных строк.
Рассмотрим фрагмент кода, создающий динамическую строку.
main()
{
char *str; // ячейка str находится в стеке
str = (char *)malloc(13);
strcpy(str, "Hello,World!");
// строка Hello,World! помещается в кучу
}
Строка "Hello,World!" реально состоит из 13 символов, так как кроме самих символов содержит 0 - признак конца строки. Поэтому, если выделить только 12 элементов
Str = (char *)malloc(12),
то признак конца строки "залезет" на заголовок следующего блока ДП и изменит длину этого блока. Если бы длина строки была меньше 12 байт, то фраза уместилась бы в первом параграфе, и ошибки бы не произошло. Источник хорошо скрытой логической ошибки!
4. Дополнительные фунции ДРП
Определение размера свободной области кучи
unsigned long coreleft(void);
Возвращает размер неиспользованной памяти в байтах, расположенной за последним занятым блоком. "Дырки" в куче не учитываются.
Блочное выделение памяти
void *calloc(size_t NItems, size_t SizeOfItem);
Выделяет и обнуляет память для Nitems фрагментов по SizeOfItem байт каждый. Размер фрагмента не превосходит 64K, но общий объем памяти может превышать 64K. В случае неудачи возвращается NULL.
Проверка целостности кучи
int heapcheck(void);
Просматривает кучу и проверяет для каждого блока указатели, размер и другую критическую информацию. Если все нормально, то возвращаемое значение больше 0. В противном случае, возвращается отрицательное число.
Просмотр блоков кучи
int heapwalk(struct heapinfo *hi);
Просматривает кучу блок за блоком. Предполагается, что сбоев в куче нет, для этого используйте heapcheck. Фнукция получает указатель на структуру heapinfo. При первом вызове, установите hi.ptr в 0. Функция устанавливает этот указатель на адрес очередного блока. Другие поля структуры size, in_use позволяют определить размер блока в байтах и его занятость. Для очередного блока функция вернет _HEAPOK, для последнего блока _HEAPEND.
Пример 3. Занятые и свободные блоки.
#include <stdio.h>
#include <alloc.h>
#define NUM_PTRS 4
#define NUM_BYTES 20
int main(void)
{
struct heapinfo hi;
char *array[ NUM_PTRS ];
for(int i = 0; i < NUM_PTRS; i++)
array[ i ] = (char *)malloc(NUM_BYTES);
for(i = 0; i < NUM_PTRS; i += 2)
free(array[ i ]);
hi.ptr = NULL;
printf(" Размер Статус\n");
printf(" ---- ------\n");
while(heapwalk(&hi) == _HEAPOK)
{
printf("%7u ", hi.size);
printf("%s\n",(hi.in_use?"используется": "свободен"));
}
return 0;
}
В результате будет напечатано
Размер |
Статус |
528 |
Используется |
32 |
Свободен |
32 |
Используется |
32 |
Свободен |
32 |
Используется |
Инициализация свободных блоков кучи
int heapfillfree(unsigned int fillvalue);
Заполняет байты свободных блоков кучи константным значением fillvalue.
Проверка свободных блоков кучи
int heapcheckfree(unsigned int fillvalue);
Проверяет байты свободных блоков кучи на их равенство константному значению fillvalue.
Функции группы far.
В моделях памяти, где куча не превышает 64K, можно использовать память вне этой области - дальнюю кучу. Для работы с дальней кучей имеются свои версии функций, c префиксом far.
5. Лабораторные задания
Области памяти
Для следующей программы укажите значения сегментных регистров. Укажите абсолютные адреса и размеры в байтах области кода; области данных, глобальных и статических переменных; стека; кучи. Модель памяти large. Определите в отладчике адреса и размещение по областям переменных: main; Privet; Dlit в функции main; i и Dlit в функции Privet; printf.
void Privet(int sound); // прототип функции Privet
main(){
int Dlit = 5;
Privet(Dlit); //вызов функции Privet
}
void Privet(int Dlit) { // заголовок функции Privet
{
printf("Привет!\n");
printf("С добрым утром!");
for(int i = 0; i<Dlit; i++) //печатает первые Dlit
printf("%c", i); // символов ascii-таблицы
}
Исследование менеджера ДРП
Выделите динамическую память для трех данных типа char. Адреса сохраните в переменных char *x, *y, *z. Определите в отладчике адреса *x, *y, *z. Убедитесь, что для кажго из однобайтовых данных будет отведено в куче 16 байт,т.е. целый параграф.
Односвязный список менеджера
Разместите в куче несколько данных разного типа, найдите их адреса, размер блоков. Убедитесь в наличии односвязного списка.
Новый менеджер
Язык Си не пускает дефрагментации ДП. Напишите свой менеджер, содержащий функции mymalloc, myfree, mydefrag.
Сумма свободных блоков
Определите суммарный объем "дырок" в куче, образовавшихся после освобождения блоков.
Другие рефераты на тему «Программирование, компьютеры и кибернетика»:
Поиск рефератов
Последние рефераты раздела
- Основные этапы объектно-ориентированного проектирования
- Основные структуры языка Java
- Основные принципы разработки графического пользовательского интерфейса
- Основы дискретной математики
- Программное обеспечение системы принятия решений адаптивного робота
- Программное обеспечение
- Проблемы сохранности информации в процессе предпринимательской деятельности