Каковы все способы выделения памяти в C и чем они отличаются? - PullRequest
5 голосов
/ 25 сентября 2010

Мне известно следующее:

  • malloc
  • calloc
  • realloc

В чем различия между этими?Почему кажется, что malloc используется почти исключительно?Есть ли поведенческие различия между компиляторами?

Ответы [ 5 ]

12 голосов
/ 25 сентября 2010

malloc выделяет память.Содержимое памяти остается как есть (заполняется тем, что было раньше).

calloc выделяет память и устанавливает в ее содержимое все нули.размер существующего выделенного блока памяти или копирует содержимое существующего блока памяти во вновь выделенный блок запрошенного размера, а затем освобождает старый блок.

Очевидно, realloc является специальнымситуацияЕсли у вас нет старого блока памяти для изменения размера (или копирования и освобождения), нет никаких причин использовать его.Причина, по которой malloc обычно используется вместо calloc, заключается в том, что во время выполнения стоит установка памяти на все нули и если вы планируете немедленно заполнить память полезными данными (как обычно), нет смысла сначала обнулять его.

Все эти функции стандартны и работают надежно во всех компиляторах.

3 голосов
/ 25 сентября 2010

Помимо тех, о которых вы упоминаете (некоторые из них являются расширениями):

  • переменные в стеке также распределяются динамически.Рекурсия - это способ выделить и использовать это.
  • C99 имеет массивы переменной длины (как упоминает BlueRaja).
  • В некоторых системах у вас даже есть вызов alloca, который позволяет вам выделять куски переменной длины в стеке.
  • POSIX имеет отображение сегментов памяти и файлов с комбинациями shm_open или open и mmap.
  • SysV IPC имеет shmget и т.д. звонки
2 голосов
/ 25 сентября 2010

Одним из способов выделения памяти, который не был упомянут, является alloca(size_t size), который резервирует байты размера памяти в текущем кадре стека и автоматически освобождает память снова, когда вы покидаете кадр стека.

1 голос
/ 25 сентября 2010

calloc, вероятно, просто реализован как нечто похожее на:

void * calloc(size_t nmemb, size_t size) {
      size_t len = nmemb * size);
      void * ptr = malloc(len);
      if (ptr) {
          return memset(ptr, 0, len);
      }
      return ptr;
}

Так что он просто добавляет умножение до и очистку после malloc.

malloc может быть (но, вероятно, нет)t) реализовано следующим образом:

void * malloc(size_t size) {
      return realloc(NULL, size);
}

, поскольку вы можете передавать realloc указатель NULL в качестве предыдущего указателя, но malloc, скорее всего, не реализован таким образом, поскольку он будет замедлять все malloc и потому что realloc, вероятно, использует malloc.

Главное, что нужно знать о realloc, это то, что он часто способен определить фактический размер блока памяти, который вернула любая из подпрограмм выделения кучи, и посмотреть, достаточно ли большой блок уже или в некоторыхв случаях, если лучше попытаться уменьшить блок или переместить его.

void realloc(void * ptr, size_t size) {
    size_t alen = MALLOC_LENGTH_OF(ptr); // this just stands for some method of determining
                                     // the size of the block that was allocated, and could
                                     // be looking it up in a table or looking at a place
                                     // several bytes before the pointer, or some other
                                     // implementation specific thing
    if (0 == size) {
       free(ptr);
       return NULL;
    }
    if (alen >= size) {
        return ptr; // big enough, and not worrying about it being too big
    }
    void new_ptr = malloc(size); // since I said that malloc most likely isn't
                                // implemented using realloc using malloc here is ok
    if (new_ptr && ptr) {
       memcpy(new_ptr, ptr, alen);
    }
    free(ptr);
    return new_ptr;
}

Malloc используется чаще, потому что он наиболее прост.Программисты часто могут сделать свои выделения достаточно большими, чтобы начать с того, что им не нужно беспокоиться об изменении их размера с помощью realloc, и очень часто очистка памяти не требуется.

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

Некоторые библиотеки malloc предназначены для отладки и обнаружения ошибок.Другие могут предложить лучшую производительность.Некоторые оптимизированы для одновременного выделения памяти нескольким различным потокам и позволяют избежать того, что разные потоки должны блокировать всю кучу для выполнения выделения или освобождения.

Все они должны предоставлять одинаковую семантику изперспективы приложений, хотя.

0 голосов
/ 07 января 2014

malloc: Допустим, у вас есть ptr = (int *) malloc (10); Это выделяет 10 непрерывных байтов пространства памяти, а адрес первого байта сохраняется в переменная указателя ptr . Выделенная память теперь содержит значение мусора.
Поэтому, если я изменяюсь от 0 до 3 scanf ("% d", ptr + i); хранит 4 целых числа в 4 смежных местах. ptr имеет адрес 1-го целого числа, ptr + 1 имеет адрес 2-го числа и так далее. Следовательно, printf ("% d", atstrick (ptr + i)); выведет соответствующие значения. В отличие от памяти, выделенной для переменных и массивов, динамически выделяемое имя не связано с ним. Как видно выше.

calloc: Он похож на malloc за исключением двух отличий: 1. Объявление: ptr = (int *) calloc (5, sizeof (int)); Здесь у нас есть два аргумента, 5 - нет выделенных блоков, а 2-й аргумент равен 4 байтам. Это эквивалентно ptr = (int *) malloc (5 * sizeof (int)); 2.In Собственно выделенная память calloc не является мусором, но равна 0. И malloc, и calloc возвращают NULL, если в куче недостаточно памяти.

...