РАСПРЕДЕЛЕНИЕ ПАМЯТИ: malloc( ) И са11ос( )
РАСПРЕДЕЛЕНИЕ ПАМЯТИ: malloc( ) И са11ос( )
Ваша программа должна предоставить достаточный объем памяти для запоминания используемых данных. Некоторые из этих ячеек памяти распределяются автоматически. Например, мы можем объявить
char place[ ] = "Залив Свиной печенки";
и будет выделена память, достаточная для запоминания этой строки.
Или мы можем быть более конкретны и запросить определенный объем памяти:
int plates[100];
Это описание выделяет 100 ячеек памяти, каждая из которых предназначена для запоминания целого значения.
Язык Си не останавливается на этом. Он позволяет вам распределять дополнительную память во время работы программы. Предположим, например, вы пишете диалоговую программу и не знаете заранее, сколько данных вам придется вводить. Можно выделить нужный вам (как вы считаете) объем памяти, а затем, если понадобится, потребовать еще. На рис. 15.5 дан пример, в котором используется функция malloc( ), чтобы сделать именно это. Кроме того, обратите внимание на то, как такая программа применяет указатели.
/* добавляет память, если необходимо */
#include <sldio.h>
#define STOP " " /* сигнал прекращения ввода */
#define BLOCK 100 /* байты памяти */
#define LIM 40 /* предельная длина вводимой строки */
#define MAX 50 /* максимальное число вводимых строк */
#define DRAMA 20000 /* большая задержка времени */
main( )
{
char store[BLOCK]; /* исходный блок памяти */
char symph[LIM]; /* приемник вводимых строк */
char *end; /* указывает на конец памяти */
char *starts[MAX]; /* указывает на начала строк */
int index = 0; /* количество вводимых строк */
int count; /* счетчик */
char *malloc( ); /* распределитель памяти */
starts[0] = store;
end = starts[0] + BLOCK - 1;
puts(" Назовите несколько симфонических оркестром.");
puts(" Вводите по одному: нажмите клавишу [ввод] в начале");
puts(" строки для завершения вашего списка. Хорошо, я готова." );
while(strcmp(fgets(symph, LIM, stdin), STOP) != 0 && index < MAX)
{ if(strlen(symph) > end - starts[index])
{ /* действия при недостатке памяти для запоминания вводимых данных*/
puts(" Подождите секунду. Я попробую найти дополнительную память.");
starts[index] = malloc(BLOCK);
end = starts[index] + BLOCK - 1;
for(count = 0; count < DRAMA; count++);
puts(" Нашла немного!" ); }
strcpy (starts [index], symph);
starts[index + 1] = starts[index] + strlen(symph) + 1;
if(++index < MAX)
printf("Этo %d. Продолжайте, если хотите. ", index); }
puts(" Хорошо, вот что я получила:");
for(count = 0; count < index; count ++)
puts(starts[count]);
}
РИС. 15.5. Программа, добавляющая память по требованию.
Вот образец работы программы:
Назовите несколько симфонических оркестров оркестров.
Вводите их по одному; нажмите клавишу [ввод] в начале
строки для завершения нашего списка. Хорошо, я готова.
Сан-франциский симфонический.
Это 1. Продолжайте, если хотите.
Чикагский симфонический
Это 2. Продолжайте, если хотите.
Берлинский филармонический
Это 3. Продолжайте, если хотите.
Московский камерный
Это 4. Продолжайте, если хотите. Лондонский симфонический
Это 5. Продолжайте, если хотите. Венский филармонический
Подождите секунду. Я попробую найти дополнительную память.
Нашла немного!
Это 6. Продолжайте, если хотите.
Питтсбургский симфонический
Это 7. Продолжайте, если хотите.
Хорошо, вот что я получила:
Сан-францизкий симфонический
Чикагский симфонический
Берлинский филармонический
Московский камерный
Лондонский симфонический
Венский филармонический
Питтсбургский симфонический
Сначала давайте посмотрим, что делает функция malloc( ). Она берет аргумент в виде целого без знака, которое представляет количество требуемых байтов памяти. Так, malloc(BLOCK) требует 100 байт. Функция возвращает указатель на тип char в начало нового блока памяти. Мы использовали описание
char *malloc( );
чтобы предупредить компилятор, что malloc( ) возвращает указатель на тип char. Поэтому мы присвоили значение этого указателя элементу массива starts[index] при помощи оператора
starts[index] = malloc(BLOCK);
Хорошо, давайте теперь рассмотрим проект программы, заключающийся в том, чтобы запомнить все исходные строки подряд в большом массиве store. Мы хотим использовать starts[0] для ссылки на начало первой строки, starts[l] - второй строки и т. д. На промежуточном этапе программа вводит строку в массив symph. Мы использовали fgets( ) вместо gets( ), чтобы ограничить входную строку длиной массива symph.
РИС. 15.6. Последовательные строки symph, записанные в массив store.
Прежде чем копировать symph в store, мы должны проверить, достаточно ли для нее оставшегося места. Указатель end ссылается на конец памяти, а текущее значение starts[index] ссылается на начало неиспользованной памяти. Таким образом, мы можем сравнить разницу между этими двумя указателями с длиной symph и определить, достаточно ли осталось памяти.
Если места недостаточно, вызываем malloc( ), чтобы подготовить дополнительную память. Мы устанавливаем starts[index] на начало нового блока памяти, a end - на конец нового блока. Заметим, что у нас нет имени этой новой памяти. Она не является, например, расширением store. У нас есть только обозначения указателей, ссылающихся на новую область памяти.
Когда программа работает, на каждую новую строку ссылается элемент массива указателей starts. Некоторые строки находятся в store, другие - в одной или нескольких новых областях памяти.
Но пока у нас есть указатели, мы можем работать со строками, как показывает нам часть программы, выполняющая вывод на печать.
Таким образом используется mаllос( ). Но предположим, что вы хотите работать с памятью типа int, а не char. Можете и здесь использовать mаllос( ). Вот как это делается:
char *malloc( ); /* по-прежнему описываем как указатель на char */
int *newmem;
newmem = (int *) malloc(l00); /* используем операцию приведения типа */
Снова требуется 100 байт. Операция приведения типа преобразует значение, возвращенное указателем на тип char, в указатель на тип int. Если, как в нашей системе, int занимает два байта памяти, это значит, что newmem + 1 будет увеличивать указатель на два байта, т. е. передвигать его к следующему целому. Это также означает, что 100 байт можно использовать для запоминания 50 целых чисел.
Другую возможность распределения памяти дает нам применение функции саllос( ):
char *calloc( );
long *newmem;
newmem = (long *) calloc(100, sizeof(long));
Подобно malloc( ) функция саllос( ) возвращает указатель на char. Нужно использовать оператор приведения типа, если вы хотите запомнить другой тип. Эта новая функция имеет два аргумента, и оба они должны быть целыми без знака. Первый аргумент содержит количество требуемых ячеек памяти. Второй аргумент - размер каждой ячейки в байтах. В нашем случае long использует четыре байта, поэтому оператор выделит 100 четырехбайтных элементов, используя в целом 400 байтов памяти.
Применяя sizeof (long) вместо 4, мы сделали эту программу более мобильной. Она будет работать на системах, где long имеет размер, отличный от четырех.
Функция саllос( ) имеет еще одну особенность; она обнуляет содержимое всего блока.
Ваша библиотека языка Си, вероятно, предоставляет несколько других функций управления памятью, и вы можете захотеть проверить их.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
3.2.1. Библиотечные вызовы: malloc() , calloc() , realloc() , free()
3.2.1. Библиотечные вызовы: malloc(), calloc(), realloc(), free() Динамическую память выделяют с помощью функций malloc() или calloc(). Эти функции возвращают указатели на выделенную память. Когда у вас есть блок памяти определенного первоначального размера, вы можете изменить его размер с помощью
15.5.2.5. Другие отладчики malloc
15.5.2.5. Другие отладчики malloc Две статьи Cal Ericson в Linux Journal описывают mtrace и dmalloc, а также большинство других перечисленных ниже инструментов. Эти статьи Memory Leak Detection in Embedded Systems, выпуск 101[184], сентябрь 2002 г., и Memory Leak Detection in C++, выпуск 110[185], июнь 2003 г. Обе статьи доступны на веб-сайте
1.5.3 Распределение памяти
1.5.3 Распределение памяти Ядро постоянно располагается в оперативной памяти, наряду с выполняющимся в данный момент процессом (или частью его, по меньшей мере). В процессе компиляции программа-компилятор генерирует последовательность адресов, являющихся адресами
Динамическое распределение IP-адресов
Динамическое распределение IP-адресов Наиболее просто устанавливается конфигурация сервера DHCP, предполагающая динамическое распределение IP-адресов. В этом случае сервер сам решает, какой адрес следует выделить компьютеру, который обратился к нему. IP-адреса для
Выравнивание и распределение
Выравнивание и распределение Когда активен инструмент Перемещение, на панели под строкой меню появляется набор кнопок для выравнивания и распределения изображений и объектов (рис. 9.1). Рис. 9.1. Кнопки выравниванияПиктограммы на кнопках подсказывают, как будут
Выравнивание и распределение
Выравнивание и распределение В тех случаях, когда необходимо расположить объекты с высокой точностью по отношению друг к другу (например, ровно в ряд на равном расстоянии), но точность расположения на странице не требуется, мы можем прибегнуть к процедурам выравнивания и
А.2.2. Проверка функции malloc()
А.2.2. Проверка функции malloc() Функции выделения и освобождения памяти, имеющиеся в GNU-библиотеке языка С, способны обнаруживать факт записи в память до начала выделенной области, а также попытку освободить одну и ту же область дважды. Если задать переменную среды MALLOC_CHECK_
Динамическое распределение памяти
Динамическое распределение памяти Библиотека языка Си предоставляет механизм распределения динамической памяти (heap). Этот механизм позволяет динамически (по мере возникновения необходимости) запрашивать из программы дополнительные области оперативной памяти.Работа
Распределение текстур
Распределение текстур Мы рассмотрели общие основы создания и наложения текстур на объекты. Наверняка вы уже успели столкнуться с необходимостью распределения текстур по поверхности объекта. Подобная необходимость возникает при текстурировании постоянно. Дело в том,
Распределение функций
Распределение функций Модель клиент-сервер позволяет отдельным фрагментам работы системы быть эффективно распределенными между компонентами аппаратуры и программного обеспечения. Сервер базы данных заботится о хранении, управлении и поиске данных, а через хранимые
Распределение
Распределение Для одного или нескольких выделенных объектов или их групп можно задать одно из девяти предопределенных положений (то есть применить автоматическое распределение). Чтобы применить к группе объектов распределение, выделите нужные объекты и нажмите кнопку
Распределение памяти
Распределение памяти Стандартная библиотека компиляторов содержит специальные функции управления памятью – malloc, free, а также другие разновидности этих функций. Они позволяют получить для использования блок оперативной памяти, и затем отдать его обратно операционной
9 РАСПРЕДЕЛЕНИЕ РЕСУРСОВ ДЛЯ ДОКУМЕНТИРОВАНИЯ
9 РАСПРЕДЕЛЕНИЕ РЕСУРСОВ ДЛЯ ДОКУМЕНТИРОВАНИЯ Основными ресурсами, требуемыми для документирования, являются следующие:персонал (см. 9.1);средства (см. 9.2);финансирование (см.
Распределение графики по слоям
Распределение графики по слоям Иногда бывает нужно "разбросать" фрагменты изображения, находящиеся в одном слое, по разным слоям. В терминологии Flash эта операция называется распределением графики по слоям. При этом Flash сам создаст нужное количество слоев и переместит на