Этот прием настолько широко используется, что использовать одно- и двухбуквенные префиксы обычно уже недостаточно.
27.4.
Свободная память
В языке С нет операторов
new
и
delete
, работающих с объектами. Для использования свободной памяти в нем используются функции, работающие с памятью. Наиболее важные функции определены в стандартном заголовочном файле общих утилит
<stdlib.h>
.
void* malloc(size_t sz); /* выделить sz байтов */
void free(void* p); /* освободить область памяти, на которую
ссылается указатель p */
void* calloc(size_t n, size_t sz); /* выделить n*sz байтов,
инициализировав их нулями */
void* realloc(void* p, size_t sz); /* вновь выделить sz байтов
в памяти, на которую ссылается
указатель p*/
Тип
typedef size_t
— это тип без знака, также определенный в заголовочном файле
<stdlib.h>
.
Почему функция
malloc
возвращает указатель
void*
? Потому что она не имеет информации о том, объект какого типа вы хотите разместить в памяти. Инициализация — это ваша проблема. Рассмотрим пример.
ни в программе на языке C, ни в программе на языке C++. Однако в языке С++ мы могли бы определить конструктор для структуры
Pair
и написать инструкцию
Pair* pp = new Pair("pear", 42)
;
В языке C (но не в языке C++; см. раздел 27.3.4) перед вызовом функции malloc можно не указывать приведение типа, но мы не рекомендуем это делать.
int* p = malloc(sizeof(int)*n); /* избегайте этого */
Игнорирование приведения довольно часто встречается в программах, потому что это экономит время и позволяет выявить редкую ошибку, когда
программист забывает включить в текст программы заголовочный файл
<stdlib.h>
перед использованием функции
malloc
. Однако при этом исчезает и визуальный маркер, свидетельствующий о том, что размер памяти подсчитан неправильно.
p = malloc(sizeof(char)*m); /* вероятно, ошибка — нет места для m целых */
Не используйте функции
malloc/free
в программах, написанных на языке C++; операторы
new/delete
не требуют приведения типа, выполняют инициализацию (вызывая конструкторы) и очищают память (вызывая деструкторы), сообщают об ошибках, связанных с распределением памяти (с помощью исключений), и просто работают быстрее. Не удаляйте объект, размещенный в памяти с помощью функции
malloc
, выполняя оператор
delete
, и не удаляйте объект, созданный с помощью оператора new, вызывая функцию
free
. Рассмотрим пример.
int* p = new int[200];
// ...
free(p); // ошибка
X* q = (X*)malloc(n*sizeof(X));
// ...
delete q; // error
Этот код может оказаться вполне работоспособным, но он не является переносимым. Более того, для объектов, имеющих конструкторы и деструкторы, смешение стилей языков C и C++ при управлении свободной памятью может привести к катастрофе. Для расширения буферов обычно используется функция
realloc
.
int max = 1000;
int count = 0;
int c;
char* p = (char*)malloc(max);
while ((c=getchar)!=EOF) { /* чтение: игнорируются символы
в конце файла */
if (count==max–1) { /* необходимо расширить буфер */
max += max; /* удвоить размер буфера */
p = (char*)realloc(p,max);
if (p==0) quit;
}
p[count++] = c;
}
Объяснения операторов ввода в языке С приведены в разделах 27.6.2 и Б.10.2.
Функция
realloc
может выделить память на прежнем участке, а может и перенести его содержимое во вновь выделенную область памяти. Даже не думайте применять функцию
realloc
к области памяти, выделенной с помощью оператора
new
.
Используя стандартную библиотеку языка C++, этот код можно переписать примерно так: