Понимание назначения malloc и calloc

Я пытаюсь разобраться в C. Читая K&R, я щелкаю туда-сюда, пытаясь найти, где в нем указаны ситуации, в которых я должен динамически получать блоки памяти.

Например, я хочу иметь указатель int.

int *pointer;

Но затем K&R заявляет, что я могу захотеть сделать:

int *pointer;

pointer = (int*)malloc(sizeof(int));

По сути, что я сделал здесь по-другому? В первом случае я создал указатель, который еще ни на что не указывает, поэтому я думаю, что если у компьютера закончится память, и я попытаюсь указать на значение int, у меня возникнут проблемы. Второй случай резервирует место для моего указателя. Поэтому мне не нужно беспокоиться о том, что у моей программы столько проблем с памятью. Это верно? Если это правильно, не должен ли я использовать malloc (или calloc) для каждого создаваемого указателя? Просто чтобы убедиться, что у моей программы меньше проблем?


person Community    schedule 11.12.2011    source источник
comment
Второй случай резервирует место для int и позволяет вашему указателю указывать на него. Если у вас нет памяти в этот момент, у вас тоже будут проблемы.   -  person Gunther Piez    schedule 11.12.2011


Ответы (4)


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

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

int value = 0;
int* pointer;
pointer = &value;

Но вы не можете присвоить ему значение:

int value = 0;
int* pointer;
*pointer = value; // wrong because pointer is not allocated

Это то, для чего предназначен ваш второй случай.

calloc в основном malloc + инициализация.

Правка. Несмотря на это, это не очень хороший пример использования malloc. Лучшее использование, вероятно, когда вам нужно выделить массив переменного размера (неизвестный во время компиляции). Тогда вам нужно будет использовать:

int* array = (int*)malloc(N * sizeof(int));

Это полезно по двум причинам:

  1. Если N является переменной, вы не можете выполнять статическое распределение, например int array[N];
  2. Стек может быть ограничен тем, сколько места вы можете выделить.
person Tudor    schedule 11.12.2011
comment
Но во втором случае я мог бы сделать pointer = &value. Верный? По сути, это то же самое, и мой указатель получает адрес памяти, в котором хранится значение. - person ; 11.12.2011
comment
Спасибо, Тудор, но я все еще в замешательстве. Кажется, я могу делать все, для чего используется malloc, просто используя операторы * и & без динамического выделения памяти. - person ; 11.12.2011
comment
@JJG: я добавил более полезный пример о malloc. - person Tudor; 11.12.2011

В первом случае вы разместили в стеке указатель на целое число; и это все. Итак, у вас есть один указатель.

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

person Community    schedule 11.12.2011
comment
Я бы сказал, что первый случай — это определение, обычно локальной переменной, которая оказывается внутри кадра вызова, выделенного процессором в стеке вызовов. (компилятор не выделяет его). Если это определение является глобальным, переменная не находится в стеке. - person Basile Starynkevitch; 11.12.2011
comment
@JJG, ты можешь. Смотрите мой пример. - person Tudor; 11.12.2011
comment
вы можете сделать int myinteger=42; int *mypointer= &myinteger; *mypointer=3; и после этого myinteger будет содержать 3. - person Basile Starynkevitch; 11.12.2011

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

person Santosh    schedule 11.12.2011

Первый случай: вы объявляете только 1 указатель переменной. Но без присвоения ему чего-либо. Это просто декларация.

Но второй случай: вы выделяете 1 указатель памяти в куче (вы можете создать n-й указатель в куче), умножив количество элементов, которые вы хотите.

Разница между случаем 1 и случаем 2 заключается в том, что в случае 1 память останется в стеке до тех пор, пока программа не завершит работу. но в случае 2 .. вы можете освободить (восстановить) память в любое время, используя свободный (указатель).

person Vinh Pho    schedule 08.12.2014