Каковы некоторые полезные примеры malloc() в C?
Я просто читаю о malloc()
в C.
Статья в Википедии содержит example, однако он просто выделяет достаточно памяти для массива из 10 целых чисел по сравнению с int array[10]
. Не очень полезно.
Когда вы решили использовать malloc()
over C для обработки памяти для вас?
Ответы
Ответ 1
Динамические структуры данных (списки, деревья и т.д.) используют malloc
для размещения своих узлов в куче. Например:
/* A singly-linked list node, holding data and pointer to next node */
struct slnode_t
{
struct slnode_t* next;
int data;
};
typedef struct slnode_t slnode;
/* Allocate a new node with the given data and next pointer */
slnode* sl_new_node(int data, slnode* next)
{
slnode* node = malloc(sizeof *node);
node->data = data;
node->next = next;
return node;
}
/* Insert the given data at the front of the list specified by a
** pointer to the head node
*/
void sl_insert_front(slnode** head, int data)
{
slnode* node = sl_new_node(data, *head);
*head = node;
}
Рассмотрим, как новые данные добавляются в список с помощью sl_insert_front
. Вам нужно создать node, в котором будут храниться данные и указатель на следующий node в списке. Где вы собираетесь его создать?
- Возможно, на стек! - НЕТ - где будет выделено это пространство стека? В какой функции? Что происходит с ним, когда функция завершается?
- Возможно, в статической памяти! - НЕТ - вам нужно заранее знать, сколько у вас узлов списка, поскольку статическая память предварительно распределена при загрузке программы.
- В куче? ДА - потому что у вас есть все необходимые гибкости.
malloc
используется в C, чтобы распределять вещи в пространстве памяти кучи, которые могут расти и динамически сокращаться во время выполнения, а владение которыми полностью находится под контролем программиста. Есть еще много примеров, когда это полезно, но тот, который я показываю здесь, является представительным. В конце концов, в сложных программах на C вы обнаружите, что большая часть данных программы находится в куче, доступной через указатели. Правильная программа всегда знает, какой указатель "владеет" данными и будет тщательно очищать выделенную память, когда она больше не нужна.
Ответ 2
Что делать, если вы не знаете размер массива при написании своей программы?
В качестве примера можно представить, что вы хотите загрузить изображение. Сначала вы не знаете его размер, поэтому вам нужно будет прочитать размер из файла, выделить буфер с этим размером и затем прочитать файл в этом буфере. Очевидно, вы не могли бы использовать массив статического размера.
EDIT:
Еще один момент: при использовании динамического выделения память выделяется в куче, а массивы выделяются в стеке. Это очень важно, когда вы программируете встроенное устройство, поскольку стек может иметь ограниченный размер по сравнению с кучей.
Ответ 3
В приведенном ниже примере int array[10]
исчезает, когда вы покидаете рамку стека. Если вы хотите, чтобы используемая память сохранялась за пределами локальной области, вы должны использовать malloc();
Ответ 4
Я рекомендую вам google Стек и куча.
int* heapArray = (int*)malloc(10 * sizeof(int));
int stackArray[10];
Оба очень похожи в том, как вы обращаетесь к данным. Они отличаются друг от друга тем, что данные хранятся за кулисами. HeapArray выделяется в куче и только отменяется, когда приложение умирает, или когда вызывается free(heapArray)
. Элемент stackArray выделяется в стеке и освобождается, когда пакет распаковывается.
Ответ 5
malloc() используется всякий раз, когда:
-
Вам нужно динамическое распределение памяти
Если вам нужно создать массив размера n, где n вычисляется во время выполнения вашей программы, единственный способ сделать это - использовать malloc().
-
Вам нужно выделить память в куче
Переменные, определенные в некоторых функциях, живут только до конца этой функции. Таким образом, если нужны некоторые "независимые от вызова" данные, он должен быть передан/возвращен как параметр функции (который не всегда подходит) или хранится в куче. Единственный способ хранения данных в куче - использовать malloc(). Существуют массивы с переменным размером, но они выделяются в стеке.
Ответ 6
Хотя вы можете делать массивы переменной длины с C99, по-прежнему нет достойной замены более динамических структур данных. Классическим примером является связанный список. Чтобы получить произвольный размер, вы используете malloc
для выделения каждого node, чтобы вы могли вставлять и удалять без массивного копирования памяти, как это было бы с массивом переменной длины.
Например, стеки произвольного размера с использованием простого связанного списка:
#include <stdio.h>
#include <stdlib.h>
typedef struct sNode {
int payLoad;
struct sNode *next;
} tNode;
void stkPush (tNode **stk, int val) {
tNode *newNode = malloc (sizeof (tNode));
if (newNode == NULL) return;
newNode->payLoad = val;
newNode->next = *stk;
*stk = newNode;
}
int stkPop (tNode **stk) {
tNode *oldNode;
int val;
if (*stk == NULL) return 0;
oldNode = *stk;
*stk = oldNode->next;
val = oldNode->payLoad;
free (oldNode);
return val;
}
int main (void) {
tNode *top = NULL;
stkPush (&top, 42);
printf ("%d\n", stkPop (&top));
return 0;
}
Теперь можно сделать это с помощью массивов переменной длины, но, как и запись операционной системы в COBOL, есть лучшие способы сделать это.