Для динамического выделения памяти в
С используется функция
malloc(), которая резервирует заданный размер блока памяти и возвращает указатель на этот блок. Указатель возвращается неопределенного типа
void*, который необходимо привести к требуемому типу данных. Если память выделить невозможно, функция возвращает
NULL.
Пример кода#include //файл с описанием функции...int *x; //указатель int n = 100; //кол-во элементов в массиве //выделение динамической памятиx = (int*)malloc(n*sizeof(int)); for(int i = 0; i < 100; i++) //обнуление x[i] = 0; //памятиФункция
calloc() также служит для выделения памяти, но в отличие от
malloc(), она требует два аргумента (количество элементов и размер каждого элемента). Если память выделена успешно, то функция
calloc() заполняет выделенную память нулями и возвращает на нее указатель типа
void*.
Пример кода#include //файл с описанием функции...int *x; //указатель int n = 100; //кол-во элементов массива //выделение динамической памятиx = (int*)calloc(n, sizeof(int));//for(int i = 0; i < 100; i++) память обнуляется// x[i] = 0; calloc()Для освобождения ранее выделенной памяти в
С используется функция
free(), которая принимает указатель на область, подлежащую освобождению, или
NULL. Функция не проверяет указатель на правильность и может ошибочно «освободить» невыделенную область.
Пример кодаint *x; int n = 100;//выделение динамической памяти//с заполнением её нулямиif(x = (int*)calloc(n, sizeof(int))) { x[0] = 10; ... free(x); //удаление динамической памяти}Для изменения размера ранее выделенной памяти в
С используется библиотечная функция
realloc(), которая пытается увеличить блок памяти. Если это не удалось, то функция попытается выделить новый блок памяти необходимого размера, в который будут перенесены старые данные. Если это тоже не удалось, то функция вернет
NULL.
Пример кодаint *x;x = (int*)malloc(100*sizeof(int));... x = (int*)realloc(x, 500*sizeof(int)); ... free(x);В
С++ для динамического выделения памяти используются операторы
new и
new[ ]. А для освобождения памяти – операторы
delete и
delete[ ]. Варианты с квадратными скобками применяются для выделения/освобождения памяти массива. Если память выделить невозможно, функция
new выкидывает исключение или возвращает
NULL (зависит от настроек менеджера памяти).
Пример кодаdouble *a = new double; int *x = new int[100]; Product *p = new Product; ... delete a; //удаление переменной delete[] x; //удаление массива delete p; //удаление переменнойНельзя смешивать концепции
malloc/free и
new/delete.
- Использование неинициализированного указателя.
- "Висячие" указатели.
- "Утечка" памяти.
- Повторное освобождение памяти.
- Ошибочное применение delete вместо delete[ ].
Пример кодаint *x; //имеет смысл обнулить указатель x = NULL;//"друзья" закомментировали следующую сточку //x = (int*)malloc(100*sizeof(int));x[0] = 10; Если локальный указатель не инициализирован, то он содержит непредсказуемое значение. Это значение трактуется как адрес целой переменной, к которой осуществляется доступ. По чистой случайности может оказаться, что указатель
x содержит истинный адрес переменной программы, тогда значение переменной будет изменено, выполнение программы продолжится дальше, а факт изменения переменной непредсказуемым образом повлияет на дальнейшее выполнение программы.
Пример кодаint *x = NULL;x = (int*)malloc(100*sizeof(int));...free(x); //после удаления памяти имеет смысл //обнулить указатель x = NULL;x[0] = 10; После освобождения динамической памяти указатель продолжает указывать на прежний адрес памяти. Такие указатели называются "висячими". Попытка записи по такому указателю не приводит к немедленной ошибке. Однако память, на которую он указывает, могла быть уже выделена другому динамическому объекту и попытка записи приведет к порче этого объекта.
Пример кодаint func(int N) { int *x = (int*)malloc(N*sizeof(int)); x[0] = 10; ... return x[0]; } // выход из функции без удаления памятиДанная ошибка возникает, когда память не освобождается, но перестает контролироваться указателем (программой). Таким образом занятую память невозможно освободить. Подобные ошибки трудно обнаружить, поскольку они практически не сказывается на работе приложения. Однако при систематических утечках программа требует все больше памяти у операционной системы, замедляя работу других приложений.
Пример кодаint *x = NULL;x = (int*)malloc(100*sizeof(int));...free(x); ...free(x); //повторное освобождение памятиДанная ошибка возникает, когда происходит освобождение одного и того же выделенного блока памяти несколько раз. Как правило, такая ошибка приводит к нарушению работы менеджера памяти и непредсказуемым последствиям.
double* cpp_realloc(const double* ptr, unsigned new_size, unsigned old_size) { if (ptr == NULL && new_size != 0) return new double[new_size]; if (new_size == 0) { if (ptr != NULL) delete [] ptr; return NULL; } double* tmp = new double[new_size]; for(unsigned i = 0; i < old_size; i++) tmp[i] = ptr[i]; delete [] ptr; return tmp;}Пример realloc для С++Пример функцииДвумерные динамические массивыФункции
malloc(),
calloc() и оператор
new[ ] позволяют выделять только одномерные массивы, поэтому для работы с двумерными массивами необходимо либо дополнительно создавать массив указателей, либо пересчитывать двумерные индексы в индексы для одномерного массива.
Пример кода//захват памяти для массива NxMint **a = new int*[N];for (int i = 0; i < N; ++i) a[i] = new int[M];//обращения к массиву стандартноеa[2][2] = 5;//освобождение памятиfor (int i = 0; i < N; ++i) delete [] a[i];delete [] a;Двумерные массив через одномерныйПример кода int N = 3, M = 4; int *a = new int[N*M];//массив хранится по строчкам for(int i = 0; i < N; i++) for(int j = 0; j < M; j++) a[i*M+j] = i+1;//вывод массива на экран for(int i = 0; i < N; i++) { for(int j = 0; j < M; j++) cout << a[i*M+j] << "\t"; cout << endl; }